MixedModelsSmallSample
The confidence intervals and hypothesis tests for the fixed effects in MixedModels.jl are based on large sample approximations. This package implements small sample corrections for these intervals and tests, as described in:
Kenward, Michael G., and James H. Roger. "Small sample inference for fixed effects from restricted maximum likelihood." Biometrics (1997): 983-997,
and in:
Hrong-Tai Fai, Alex, and Paul L. Cornelius. "Approximate F-tests of multiple degree of freedom hypotheses in generalized least squares analyses of unbalanced split-plot experiments." Journal of statistical computation and simulation 54.4 (1996): 363-378.
Getting Started
We will look at a split plot experiment, described in chapter 10 of:
Goos, Peter, and Bradley Jones. Optimal design of experiments: a case study approach. John Wiley & Sons, 2011.
Split-plot experiments have hard-to-change factors and easy-to-change factors. Hard-to-change factors are not properly randomized, they are kept at the same factor setting for multiple observations. The dataset can thus be split up into blocks, where the hard-to-change factors remain constant. These blocks are also called whole plots. The observations within such a block are more similar to one another than observations coming from a different block. A random intercept per block is introduced to deal with the correlation between observations. In the below dataset, FRH and RRH are hard-to-change, while YA and GC are easy-to-change. The WP column shows that there are 10 blocks in the dataset in which FRH and RRH remain constant. Efficiency is the output we want to model.
Click here to expand the details loading the data.
#! format: off
using DataFrames
df = DataFrame(
WP = [1,1,1,1,1,
2,2,2,2,2,
3,3,3,3,3,
4,4,4,4,4,
5,5,5,5,5,
6,6,6,6,6,
7,7,7,7,7,
8,8,8,8,8,
9,9,9,9,9,
10,10,10,10,10],
FRH = [-1,-1,-1,-1,-1,
0,0,0,0,0,
1,1,1,1,1,
-1,-1,-1,-1,-1,
0,0,0,0,0,
0,0,0,0,0,
1,1,1,1,1,
-1,-1,-1,-1,-1,
0,0,0,0,0,
1,1,1,1,1],
RRH = [-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
1,1,1,1,1,
1,1,1,1,1,
1,1,1,1,1],
YA = [-1,1,0,1,-1,
1,0,1,0,-1,
1,1,-1,-1,0,
-1,0,1,0,-1,
0,1,0,-1,0,
1,0,0,0,-1,
0,1,0,0,-1,
-1,1,0,1,-1,
-1,0,0,0,1,
-1,1,-1,1,0],
GC = [-1,1,0,-1,1,
1,0,-1,1,0,
-1,1,-1,1,0,
0,1,0,-1,1,
-1,0,0,1,0,
0,0,0,0,-1,
-1, 1,0,1,0,
-1,-1,0,1,1,
0,-1,0,1,1,
1,-1,-1,0,1],
EFFICIENCY = [
0.873,0.969,0.959,0.821,1.019,
0.921,0.923,0.821,0.958,0.914,
0.705,0.861,0.756,0.861,0.78,
0.999,1.06,0.91,0.854,1.082,
0.841,0.885,0.905,1.025,0.936,
0.844,0.891,0.902,0.871,0.833,
0.786,0.879,0.86,0.905,0.87,
0.98,0.907,1.045,1.094,1.159,
1.0,0.901,0.99,1.059,1.025,
0.991,0.828,0.853,0.923,0.997
]
)
Row | WP | FRH | RRH | YA | GC | EFFICIENCY |
---|---|---|---|---|---|---|
Int64 | Int64 | Int64 | Int64 | Int64 | Float64 | |
1 | 1 | -1 | -1 | -1 | -1 | 0.873 |
2 | 1 | -1 | -1 | 1 | 1 | 0.969 |
3 | 1 | -1 | -1 | 0 | 0 | 0.959 |
4 | 1 | -1 | -1 | 1 | -1 | 0.821 |
5 | 1 | -1 | -1 | -1 | 1 | 1.019 |
6 | 2 | 0 | -1 | 1 | 1 | 0.921 |
7 | 2 | 0 | -1 | 0 | 0 | 0.923 |
8 | 2 | 0 | -1 | 1 | -1 | 0.821 |
9 | 2 | 0 | -1 | 0 | 1 | 0.958 |
10 | 2 | 0 | -1 | -1 | 0 | 0.914 |
11 | 3 | 1 | -1 | 1 | -1 | 0.705 |
12 | 3 | 1 | -1 | 1 | 1 | 0.861 |
13 | 3 | 1 | -1 | -1 | -1 | 0.756 |
14 | 3 | 1 | -1 | -1 | 1 | 0.861 |
15 | 3 | 1 | -1 | 0 | 0 | 0.78 |
16 | 4 | -1 | 0 | -1 | 0 | 0.999 |
17 | 4 | -1 | 0 | 0 | 1 | 1.06 |
18 | 4 | -1 | 0 | 1 | 0 | 0.91 |
19 | 4 | -1 | 0 | 0 | -1 | 0.854 |
20 | 4 | -1 | 0 | -1 | 1 | 1.082 |
21 | 5 | 0 | 0 | 0 | -1 | 0.841 |
22 | 5 | 0 | 0 | 1 | 0 | 0.885 |
23 | 5 | 0 | 0 | 0 | 0 | 0.905 |
24 | 5 | 0 | 0 | -1 | 1 | 1.025 |
25 | 5 | 0 | 0 | 0 | 0 | 0.936 |
26 | 6 | 0 | 0 | 1 | 0 | 0.844 |
27 | 6 | 0 | 0 | 0 | 0 | 0.891 |
28 | 6 | 0 | 0 | 0 | 0 | 0.902 |
29 | 6 | 0 | 0 | 0 | 0 | 0.871 |
30 | 6 | 0 | 0 | -1 | -1 | 0.833 |
31 | 7 | 1 | 0 | 0 | -1 | 0.786 |
32 | 7 | 1 | 0 | 1 | 1 | 0.879 |
33 | 7 | 1 | 0 | 0 | 0 | 0.86 |
34 | 7 | 1 | 0 | 0 | 1 | 0.905 |
35 | 7 | 1 | 0 | -1 | 0 | 0.87 |
36 | 8 | -1 | 1 | -1 | -1 | 0.98 |
37 | 8 | -1 | 1 | 1 | -1 | 0.907 |
38 | 8 | -1 | 1 | 0 | 0 | 1.045 |
39 | 8 | -1 | 1 | 1 | 1 | 1.094 |
40 | 8 | -1 | 1 | -1 | 1 | 1.159 |
41 | 9 | 0 | 1 | -1 | 0 | 1.0 |
42 | 9 | 0 | 1 | 0 | -1 | 0.901 |
43 | 9 | 0 | 1 | 0 | 0 | 0.99 |
44 | 9 | 0 | 1 | 0 | 1 | 1.059 |
45 | 9 | 0 | 1 | 1 | 1 | 1.025 |
46 | 10 | 1 | 1 | -1 | 1 | 0.991 |
47 | 10 | 1 | 1 | 1 | -1 | 0.828 |
48 | 10 | 1 | 1 | -1 | -1 | 0.853 |
49 | 10 | 1 | 1 | 1 | 0 | 0.923 |
50 | 10 | 1 | 1 | 0 | 1 | 0.997 |
df[1:10, :]
Row | WP | FRH | RRH | YA | GC | EFFICIENCY |
---|---|---|---|---|---|---|
Int64 | Int64 | Int64 | Int64 | Int64 | Float64 | |
1 | 1 | -1 | -1 | -1 | -1 | 0.873 |
2 | 1 | -1 | -1 | 1 | 1 | 0.969 |
3 | 1 | -1 | -1 | 0 | 0 | 0.959 |
4 | 1 | -1 | -1 | 1 | -1 | 0.821 |
5 | 1 | -1 | -1 | -1 | 1 | 1.019 |
6 | 2 | 0 | -1 | 1 | 1 | 0.921 |
7 | 2 | 0 | -1 | 0 | 0 | 0.923 |
8 | 2 | 0 | -1 | 1 | -1 | 0.821 |
9 | 2 | 0 | -1 | 0 | 1 | 0.958 |
10 | 2 | 0 | -1 | -1 | 0 | 0.914 |
df[45:50, :]
Row | WP | FRH | RRH | YA | GC | EFFICIENCY |
---|---|---|---|---|---|---|
Int64 | Int64 | Int64 | Int64 | Int64 | Float64 | |
1 | 9 | 0 | 1 | 1 | 1 | 1.025 |
2 | 10 | 1 | 1 | -1 | 1 | 0.991 |
3 | 10 | 1 | 1 | 1 | -1 | 0.828 |
4 | 10 | 1 | 1 | -1 | -1 | 0.853 |
5 | 10 | 1 | 1 | 1 | 0 | 0.923 |
6 | 10 | 1 | 1 | 0 | 1 | 0.997 |
We work with a full quadratic model, where the intercept is allowed to vary between blocks. First, we get the output using only MixedModels
. Here, the p-values for the main effects (first-order terms) are all below 1e-10
.
using MixedModels
fm = @formula(
EFFICIENCY ~
1 +
(1 | WP) +
FRH +
RRH +
YA +
GC +
FRH & RRH +
FRH & YA +
FRH & GC +
RRH & YA +
RRH & GC +
YA & GC +
FRH & FRH +
RRH & RRH +
YA & YA +
GC & GC
)
m = fit(MixedModel, fm, df; REML=true)
Est. | SE | z | p | σ_WP | |
---|---|---|---|---|---|
(Intercept) | 0.9114 | 0.0117 | 77.67 | <1e-99 | 0.0182 |
FRH | -0.0609 | 0.0079 | -7.70 | <1e-13 | |
RRH | 0.0522 | 0.0079 | 6.60 | <1e-10 | |
YA | -0.0247 | 0.0027 | -9.04 | <1e-18 | |
GC | 0.0745 | 0.0027 | 27.54 | <1e-99 | |
FRH & RRH | 0.0042 | 0.0097 | 0.44 | 0.6605 | |
FRH & YA | 0.0106 | 0.0033 | 3.24 | 0.0012 | |
FRH & GC | -0.0111 | 0.0032 | -3.46 | 0.0005 | |
RRH & YA | -0.0015 | 0.0033 | -0.47 | 0.6384 | |
RRH & GC | 0.0078 | 0.0032 | 2.44 | 0.0147 | |
YA & GC | -0.0000 | 0.0033 | -0.01 | 0.9939 | |
FRH & FRH | -0.0075 | 0.0127 | -0.58 | 0.5587 | |
RRH & RRH | 0.0291 | 0.0127 | 2.28 | 0.0224 | |
YA & YA | -0.0075 | 0.0047 | -1.60 | 0.1105 | |
GC & GC | -0.0064 | 0.0048 | -1.34 | 0.1812 | |
Residual | 0.0148 |
Now we look at the adjustments made in the Kenward Roger approach. The p-values for the main effects of the hard-to-change factors are much larger. This is primarily because the degrees of freedom for these factors are very limited.
Similar results hold for the second-order terms. Terms involving only the hard-to-change factors have limited degrees of freedom. The interactions involving both a hard and an easy-to-change factor have similar degrees of freedom as terms only involving easy-to-change factors.
using MixedModelsSmallSample
kr = adjust_KR(m; FIM_σ²=:expected)
Coef. | Std. Error | DenDF | t | Pr(>|t|) | |
---|---|---|---|---|---|
(Intercept) | 0.91139 | 0.011734 | 4.2078 | 77.669 | 8.3743e-8 |
FRH | -0.060868 | 0.0079025 | 3.9751 | -7.7023 | 0.0015681 |
RRH | 0.052156 | 0.0079025 | 3.9751 | 6.5999 | 0.0027915 |
YA | -0.024719 | 0.0027352 | 31.03 | -9.0372 | 3.3648e-10 |
GC | 0.074543 | 0.002711 | 31.189 | 27.497 | 1.9694e-23 |
FRH & RRH | 0.0042487 | 0.0096728 | 3.9657 | 0.43925 | 0.68336 |
FRH & YA | 0.010584 | 0.0032635 | 31.025 | 3.2431 | 0.0028267 |
FRH & GC | -0.011065 | 0.0032021 | 31.073 | -3.4556 | 0.0016105 |
RRH & YA | -0.0015368 | 0.003271 | 31.032 | -0.46982 | 0.64177 |
RRH & GC | 0.0078247 | 0.0032118 | 31.114 | 2.4362 | 0.020759 |
YA & GC | -2.5084e-5 | 0.0032853 | 31.383 | -0.0076352 | 0.99396 |
FRH & FRH | -0.0074549 | 0.012749 | 4.0712 | -0.58477 | 0.58958 |
RRH & RRH | 0.029096 | 0.012743 | 4.0641 | 2.2834 | 0.083427 |
YA & YA | -0.0074878 | 0.0047005 | 31.21 | -1.593 | 0.12124 |
GC & GC | -0.0064216 | 0.0048079 | 31.11 | -1.3356 | 0.19136 |
The standard errors on the estimates are also slightly different. However, for this specific experiment, the adjustment does not have a large effect. An example where there is a large difference in standard error will be added later.
Multiple random effects
using CSV
using DataFrames
using MixedModels
using MixedModelsSmallSample
df = DataFrame(MixedModels.dataset(:sleepstudy))
fm = @formula(reaction ~ 1 + days + zerocorr(1 + days | subj)) # zerocorr is necessary
m = fit(MixedModel, fm, df; REML=true)
Est. | SE | z | p | σ_subj | |
---|---|---|---|---|---|
(Intercept) | 251.4051 | 6.8854 | 36.51 | <1e-99 | 25.0513 |
days | 10.4673 | 1.5596 | 6.71 | <1e-10 | 5.9882 |
Residual | 25.5653 |
kr = adjust_KR(m; FIM_σ²=:expected) # :expected or :observed
Coef. | Std. Error | DenDF | t | Pr(>|t|) | |
---|---|---|---|---|---|
(Intercept) | 251.41 | 6.8854 | 18.187 | 36.513 | 1.796e-18 |
days | 10.467 | 1.5596 | 18.187 | 6.7117 | 2.5709e-6 |
Mathematical details
To quantify the uncertainty on the estimates of the variance components, either the observed or the expected Fisher information matrix can be used, by passing :expected
or :observed
to the keyword argument FIM_σ²
. Observed is the default option.
Limitations
Currently, correlated random effects are not supported. In the above example the zerocorr
is necessary.