This repository has been archived by the owner on Sep 20, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
/
sleepstudy_shrinkage.qmd
112 lines (83 loc) · 2.47 KB
/
sleepstudy_shrinkage.qmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
---
title: "The sleepstudy: Shrinkage"
jupyter: julia-1.9
---
```{julia}
using CairoMakie
using Chain # like pipes but cleaner
using CSV
using DataFrameMacros
using DataFrames
using MixedModels
using MixedModelsExtras
using MixedModelsMakie
using Random # we don't depend on exact PRNG vals, so no need for StableRNGs
using Statistics
using Test
using MixedModelsMakie: confint_table
const progress = false
```
# Preprocessing
The `sleepstudy` data are one of the datasets available with recent versions of the `MixedModels` package. We carry out some preprocessing to have the dataframe in the desired shape:
- Capitalize random factor `Subj`
- Compute `speed` as an alternative dependent variable from `reaction`, warranted by a 'boxcox' check of residuals.
- Create a `GroupedDataFrame` by levels of `Subj` (the original dataframe is available as `gdf.parent`, which we name `df`)
```{julia}
gdf = @chain MixedModels.dataset(:sleepstudy) begin
DataFrame
rename!(:subj => :Subj, :days => :day)
@transform!(:speed = 1000 / :reaction)
groupby(:Subj)
end
```
```{julia}
df = gdf.parent
describe(df)
```
## Estimates for pooled data
In the first analysis we ignore the dependency of observations due to repeated measures from the same subjects. We pool all the data and estimate the regression of 180 speed scores on the nine days of the experiment.
```{julia}
pooledcoef = simplelinreg(df.day, df.speed) # produces a Tuple
```
# LM
```{julia}
within = combine(gdf, [:day, :speed] => simplelinreg => :coef)
```
# LMM
```{julia}
m1 = fit(MixedModel,
@formula(speed ~ 1 + day + (1 + day | Subj)), df; progress)
m1_fe = coeftable(m1)
```
# Figure of conditional means of random effects given the data
```{julia}
fig1 = caterpillar(m1)
```
```{julia}
fig2 = qqcaterpillar(m1)
```
```{julia}
fig3 = shrinkageplot(m1)
```
```{julia}
save( "figures/slp_ctrpllr1.png", fig1)
save( "figures/slp_qqctrpllr1.png", fig2)
save( "figures/slp_shrkng1.png", fig3)
```
# Under the hood ...
Let's take a look at the data used to generate the figures.
```{julia}
m1_slp_shrnkg = DataFrame(shrinkagetables(m1)[:Subj])
```
```{julia}
m1_slp_shrnkgnrm = DataFrame(shrinkagenorm(m1)[:Subj])
```
```{julia}
m1_slp_csd = DataFrame(ranefinfotable(ranefinfo(m1)[:Subj]))
```
Write them out for post-processing somewhere else.
```{julia}
CSV.write("./data/m1_shrnkg.csv", m1_slp_shrnkg);
CSV.write("./data/m1_shrnkgnrm.csv", m1_slp_shrnkgnrm);
CSV.write("./data/m1_slp_csd.csv", m1_slp_csd);
```