Power
Power is the probability of detecting an effect when it is present. Knowing the power of a study is important: Weak studies spew out 5% false positives (i.e., at the rate alpha), but without power, they fail to detect true results at rate beta. Power is 1-beta.
This post covers:
- Computing power to detect a difference between 2 models.
- Computing power given a certain
n
.
umx
supports power calculations for the umxACE
model (via power.ACE.test
) and a generic umxPower
function, which can handle a range of power-related questions given a trueModel, and a parameter which you wish to drop.
Comparing two models with umxPower
R
has great support for power. For instance, testing power to detect a correlation of .3 in a sample of 36 subjects, R quickly tells us we’re going to need some more subjects…
pwr::pwr.r.test(n = 36, r = .3)
n = 36
r = 0.3
sig.level = 0.05
power = 0.4361314
alternative = two.sided
Computing power for SEM is rather more complex, as the models are arbitrary. Many more questions can also be asked than, say, pwr.t.test
could answer.
umxPower
tackles this by using an interface very similar to umxModify
. You offer up a true model, and paths that you want test.
umxPower(trueModel = , update = "path_to_test", n= , power = , sig.level = .05, method = c("ncp", "empirical"))
To emulate the pwr.r.test
example, you would build a trueModel
of two manifests (“X”, and “Y”), with a covariance between them equal to r= .3.
You can then input this to umxPower
test, setting update to “X_with_Y” (value= 0 is the default for updated parameters).
Demonstration: Power to detect a correlation of .3 between two variables: X and Y
First: Make and run a model of the true correlation (.3)
Make data for the model (this can be tricky for more complex models. the easiest solution is often to use the model with mxGenerateData to generate data corresponding to the model).
tmp = umx_make_raw_from_cov(qm(1, .3| .3, 1), n=200, varNames= c("X", "Y"), empirical= TRUE)
Build the model: in this case a correlation
m1 = umxRAM("corXY", data = tmp,
umxPath("X", with = "Y"),
umxPath(var = c("X", "Y"))
)
Next: Using umxPower
, test the path you want to drop,
umxPower(m1, "X_with_Y", n= 50, method="empirical")
After a few moments, this yields:
method = empirical
n = 50 sig.level = 0.05
power = 0.6266667
probes = 300 statistic = LRT
We can also take advantage of the noncentrality parameter, to run power. This is near-instant and accurate if the model is valid.
umxPower(m1, "X_with_Y", n= 50, method="ncp")
method = ncp
n = 50
sig.level = 0.05
power = 0.5837944
statistic = LRT
Now, let’s compare the results using a cor.test
doing the same thing?
pwr::pwr.r.test(n = 50, r = .3)
n = 50
r = 0.3
sig.level = 0.05
power = 0.5715558
alternative = two.sided
Another example
If someone publishes this simple model claiming that larger engines lower miles/gallon in vehicles, what power do we have to detect engine_litres_to_mpg
is > 0 if we replicate with the same n
, and assume that the obtained effect is the true one?
First we build the claimed model:
df = mtcars
df$engine_litres = .016 * df$disp
m1 = umxRAM(data = df, "#mpg_model
mpg ~ engine_litres + wt
wt ~~ engine_litres"
)
And test power:
umxPower(m1, "engine_litres_to_mpg", n= 30, method = "empirical")
method = empirical
n = 30
power = 0.46
probes = 300
sig.level = 0.05
statistic = LRT
Now let’s solve for N to give us 80% power.
# solve for N
umxPower(m1, update = "engine_litres_to_mpg", power = .8, method = "ncp")
####################
# Estimating n #
####################
method = ncp
n = 68
power = 0.8
sig.level = 0.05
statistic = LRT
Finally, we can make a table showing how power changes across n:
tmp = umx_make_raw_from_cov(qm(1, .3| .3, 1), n= 200, varNames= c("X", "Y"), empirical= TRUE)
m1 = umxRAM("corXY", data = tmp,
umxPath("X", with = "Y"),
umxPath(var = c("X", "Y"))
)
umxPower(m1, update = "X_with_Y", explore = TRUE)
N power
1 17.68 0.25
2 25.36 0.34
3 33.03 0.42
4 40.70 0.50
5 48.38 0.57
6 56.05 0.63
7 63.72 0.69
8 71.40 0.74
9 79.07 0.78
10 86.74 0.82
11 94.42 0.85
12 102.09 0.87
13 109.76 0.90
14 117.44 0.91
15 125.11 0.93
16 132.78 0.94
17 140.46 0.95
18 148.13 0.96
19 155.80 0.97
20 163.48 0.98