This post is adapted from my Observable notebook. The package results discussed below are those recorded in that notebook.
Dablander, van den Bergh, Wagenmakers, and Ly (2024) outline a method for computing Bayes factors for variance comparisons. Section 5.2 gives an example of comparing a single sample variance with a reference variance, using both an undirected and a directed hypothesis.
The example is as follows:
The EPA is testing a new device for measuring PCB concentrations in fish. The measurements of the device are required to have a variance of less than 0.1 (
). Therefore, . Seven readings are taken from a sample of fish, and the sample standard is . This gives a sample effect size
Dablander et al compare two hypotheses:
The Bayes factor calculated with the accompanying R package as follows:
> bfvartest::onesd_test(n=7, s=.22, popsd=sqrt(0.1), u = 0.5, logarithm=FALSE, alternative_interval=c(1,Inf))
[1] 0.509796
This matches the value reported in the paper.
Dablander et al also reported the undirected Bayes factor. That is, the Bayes factor from comparing the following hypotheses:
This can be calculated with the accompanying R package as follows:
> bfvartest::onesd_test(n=7, s=.22, popsd=sqrt(0.1), u = 0.5, logarithm=FALSE)
[1] 0.4104968
Again, this matches the value reported in the paper.
Bayesplay for variance Bayes factors
The Bayesplay package also has the functionality to compute Bayes factors for
differences between variances. These are parametrised slightly differently in
Bayesplay compared with bfvartest, but they work essentially the same. In
Bayesplay, the likelihood is parametrised in terms of u, which is the
variance ratio of the sample variance against the reference variance
(df of n-1.
Inputting the values from Example 5.2, we get the following:
Because the likelihood is in terms of variance, and not precision, the bounds of the truncated prior are also specified in the opposite direction.
With these differences in mind, we can specify the models in the Bayesplay
modelling language as follows (both directed hypotheses are included, because
the results will become useful below):
model = `
analysis R {
likelihood variance_ratio(u = 0.484, df = 6)
hypotheses {
0: point(1)
1: beta_prime(0.5)
-: beta_prime(0.5) | R < 1
+: beta_prime(0.5) | R > 1
}
}
`
Again, note that because the likelihood is in terms of variance rather than
precision,
If we look at the results produced by Bayesplay, we can see that the
undirected Bayes factor is the sample as that produced by bfvartest and the
value reported in the paper:
However, if we look at the directed Bayes factor, the result produced by
Bayesplay is different. For the directed Bayes factor, Bayesplay gives the
result:
Which result is correct?
First, we can look at the two directed hypotheses and whether they’re consistent with the undirected hypothesis.
We should expect that
Checking the numbers produced by bfvartest we get:
We can also check the numbers produced by Bayesplay:
We can get a clue as to what is going wrong with bfvartest if we change the
model we use with Bayesplay slightly. Instead of defining bfvartest
we get the following model.
model2 = `
analysis R {
likelihood variance_ratio(u = 0.484, df = 6)
hypotheses {
0: point(1)
1: beta_prime(0.5)
-: beta_prime(0.5) | R < 10
}
}
`
With this new model definition, we obtain a
We can also update the prior, to use the informed prior reported in the paper.
In the Bayesplay modelling language, this gives the following model:
model3 = `
analysis R {
likelihood variance_ratio(u = 0.484, df = 6)
hypotheses {
0: point(1)
1: beta_prime(2.16)
-: beta_prime(2.16) | R < 10
}
}
`
With this model definition, we get the a result for
These findings taken together suggests that there is an error with bfvartest
where the directed priors are truncated relative to
To confirm this, we can modify the model again. We can change our data slightly
so that we’re measuring our data on a slightly different scale, for example,
parts per 100,000 rather than parts per million. For Bayesplay the model is
unchanged, so the result are unchanged.
For bfvartest we’d update the function call as follows:
> bfvartest::onesd_test(n=7, s=2.2, popsd=3.2, u = 0.5, logarithm=FALSE, alternative_interval=c(1,Inf))
[1] 7.897717e-05
We should not expect our Bayes factor to change just because we change our units
of measurement. Again, pointing to an error with bfvartest
We can attempt to replicate this result with Bayesplay by truncating the prior
at bfvartest.
The issue with bfvartest
If we have a look at the code for bfvartest, specifically the function
.compute_logml_restr_k1 in helpers.R we can see where the error is. If we
correct this function, then bfvartest produces the correct results.
Try Bayesplay yourself
Below you can try specifying a model using a web interface to Bayesplay.
The default values are the same values as the example in Section 5.2 of Dablander, van den Bergh, Wagenmakers, and Ly (2024). You can change the sample standard deviation, the reference standard deviation, the sample size, and the prior alpha. You cal also set where to truncate the prior for each of the two directional hypothesis.
The Bayes factor is shown for the two side comparison and each of the two directional hypotheses.
Loading calculator…
- BF10
- BF−0
- BF+0
Values below 1 favor H₀. Values above 1 favor the alternative shown in the subscript.
Generated model
References
Dablander, F., van den Bergh, D., Wagenmakers, E.-J., and Ly, A. (2024). Default Bayes Factors for Testing the Inequality of Several Population Variances. Bayesian Analysis, 19(3). doi:10.1214/23-BA1369.
Original Observable
notebook,
first published on 23 August 2026. Calculations use Bayesplay JS at revision
0ffabea3.