Skip to content

Commit 048718d

Browse files
dmbatespalday
andauthored
Clean up show methods and documentation (#412)
* Extend model-fit criteria section in show. Closes #411 (not entirely but the other change can wait) * Clean up docs Co-authored-by: Phillip Alday <[email protected]>
1 parent 26dce86 commit 048718d

6 files changed

+37
-38
lines changed

docs/src/GaussHermite.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Normalized Gauss-Hermite Quadrature
22

3-
[*Gaussian Quadrature rules*](https://en.wikipedia.org/wiki/Gaussian_quadrature) provide sets of `x` values, called *abscissae*, and weights, `w`, to approximate an integral with respect to a *weight function*, $g(x)$.
3+
[*Gaussian Quadrature rules*](https://en.wikipedia.org/wiki/Gaussian_quadrature) provide sets of `x` values, called *abscissae*, and corresponding weights, `w`, to approximate an integral with respect to a *weight function*, $g(x)$.
44
For a `k`th order rule the approximation is
55
```math
66
\int f(x)g(x)\,dx \approx \sum_{i=1}^k w_i f(x_i)
@@ -93,7 +93,7 @@ A *binary response* is a "Yes"/"No" type of answer.
9393
For example, in a 1989 fertility survey of women in Bangladesh (reported in [Huq, N. M. and Cleland, J., 1990](https://www.popline.org/node/371841)) one response of interest was whether the woman used artificial contraception.
9494
Several covariates were recorded including the woman's age (centered at the mean), the number of live children the woman has had (in 4 categories: 0, 1, 2, and 3 or more), whether she lived in an urban setting, and the district in which she lived.
9595
The version of the data used here is that used in review of multilevel modeling software conducted by the Center for Multilevel Modelling, currently at University of Bristol (http://www.bristol.ac.uk/cmm/learning/mmsoftware/data-rev.html).
96-
These data are available as the `Contraception` data frame in the test data for the `MixedModels` package.
96+
These data are available as the `:contra` dataset.
9797
```@example Main
9898
contra = DataFrame(MixedModels.dataset(:contra))
9999
describe(contra)
@@ -109,8 +109,7 @@ shows that the proportion of women using artificial contraception is approximate
109109
A model with fixed-effects for age, age squared, number of live children and urban location and with random effects for district, is fit as
110110
```@example Main
111111
const form1 = @formula use ~ 1 + age + abs2(age) + livch + urban + (1|dist);
112-
m1 = fit!(GeneralizedLinearMixedModel(form1, contra,
113-
Bernoulli()), fast=true)
112+
m1 = fit(MixedModel, form1, contra, Bernoulli(), fast=true)
114113
```
115114

116115
For a model such as `m1`, which has a single, scalar random-effects term, the unscaled conditional density of the spherical random effects variable, $\mathcal{U}$,
@@ -125,7 +124,7 @@ To use Gauss-Hermite quadrature the contributions of each of the $u_i,\;i=1,\dot
125124
```@example Main
126125
const devc0 = map!(abs2, m1.devc0, m1.u[1]); # start with uᵢ²
127126
const devresid = m1.resp.devresid; # n-dimensional vector of deviance residuals
128-
const refs = first(m1.LMM.reterms).refs; # n-dimensional vector of indices in 1:q
127+
const refs = only(m1.LMM.reterms).refs; # n-dimensional vector of indices in 1:q
129128
for (dr, i) in zip(devresid, refs)
130129
devc0[i] += dr
131130
end
@@ -141,7 +140,7 @@ freqtable(contra, :dist)'
141140

142141
Because the first district has one of the largest sample sizes and the third district has the smallest sample size, these two will be used for illustration.
143142
For a range of $u$ values, evaluate the individual components of the deviance and store them in a matrix.
144-
```@setup Main
143+
```@example Main
145144
const devc = m1.devc;
146145
const xvals = -5.0:2.0^(-4):5.0;
147146
const uv = vec(m1.u[1]);

docs/src/constructors.md

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ describe(pastes)
136136
fm4 = fit(MixedModel, @formula(strength ~ 1 + (1|sample) + (1|batch)), pastes)
137137
```
138138

139-
An alternative syntax with a solidus (the "`/`" character) separating grouping factors, read "`cask` nested within `batch`", fits the same model.
139+
An alternative syntax with a solidus (the "`/`" character) separating grouping factors, read "`cask` nested within `batch`", fits the same model. (`sample` is just an explicitly stored version of `batch & cask`.)
140140
```@example Main
141141
fit(MixedModel, @formula(strength ~ 1 + (1|batch/cask)), pastes)
142142
```
@@ -160,17 +160,14 @@ end
160160
### Simplifying the random effect correlation structure
161161

162162
MixedEffects.jl estimates not only the *variance* of the effects for each random effect level, but also the *correlation* between the random effects for different predictors.
163-
So, for the model of the *sleepstudy* data above, one of the parameters that is estimated is the correlation between each subject's random intercept (i.e., their baseline reaction time) and slope (i.e., their particular change in reaction time over days of sleep deprivation).
163+
So, for the model of the *sleepstudy* data above, one of the parameters that is estimated is the correlation between each subject's random intercept (i.e., their baseline reaction time) and slope (i.e., their particular change in reaction time per day of sleep deprivation).
164164
In some cases, you may wish to simplify the random effects structure by removing these correlation parameters.
165165
This often arises when there are many random effects you want to estimate (as is common in psychological experiments with many conditions and covariates), since the number of random effects parameters increases as the square of the number of predictors, making these models difficult to estimate from limited data.
166166

167167
The special syntax `zerocorr` can be applied to individual random effects terms inside the `@formula`:
168168
```@example Main
169169
fm2zerocorr_fm = fit(MixedModel, @formula(reaction ~ 1 + days + zerocorr(1 + days|subj)), sleepstudy)
170170
```
171-
```@setup Main
172-
all(fm2zerocorr == fm2zerocorr_fm)
173-
```
174171

175172
Alternatively, correlations between parameters can be removed by including them as separate random effects terms:
176173
```@example Main
@@ -189,6 +186,7 @@ Separating the `1` and `days` random effects into separate terms removes the cor
189186
fit(MixedModel, @formula(reaction ~ 1 + days + (1|subj) + (days|subj)), sleepstudy,
190187
contrasts = Dict(:days => DummyCoding()))
191188
```
189+
(Notice that the variance component for `days: 1` is estimated as zero, so the correlations for this component are undefined and expressed as `NaN`, not a number.)
192190

193191
An alternative is to force all the levels of `days` as indicators using `fulldummy` encoding.
194192
```@docs
@@ -234,10 +232,10 @@ The canonical link, which is `LogitLink` for the `Bernoulli` distribution, is us
234232
Note that, in keeping with convention in the [`GLM` package](https://github.com/JuliaStats/GLM.jl), the distribution family for a binary (i.e. 0/1) response is the `Bernoulli` distribution.
235233
The `Binomial` distribution is only used when the response is the fraction of trials returning a positive, in which case the number of trials must be specified as the case weights.
236234

237-
### Optional arguments to fit!
235+
### Optional arguments to fit
238236

239237
An alternative approach is to create the `GeneralizedLinearMixedModel` object then call `fit!` on it.
240-
In this form optional arguments `fast` and/or `nAGQ` can be passed to the optimization process.
238+
The optional arguments `fast` and/or `nAGQ` can be passed to the optimization process via both `fit` and `fit!` (i.e these optimization settings are not used nor recognized when constructing the model).
241239

242240
As the name implies, `fast=true`, provides a faster but somewhat less accurate fit.
243241
These fits may suffice for model comparisons.
@@ -344,7 +342,7 @@ coefnames(fm1)
344342
```
345343
```@example Main
346344
fixef(fm1)
347-
fixefnames
345+
fixefnames(fm1)
348346
```
349347

350348
An alternative extractor for the fixed-effects coefficient is the `β` property.
@@ -445,6 +443,15 @@ These are sometimes called the *best linear unbiased predictors* or [`BLUPs`](ht
445443

446444
At a superficial level these can be considered as the "estimates" of the random effects, with a bit of hand waving, but pursuing this analogy too far usually results in confusion.
447445

446+
To obtain tables associating the values of the conditional modes with the levels of the grouping factor, use
447+
```@docs
448+
raneftables
449+
```
450+
as in
451+
```@example Main
452+
DataFrame(only(raneftables(fm1)))
453+
```
454+
448455
The corresponding conditional variances are returned by
449456
```@docs
450457
condVar
@@ -521,4 +528,3 @@ fm4r = fit(MixedModel, @formula(diameter ~ 1+(1|plate)+(1|sample)),
521528
sum(leverage(fm4r))
522529
```
523530

524-

docs/src/optimization.md

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ In the types of `LinearMixedModel` available through the `MixedModels` package,
9898

9999
For the simple example
100100
```@example Main
101-
using DataFrames, MixedModels
101+
using BenchmarkTools, DataFrames, MixedModels
102102
```
103103
```@example Main
104104
dyestuff = MixedModels.dataset(:dyestuff)
@@ -145,8 +145,7 @@ MixedModels.getθ(t21)
145145

146146
Random-effects terms in the model formula that have the same grouping factor are amalgamated into a single `ReMat` object.
147147
```@example Main
148-
fm3 = fit!(LinearMixedModel(@formula(reaction ~ 1+days+(1|subj) + (0+days|subj)),
149-
sleepstudy))
148+
fm3 = fit(MixedModel, @formula(reaction ~ 1+days+(1|subj) + (0+days|subj)), sleepstudy)
150149
t31 = first(fm3.reterms);
151150
Int.(t31)
152151
```
@@ -170,17 +169,7 @@ Note that the first `ReMat` in `fm4.terms` corresponds to grouping factor `G` ev
170169

171170
### Progress of the optimization
172171

173-
An optional named argument, `verbose=true`, in the call to `fit` for a `LinearMixedModel` causes printing of the objective and the $\theta$ parameter at each evaluation during the optimization.
174-
```@example Main
175-
fit(MixedModel,
176-
@formula(yield ~ 1 + (1|batch)),
177-
dyestuff,
178-
verbose=true);
179-
fit(MixedModel,
180-
@formula(reaction ~ 1 + days + (1+days|subj)),
181-
sleepstudy,
182-
verbose=true);
183-
```
172+
An optional named argument, `verbose=true`, in the call to `fit` for a `LinearMixedModel` causes printing of the objective and the $\theta$ parameter at each evaluation during the optimization. (Not illustrated here.)
184173

185174
A shorter summary of the optimization process is always available as an
186175
```@docs
@@ -333,7 +322,7 @@ mdl.b # conditional modes of b
333322
```
334323

335324
```@example Main
336-
fit!(mdl, fast=true, verbose=true);
325+
fit!(mdl, fast=true);
337326
```
338327

339328
The optimization process is summarized by
@@ -344,15 +333,13 @@ mdl.LMM.optsum
344333

345334
As one would hope, given the name of the option, this fit is comparatively fast.
346335
```@example Main
347-
@time(fit!(GeneralizedLinearMixedModel(vaform,
348-
verbagg, Bernoulli()), fast=true))
336+
@btime fit(MixedModel, vaform, verbagg, Bernoulli(), fast=true)
349337
```
350338

351339
The alternative algorithm is to use PIRLS to find the conditional mode of the random effects, given $\beta$ and $\theta$ and then use the general nonlinear optimizer to fit with respect to both $\beta$ and $\theta$.
352-
Because it is slower to incorporate the $\beta$ parameters in the general nonlinear optimization, the fast fit is performed first and used to determine starting estimates for the more general optimization.
353340

354341
```@example Main
355-
@time mdl1 = fit(MixedModel, vaform, verbagg, Bernoulli())
342+
mdl1 = @btime fit(MixedModel, vaform, verbagg, Bernoulli())
356343
```
357344

358345
This fit provided slightly better results (Laplace approximation to the deviance of 8151.400 versus 8151.583) but took 6 times as long.

docs/src/rankdeficiency.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ The same holds for the associated [`fixefnames`](@ref) and [`coefnames`](@ref).
4242
In MixedModels.jl, we use standard numerical techniques to detect rank deficiency.
4343
We currently offer no guarantees as to which exactly of the standard techniques (pivoted QR decomposition, pivoted Cholesky decomposition, etc.) will be used.
4444
This choice should be viewed as an implementation detail.
45-
Similarly, we offer no guarentees as to which of columns will be treated as redundant.
45+
Similarly, we offer no guarantees as to which of columns will be treated as redundant.
4646
This choice may vary between releases and even between platforms (both in broad strokes of "Linux" vs. "Windows" and at the level of which BLAS options are loaded on a given processor architecture) for the same release.
4747
In other words, *you should not rely on the order of the pivoted columns being consistent!* when you switch to a different computer or a different operating system.
4848
If consistency in the pivoted columns is important to you, then you should instead determine your rank ahead of time and remove extraneous columns / predictors from your model specification.

src/generalizedlinearmixedmodel.jl

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,14 @@ function Base.show(io::IO, m::GeneralizedLinearMixedModel)
624624
println(io, " ", m.LMM.formula)
625625
println(io, " Distribution: ", Distribution(m.resp))
626626
println(io, " Link: ", GLM.Link(m.resp), "\n")
627-
println(io, " Deviance: ", Ryu.writefixed(deviance(m, nAGQ), 4))
627+
println(io)
628+
nums = Ryu.writefixed.([loglikelihood(m), deviance(m), aic(m), aicc(m), bic(m)], 4)
629+
fieldwd = max(maximum(textwidth.(nums)) + 1, 11)
630+
for label in [" logLik", " deviance", "AIC", "AICc", "BIC"]
631+
print(io, rpad(lpad(label, (fieldwd + textwidth(label)) >> 1), fieldwd))
632+
end
633+
println(io)
634+
print.(Ref(io), lpad.(nums, fieldwd))
628635
println(io)
629636

630637
show(io, VarCorr(m))

src/linearmixedmodel.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -787,9 +787,9 @@ function Base.show(io::IO, m::LinearMixedModel)
787787
if REML
788788
println(io, " REML criterion at convergence: ", oo)
789789
else
790-
nums = Ryu.writefixed.([-oo / 2, oo, aic(m), bic(m)], 4)
790+
nums = Ryu.writefixed.([-oo / 2, oo, aic(m), aicc(m), bic(m)], 4)
791791
fieldwd = max(maximum(textwidth.(nums)) + 1, 11)
792-
for label in [" logLik", "-2 logLik", "AIC", "BIC"]
792+
for label in [" logLik", "-2 logLik", "AIC", "AICc", "BIC"]
793793
print(io, rpad(lpad(label, (fieldwd + textwidth(label)) >> 1), fieldwd))
794794
end
795795
println(io)

0 commit comments

Comments
 (0)