Mixed effects models in the morning, model selection in the afternoon
From streams to fish in lakes, we build up random intercepts, random slopes, REML vs ML, and variance components. Then we turn around and ask the harder question: which model do we trust, and what does "trust" even mean?
What's in this lab and what to hand in
This page is your in-class practice problem set, worked examples with visible answers. Your graded work is a separate problem set. The morning session's Hierarchical modeling problem set is worth 20 points and the afternoon session's Model selection problem set is worth 20 points, for 40 points across Day 3. Both live on the same page (the graded problem set); write up your answers in the R Markdown template for each session and submit them as two Canvas assignments.
Need help with R Markdown? See the R Markdown tutorial. Other docs for this day: plain-language summary.
Data files & R scripts
Everything referenced in this lab's exercises lives in this folder. Click any link below to download.
Datasets
stream_density.csvFish density in 100 streams, three observations per stream (random-intercept intro).length_weight.csvLength-weight measurements per individual (random-intercept regression).fish_growth.csvAge and length measurements per individual fish (nonlinear mixed-effects, von Bertalanffy).qcbs_w6_data.csvQCBS fish trophic position dataset: three species nested across six lakes.Where we are in the week
Day 1 you wrote down probability stories and named the distribution that matched. Day 2 you bolted a linear predictor and a link function onto those distributions to get GLMs. Today we attack the assumption that has been quietly buried in every model so far: independence. Almost no ecological data are independent. Fish are nested in lakes, plots in sites, repeated measurements in subjects. Mixed models are how we model that nesting without burning a separate parameter per group. Model selection is then how we decide, given several plausible nested structures, which one to use.
Three habits to start today:
- Draw the nesting before fitting anything. A diagram of "observations within groups within bigger groups" determines every random-effect term.
- State whether each effect is fixed or random, and have a defensible reason. The right answer is usually about what you want to generalize to, not what's in your data frame.
- Estimate uncertainty, not just point values. A confidence interval on a variance component or an effect size is far more useful than "p < 0.05" or "$\Delta\text{AIC} = 1.3$."
Plain-language overview
Today's running example (and yes, "badjuice" is made up). A new graduate student joins your lab to study razor clam abundance along 10 beaches on the Oregon coast. At each beach they record clam abundance and the local concentration of badjuice, a fictitious environmental toxin invented for this course (it is not a real chemical), and they repeat the survey for four years. The student wants to know: does badjuice affect clam abundance? Hold on to that scenario. It is the example we return to all day, and it already contains the whole fixed-vs-random distinction.
A fixed effect is an effect you care about by name, such as badjuice concentration, body length, treatment. A random effect is a grouping variable whose individual levels you don't particularly care about, but which violates independence if you ignore it, such as which stream, which lake, or which subject. We don't estimate a separate intercept for each stream as a "thing we want to know"; we estimate how much streams vary and let each stream's estimate be pulled toward the overall mean. That pulling is called shrinkage and it's the magic of mixed models. Streams with little data borrow strength from the rest.
This afternoon we ask the next obvious question. With several candidate models on the table, how do we pick? We meet LRT for nested models, AIC / AICc / BIC for ranking on a common scale, and cross-validation when the goal is honest prediction error. We also take the lab time to make a hard but important argument, that picking "the best model" from a long candidate list and then reporting its p-values is one of the most common ways scientists fool themselves.
Read the full plain-language summary for Day 3 →. The same ideas are worked through slowly, with examples and no math.
Core concepts: linear mixed effects models
Scope. Everything in this section is about linear mixed models: lmer() and lme(), a Normal response with a separate residual variance $\sigma^2$. Most of it carries over to generalized mixed models (glmer()) unchanged, but two items below do not, and both are flagged where they appear, the REML rule in item 4 and the one-observation-per-level guidance in item 6.
1. Complete pooling, no pooling, partial pooling
Three ways to handle a grouping variable like "stream":
| Approach | Model | What it assumes |
|---|---|---|
| Complete pooling | lm(y ~ 1) | Streams are identical; one grand mean fits all. |
| No pooling | lm(y ~ factor(stream) - 1) | Streams are unrelated; each has its own freely-floating mean. |
| Partial pooling | lmer(y ~ 1 + (1|stream)) | Streams are drawn from a population of streams. Each stream's mean is pulled toward the grand mean by an amount proportional to how little data we have on it. |
2. The random-intercept model in equations
Read it as follows. The $i$-th observation in group $j$ has the grand mean $\beta_0$, plus a group-specific bump $b_{0,j}$ shared by every member of group $j$, plus its own residual noise. The bumps are drawn from a Normal centered at 0 with variance $\sigma_\text{group}^2$. Two variance components ($\sigma_\text{group}^2$ and $\sigma^2$) replace the long list of "one parameter per group" you would have in the fixed-effects version.
3. Random intercepts vs random slopes
A random slope says "the effect of $x$ varies across groups." For length–weight, that would mean different groups have different length–weight allometric slopes. The pair $(b_{0,j}, b_{1,j})$ is drawn from a bivariate Normal with a $2\times 2$ covariance matrix, usually estimated, sometimes constrained to be diagonal with (1|g) + (0+x|g).
4. REML vs ML: the one rule to memorize
The rule:
- Compare models that differ in random effects (e.g., adding/removing a random slope) using REML.
- Compare models that differ in fixed effects (e.g., adding/removing a covariate) using ML.
- Report the final model fit with REML.
In lme4::lmer() the default is REML; pass REML = FALSE to switch to ML. In nlme::lme(), set method = "ML" or "REML". This rule is for linear mixed models only. glmer() has no REML argument at all, because generalized mixed models are fit by maximum likelihood (Laplace approximation or adaptive Gauss-Hermite quadrature), so the REML-versus-ML choice does not arise there.
Why? Maximum likelihood underestimates variance components (it ignores the degrees of freedom used by the fixed effects). REML "restricts" the likelihood to contrasts that don't depend on the fixed effects, giving unbiased variance estimates. But REML likelihoods from models with different fixed effects aren't directly comparable, because they are computed on different reduced data.
5. Variance components: what to read off the summary
Every lmer or lme summary gives you two numbers per random effect, a variance (or standard deviation) for the random effect itself, and a residual variance. Their ratio tells you how clumpy the data are:
The intraclass correlation coefficient (ICC) is the proportion of total variation explained by the grouping. An ICC near 0 means groups are interchangeable, and you barely needed the random effect. An ICC near 1 means almost all the variability is between groups, and ignoring it would give wildly anti-conservative inference.
6. When to use a random effect at all
| Use a random effect when… | Don't bother when… |
|---|---|
| You have ≥ 5 (better: 8+) levels of the grouping. | You only have 2–3 levels. Use a fixed effect. |
| You don't care about each level by name; they are exchangeable samples from a larger population (streams in Oregon, deer in a herd). | Each level is biologically distinct and you specifically want its coefficient (sex, treatment). |
| Observations are nested or repeated within levels. | Each level has exactly one observation, so you have no within-group residual to separate from the group effect. (Linear models only. A GLMM has no separate residual variance, so a random effect with one observation per level is identifiable there. That is exactly the observation-level random effect used to absorb overdispersion in a Poisson or binomial GLMM.) |
| Generalization to other levels (other streams, other years) is the goal. | The levels are the universe of interest. |
Morning lab · Mixed effects models (four progressive examples)
We use the same four datasets the original lab does. A simple stream example to see complete vs partial pooling side by side; a length–weight example to introduce random intercepts with a fixed-effect covariate; a nonlinear von Bertalanffy growth model to show that random effects work on parameters of nonlinear models too; and a fish trophic position dataset with two crossed random effects (lake and species) and multiple competing structures.
nlme (Pinheiro & Bates, the classic, and required for nlme() nonlinear models) and lme4 (Bates et al., the modern workhorse). Both fit linear mixed models; lme4::lmer() is faster and uses a cleaner formula syntax (random terms in parentheses). For most linear problems you want lme4; for nonlinear mixed models you need nlme.
Streams: complete pooling vs no pooling vs partial pooling
The file stream_density.csv has fish density measurements from 100 streams, three observations per stream.
library(nlme); library(lme4); library(lattice); library(ggplot2)
TheData <- read.csv("data/stream_density.csv")
Streams <- data.frame(TheData)
Streams$Stream <- factor(Streams$Stream)
# Three models
lm1 <- lm(Density ~ 1, data=Streams) # complete pooling
lm2 <- lm(Density ~ factor(Stream) - 1, data=Streams) # no pooling (factor() -> one mean per stream)
lm3 <- lme(fixed = Density ~ 1, random = ~ 1 | Stream, data=Streams) # partial pooling
- Write out the equation each of the three models is fitting. How many parameters does each estimate?
- Plot residuals from
lm1by stream (useboxplot(split(resid(lm1), Streams$Stream))). What do you see, and what does that tell you about the validity oflm1? - Compare
coef(lm2)(the 100 stream means) tocoef(lm3)(the 100 partially-pooled stream estimates). Pick the most extreme stream and explain how much it shrank toward the overall mean, and why. - From
summary(lm3)andintervals(lm3), report the among-stream standard deviation and its 95% CI, the within-stream residual standard deviation, and the ICC.
Reveal worked solution
(a) Let $y_{ij}$ be density measurement $i$ in stream $j$. lm1: $y_{ij} = \beta_0 + \varepsilon_{ij}$, two parameters ($\beta_0, \sigma^2$). lm2: $y_{ij} = \alpha_j + \varepsilon_{ij}$ with a free mean $\alpha_j$ for each of the $j=1,\dots,100$ streams, 101 parameters (100 means $+\ \sigma^2$). lm3: $y_{ij} = \beta_0 + b_{0,j} + \varepsilon_{ij}$, $b_{0,j} \sim \mathcal{N}(0,\sigma_\text{stream}^2)$, only 3 parameters ($\beta_0, \sigma_\text{stream}^2, \sigma^2$), regardless of how many streams there are.
(b) Residuals from lm1 cluster strongly by stream, entire streams are shifted above or below zero. This violates the independence assumption of OLS. Standard errors from lm1 are too small (anti-conservative).
(c) Stream 11 has the lowest mean (8.9) and Stream 43 the highest (111.7); every stream has exactly 3 observations. The partially-pooled estimates from lm3 sit slightly closer to the grand mean of 63.26. Stream 11 moves 8.9 → 9.7, Stream 43 moves 111.7 → 111.0.
What shrinkage does here is simple. Every stream is pulled toward the grand mean by the same percentage of its distance from that mean, about 1.5%. Because it is the same fraction for all of them, a stream that starts far from the grand mean moves more in absolute terms. Stream 11 sits about 54 units below the mean and is nudged ~0.8, Stream 43 about 48 units above and is nudged ~0.7, but no stream is shrunk by a larger fraction than any other. Each estimate keeps roughly 98.5% of its own stream average and borrows just ~1.5% from the overall mean.
Two things set how big that pull is, how noisy each stream's own average is, and how different the streams genuinely are. Here the streams differ a lot relative to the noise in a 3-observation average, so the model mostly trusts each stream's own data and barely shrinks, and because every stream has the same number of observations (3), every stream gets the same small pull. Shrinkage grows when a group has few or noisy observations, or when the groups are nearly alike; it fades toward nothing when each group's own data are already precise.
(d) Approximate output:
Random effects:
Formula: ~1 | Stream
(Intercept) Residual
StdDev: 21.43 4.56
Fixed effects: Density ~ 1
Value Std.Error DF t-value
(Intercept) 63.26 2.16 200 29.3
intervals(lm3)$reStruct$Stream
lower est. upper
sd((Intercept)) 18.60 21.43 24.68
intervals(lm3)$sigma
lower est. upper
4.14 4.56 5.03
ICC = $21.43^2 / (21.43^2 + 4.56^2) \approx 459 / 480 \approx 0.957$. Almost all variation in fish density is between streams; within a stream, the three replicate measurements are very similar. That is exactly the situation in which ignoring the random effect would give you wildly over-confident inference.
Length–weight: random intercepts with a fixed-effect covariate
length_weight.csv has length and weight for individuals from multiple subjects (groups). The biological question is whether there is a length–weight relationship, and does the intercept vary by subject?
TheData <- read.csv("data/length_weight.csv")
LenW <- data.frame(TheData); LenW$Subject <- as.factor(LenW$Subject)
# Random intercept, REML (default)
m1 <- lme(Weight ~ Length, data=LenW, random = ~ 1 | Subject, method="REML")
summary(m1); intervals(m1); coef(m1)
# Same model in lme4 syntax
m1b <- lmer(Weight ~ Length + (1 | Subject), data=LenW)
summary(m1b); VarCorr(m1b); ranef(m1b)
- Write out the equation the model is fitting. What does each parameter mean biologically?
- What is the group-mean relationship between length and weight? (i.e., the fixed-effect slope and intercept.)
- What is the among-subject standard deviation of the intercept? Translate that into "subjects of the same length differ by ± X in expected weight." (Both columns are logged, so give the answer as a percentage change in weight.)
Reveal worked solution
(a) $W_{ij} = \beta_0 + b_{0,j} + \beta_1 L_{ij} + \varepsilon_{ij}$, with $b_{0,j}\sim\mathcal{N}(0,\sigma_S^2)$ and $\varepsilon_{ij}\sim\mathcal{N}(0,\sigma^2)$. $\beta_1$ is the population-average slope of weight on length, shared across subjects. $b_{0,j}$ is the subject's intercept deviation from the population mean.
(b) Approximate output: $\hat\beta_0 \approx -0.03$, $\hat\beta_1 \approx 3.02$. Because both columns are logged, this slope is the allometric exponent: weight scales as about the cube of length, $\text{weight} \propto \text{length}^{3.02}$, which is what you expect when a fish grows without changing shape, since mass tracks volume and volume tracks length cubed. A slope near 3 is the biologically meaningful reading, not "3 units of weight per unit of length". CIs from intervals(m1) exclude zero comfortably, though for an allometric exponent the interesting comparison is against 3, not against 0.
(c) Among-subject SD on the intercept is around 0.211, on the log-weight scale. A difference on a log scale is a ratio once you exponentiate: $e^{0.211} = 1.23$, so at any given length a one-SD subject is about 23% heavier than the population average, and a two-SD subject about 53% heavier. That is the interpretation to report; "±0.21" alone is not in units anyone can picture.
Von Bertalanffy growth: a nonlinear mixed model
The file fish_growth.csv contains age and length measurements for multiple individual fish ("Subject"). Each fish should follow the von Bertalanffy growth curve:
where $L_\infty$ is the asymptotic length, $\kappa$ the growth rate, and $t_0$ the theoretical age at length zero.
TheData <- read.csv("data/fish_growth.csv")
xx <- as.data.frame(cbind(Subject=TheData$Subject, Age=TheData$Age, Length=TheData$Length))
AgeLen <- groupedData(Length ~ Age | Subject, data=xx)
m_fixed <- nls(Length ~ Linf*(1-exp(-Kappa*(Age - Tzero))),
data=AgeLen, start=c(Linf=100, Kappa=0.2, Tzero=0))
summary(m_fixed)
boxplot(split(residuals(m_fixed), AgeLen$Subject))
m_nlme <- nlme(Length ~ Linf*(1-exp(-Kappa*(Age - Tzero))),
fixed = Linf + Kappa + Tzero ~ 1,
random = Linf ~ 1 | Subject,
data = AgeLen,
start = c(Linf=100, Kappa=0.2, Tzero=0))
summary(m_nlme)
plot(augPred(m_nlme))
- Why should we expect $L_\infty$ to vary by subject in a biological sense?
- From the residual boxplot of the fixed-effects
nlsfit, what evidence do you see that residuals are not independent within subject? - Compare the residual SE of the fixed-effects fit to the within-subject residual SE of the mixed model. Which is smaller, and why does that have to be the case?
- What does the code
m_nlme$coefficients$fixed[1] + m_nlme$coefficients$random$Subjectproduce? Why is that the right way to get each subject's "best estimate" of $L_\infty$ rather than fitting a separatenlsper subject?
Reveal worked solution
(a) Asymptotic body size depends on genetics, food availability, and individual life history. Pooling all fish into a single $L_\infty$ ignores real biological heterogeneity.
(b) Residuals from the fixed-effects nls form coherent vertical clusters by subject, entire subjects are systematically above or below zero. This is the same diagnostic as in the streams example. Independence is violated.
(c) The mixed-model within-subject residual SE is much smaller than the nls residual SE: $0.1060$ against $5.4168$ on this file, because the random effect on $L_\infty$ absorbed the among-subject variability that nls was forced to dump into residuals.
which is the nls residual variance of $29.34$. The additive partition is a random-intercept result. It holds when the random effect enters the mean with coefficient 1. $L_\infty$ does not, so you have to carry the attenuation factor through.
(d) It returns the BLUP (best linear unbiased predictor) of each subject's $L_\infty$, population mean plus the partially-pooled random deviation. Compared with running a separate nls per subject, BLUPs use information from other subjects to stabilize estimates for subjects with sparse or noisy data. In general, subjects with few or noisy age-points get pulled hard toward the population mean while data-rich subjects stay near their own MLE, but do not go looking for that contrast in fish_growth.csv: all 10 fish have exactly 10 age-points each, so the design is balanced and every subject receives the same amount of pull. Seeing sparse subjects shrink harder than dense ones requires an unbalanced dataset.
Comparing fixed-effect structures requires ML, not REML
Using the trophic-position dataset and the random-effect structure of M1:
fit_no_x <- lmer(Z_TP ~ 1 + (1|Fish_Species) + (1|Lake), data=dat, REML=FALSE)
fit_with_x <- lmer(Z_TP ~ Z_Length + (1|Fish_Species) + (1|Lake), data=dat, REML=FALSE)
anova(fit_no_x, fit_with_x) # LRT on the fixed-effect coefficient
- Why
REML = FALSEhere, and not above? - Run the LRT and compare AIC. Is body length a "supported" predictor of trophic position after accounting for species and lake, and do the two agree?
- After picking the model, refit it with
REML = TRUEfor reporting. Why?
Reveal worked solution
(a) We're comparing models that differ in their fixed-effect structure. REML log-likelihoods are not comparable across different fixed-effect specifications. anova() on two REML lmer fits will (by default) refit them with ML before computing the LRT, but it's better practice to fit them with REML = FALSE from the start so you can see what you're comparing.
(b) The LRT statistic is twice the gain in maximized log-likelihood from adding the one fixed slope: $\Lambda = 2(\ell_\text{alt} - \ell_\text{null})$. Here the ML log-likelihoods are $\ell_\text{null} = -146.4$ and $\ell_\text{alt} = -33.5$, so
Body length is overwhelmingly supported, and AIC agrees: 300.8 without the slope against 77.0 with it, a drop of 224 units. Both tools point the same way, which is the ordinary case.
Why are we selecting models before we have covered model selection? Two reasons. First, the honest answer to "is length supported?" here is that you do not need a selection criterion at all. The slope is $0.420$ with a standard error of $0.019$, a 95% interval of $[0.382, 0.458]$ nowhere near zero. Reading the coefficient and its interval is the first thing you should do, and often the last. Second, we are running the LRT and AIC anyway because you need the mechanics in hand before this afternoon, when the whole session is about what these criteria do not tell you. Today they agree with the coefficient and with each other; that will not always be true.
(c) REML gives less-biased variance components. The point estimates of the fixed effects barely change, but the standard errors are more honest under REML.
Core concepts: model selection
1. The likelihood ratio test (LRT) for nested models
If model $M_0$ is a special case of $M_1$ (e.g., one coefficient set to zero), then under the null hypothesis that $M_0$ is true,
where $\ell$ is the maximized log-likelihood and $k$ is the parameter count. The test is approximate, and it is least reliable exactly where mixed-model users reach for it, when you are testing whether a variance component is zero, because zero sits on the boundary of the values a variance is allowed to take. In that situation the reported $p$-value is too large. If it matters to your conclusion, use RLRsim::exactRLRT() or a parametric bootstrap, which build the correct reference distribution by simulation.
2. AIC, AICc, BIC
| Criterion | Formula | Philosophy |
|---|---|---|
| AIC | $-2\ell + 2k$ | Estimates how far a model sits from the truth, so it targets prediction: which of these models will forecast best on new data. The "distance" here is the Kullback–Leibler (K–L) distance, which measures how much information about the real process you lose by using the model in its place. Nobody can compute it, since it needs the truth, but differences in AIC estimate differences in it, which is all a comparison needs. |
| AICc | $\text{AIC} + \dfrac{2k(k+1)}{n-k-1}$ | Small-sample correction. Recommended whenever $n/k < 40$. |
| BIC | $-2\ell + k\ln n$ | Penalises complexity by $\ln n$ rather than 2, so it favours simpler models ever more aggressively as the sample grows. It targets inference: which model is the true one. |
The one-line version. Use AIC (or AICc) when the question is which model predicts best, and BIC when the question is which model is true. That split explains their different penalties: AIC charges a flat 2 per parameter, which never grows, while BIC charges $\ln n$, which does, so with enough data BIC will eventually reject any unnecessary parameter and AIC will not. Neither is "more correct"; they answer different questions.
All three put models on a common scale ($-2\ell$ plus a penalty for complexity), but they have different penalty strengths. As $n$ grows, BIC's $\ln n$ penalty overtakes AIC's constant penalty.
- This is asymmetric. Adding one pure-noise parameter changes AIC by exactly $\Delta\text{AIC} = 2 - \chi^2_1$, where $\chi^2_1$ is the likelihood-ratio statistic for the extra term. Since that statistic is never negative, the penalty of 2 is the most the complex model can ever be behind, and it is usually behind by less. On average $\chi^2_1 = 1$, so the typical gap is about 1, and roughly 16% of the time $\chi^2_1$ exceeds 2 and the noise model wins outright. So $\Delta\text{AIC} \le 2$ sweeps in models that cannot be further behind than that by construction; it is not evidence of an effect. Note the rule only bites in this direction. If the more complex model is 2 AIC units better, that is a real gap and the simpler model is not competitive.
- The rule conflates "predictively comparable" with "biologically supported." You'll see in the simulations below that nonsense predictors slip into the "best" model with $\Delta\text{AIC} = 0$ surprisingly often.
3. Cross-validation: the direct way to estimate prediction error
If the goal is predictive performance, the most honest evaluation is to hold out data, fit on the rest, and measure prediction error on the held-out set. Leave-one-out cross-validation (LOOCV) does this $n$ times, $k$-fold CV does it $k$ times. boot::cv.glm() gives you LOOCV (and $k$-fold) for a GLM.
Be careful about what this does and does not buy you. CV gives you a direct estimate of out-of-sample error, which is exactly what you want when the question is "how well does this model predict?" It is not an independent safeguard against picking the wrong model. For a Gaussian linear model, LOOCV is asymptotically equivalent to AIC (Stone 1977), so the two agree far more often than intuition suggests, and are fooled by the same noise. Exercise A3 makes you measure this yourself rather than take it on faith.
where $\hat{f}_{-i}$ is the model fit with the $i$-th observation withheld. Models that overfit will perform well on the training data but poorly on the held-out fold; CV exposes this directly.
4. Multimodel inference (Burnham & Anderson, briefly)
If several models are close in AIC, the "best" is poorly determined and any one of them might be the closest to the truth in a different sample. Akaike weights
$w_i = \exp(-\tfrac{1}{2}\Delta_i) / \sum_j \exp(-\tfrac{1}{2}\Delta_j)$
weight each model's predictions and can be used for model-averaged effect estimates. We will show this only briefly today; the deeper conversation is whether the question you're asking is best answered by averaging at all.
Afternoon lab · Model selection & the limits of "the best model"
The original lab is built around running the same simulation many times and watching how often each criterion (p-value, AIC, AICc, BIC) declares a noise variable "important." The lessons are uncomfortable: AIC retains noise variables noticeably more often than naïve p-values, $\Delta\text{AIC} < 2$ is not the safety rail people think, and cross-validation is the only criterion that directly answers "how well does this model predict?"
What does $\Delta\text{AIC} = 1.5$ actually mean?
n <- 1000
x <- runif(n)
y <- 2 + 3*x + rnorm(n, 0, 0.2) # strong real effect
x2 <- rnorm(n) # pure noise predictor
lm1 <- lm(y ~ x)
lm2 <- lm(y ~ x + x2)
AIC(lm1, lm2) - min(AIC(lm1, lm2))
- Run the code 20 times (resampling x2 and y each time). How often does the model with the nonsense variable have $\Delta\text{AIC} < 2$?
- Use the snippet below to formalize it. What fraction of 1000 reps puts the "junk" model within 2 AIC units of the right one?
reps <- 1000
within2 <- replicate(reps, {
n <- 1000; x <- runif(n); x2 <- rnorm(n)
y <- 2 + 3*x + rnorm(n, 0, 0.2)
d <- AIC(lm(y ~ x + x2)) - AIC(lm(y ~ x))
d < 2
})
mean(within2) # essentially 1.0 — it is always within 2
Reveal solution & discussion
The nonsense-variable model is within 2 AIC units of the correct model essentially 100% of the time. It always is. This is not luck; it falls straight out of the definition of AIC. Write $\text{AIC} = -2\ell + 2k$ for each model and subtract the simpler ($k$ parameters) from the more complex ($k+1$ parameters):
because $2(\ell_{\text{big}} - \ell_{\text{small}})$ is exactly the likelihood-ratio statistic $\chi^2_1$ for the extra term (twice the gain in maximized log-likelihood). This is the general identity worth keeping. Adding one parameter moves AIC by $2 - \chi^2_1$: the penalty for a parameter is a flat $+2$, while the reward is a random $\chi^2_1$. Two consequences follow at once. Since $\chi^2_1 \ge 0$ always, $\Delta\text{AIC} \le 2$ always, so a nested one-extra-parameter model is within 2 by construction, whatever the data say. And the junk model wins outright ($\Delta\text{AIC} < 0$) exactly when $\chi^2_1 > 2$, which for a true null happens with probability $P(\chi^2_1 > 2) = 0.157$, about 16% of the time. The $\Delta\text{AIC} < 2$ rule does not screen out useless variables at all.
The lesson: the $\Delta\text{AIC} < 2$ rule is structurally biased toward including junk. Anderson & Burnham's own writing has been used selectively here; many authors (Arnold 2010 is the standard reference) push back on the "include any model within 2" practice and emphasize that the included variable's coefficient and CI have to do real work.
Simulation: how often does AIC pick noise as "best"?
Generate $y \sim \mathcal{N}(5, 3^2)$, completely unrelated to $x_1, x_2, x_3 \sim U(0,1)$. Fit every subset; record how many predictors the top model retains, under each criterion.
library(MuMIn)
options(na.action = "na.fail")
set.seed(126)
n <- 50; a <- 5; sdy <- 3
nummodels <- 500
pstor <- AICstor <- AICcstor <- BICstor <- rep(NA, nummodels)
for(i in 1:nummodels) {
y <- rnorm(n, mean=a, sd=sdy)
x1 <- runif(n); x2 <- runif(n); x3 <- runif(n)
d <- data.frame(y, x1, x2, x3)
reg <- lm(y ~ ., data=d)
pstor[i] <- sum(summary(reg)$coefficients[2:4,4] < 0.05)
AICstor[i] <- sum(!is.na(dredge(reg, rank="AIC")[1, 2:4]))
AICcstor[i] <- sum(!is.na(dredge(reg, rank="AICc")[1, 2:4]))
BICstor[i] <- sum(!is.na(dredge(reg, rank="BIC")[1, 2:4]))
}
data.frame(p = mean(pstor > 0),
AIC = mean(AICstor > 0),
AICc = mean(AICcstor > 0),
BIC = mean(BICstor > 0))
- Predict before you run. Which criterion will pick "at least one noise variable" most often?
- Run the simulation. Report the four proportions. Compare to your prediction.
- Why does BIC do so much better than AIC at avoiding noise variables in this setting? When would BIC backfire?
Reveal solution & discussion
Approximate results across 500 reps (your seed will differ):
| Criterion | P(top model includes ≥ 1 noise variable) |
|---|---|
| p < 0.05 (any of 3) | ~0.16 |
| AIC | ~0.45 |
| AICc | ~0.39 |
| BIC | ~0.16 |
AIC and AICc retain a noise predictor in the top model about 40–45% of the time. You can predict that rate rather than only reporting it, using the $\Delta\text{AIC} = 2 - \chi^2_1$ identity from Exercise A1. A single noise predictor enters the AIC-best model exactly when it clears $\chi^2_1 > 2$, probability $0.157$ each. With three near-independent noise predictors, the chance that at least one slips in is
in line with the simulated 40–45% (the small excess is joint selection and the mild correlation among the fitted predictors). The same reusable move explains the two conservative criteria, each just raises the bar the extra variable must clear. The family-wise p-value rate is $1 - 0.95^3 \approx 0.14$. BIC replaces AIC's flat penalty of 2 with $\ln n \approx 3.9$ for $n = 50$, so a junk predictor now needs $\chi^2_1 > 3.9$ (probability $P(\chi^2_1 > 3.9) \approx 0.048$ each, hence $1 - (1 - 0.048)^3 \approx 0.14$ overall), about as strict as the p-value screen, and matching the observed $\approx 0.16$. AIC's penalty of 2 is simply too small to keep junk out.
When would BIC backfire? When true effects are weak. BIC's heavier penalty buys Type-I safety at the cost of Type-II error, see the next exercise.
LOOCV vs AIC for the noise-only case
Same setup as Exercise A2 ($y$ unrelated to predictors). It is tempting to assume that cross-validation, because it actually holds data out, is the more trustworthy criterion. Test that assumption rather than accepting it. Fit all 8 models to one realization and rank them by both LOOCV MSE and AIC.
library(boot)
set.seed(126); n <- 50
y <- rnorm(n, 5, 3)
x1 <- runif(n); x2 <- runif(n); x3 <- runif(n)
d <- data.frame(y, x1, x2, x3)
cvmse <- function(formula) cv.glm(d, glm(formula, data=d))$delta[1]
forms <- list(
m0 = y ~ 1,
m1 = y ~ x1, m2 = y ~ x2, m3 = y ~ x3,
m12 = y ~ x1+x2, m13 = y ~ x1+x3, m23 = y ~ x2+x3,
m123 = y ~ x1+x2+x3)
cv <- sapply(forms, cvmse)
aic <- sapply(forms, function(f) AIC(glm(f, data=d)))
round(data.frame(LOOCV=cv, AIC=aic, dAIC=aic-min(aic))[order(cv), ], 3)
- Which model has the smallest LOOCV MSE? Which does AIC pick? Is either one the true model?
- By how much does the winner beat the intercept-only model, in AIC units and as a percentage of the CV MSE? The winner is just the intercept-only model plus one junk predictor, so the $\Delta\text{AIC} = 2 - \chi^2_1$ identity from the core-concepts section applies. Use it to work out what that margin actually tells you.
- Repeat over many simulated datasets. What fraction of the time does the intercept-only model (truth!) win on LOOCV, and what fraction on AIC? Do the two criteria disagree as often as you expected?
- Neither criterion recovers the truth reliably here. Is that a defect in the criteria, and would a better criterion fix it?
Reveal solution & discussion
(a) Both criteria pick m3: a pure-noise predictor. They agree, and they are both wrong:
LOOCV AIC dAIC
m3 5.995 233.059 0.000
m0 6.031 233.717 0.658
m13 6.052 233.392 0.333
m1 6.078 233.948 0.889
m23 6.205 235.059 2.000
m2 6.239 235.715 2.655
m123 6.286 235.389 2.330
m12 6.309 235.939 2.880
The two orderings are nearly identical (Spearman correlation 0.95). This is the first hint that CV is not an independent check on AIC.
(b) m3 beats the truth by $\Delta$AIC = 0.658 and by 0.036 in CV MSE, six tenths of one percent. But the interesting part is why the margin has that value. m3 is m0 with one extra junk predictor, so the identity from the core-concepts section applies exactly:
The entire margin is just the likelihood-ratio statistic for x3, which is $\chi^2_1 = 2.658$ ($p = 0.103$, not close to significant). x3 wins for one reason and one reason only. Its $\chi^2$ landed above 2. That is exactly the event you already met when the $\Delta\text{AIC} < 2$ rule was picked apart: $P(\chi^2_1 > 2) = 15.7\%$, the rate at which a junk variable takes the top spot outright. Exercise A3 is not a new phenomenon; it is that same 16% event, caught in the act.
So do not read this table by asking which models fall within 2 AIC of the winner. As you saw earlier, a nested junk model is within 2 by construction, so that question has a guaranteed answer and tells you nothing. Ask instead what x3's coefficient does: $-1.914$ with a 95% CI of $[-4.292,\ 0.463]$, spanning zero. The variable that "won" cannot even sign its own effect.
(c) Over 2000 simulated datasets the intercept-only model wins 58.4% of the time on LOOCV and 57.6% on AIC. That gap of 0.8 points is smaller than the Monte Carlo error on either estimate (±2.2), so the honest reading is that the two criteria perform identically. They select the same model 90% of the time. Both are fooled by noise in roughly 42% of datasets.
This is not a coincidence of this simulation. For a Gaussian linear model, leave-one-out CV and AIC are asymptotically equivalent. Stone (1977) proved they are the same criterion in the limit, and at $n=50$ they have already nearly converged. Holding data out does not buy you protection AIC lacks; it is a different route to the same number.
That equivalence is the best reason AIC is everywhere. LOOCV is the gold-standard estimate of out-of-sample prediction error, but it costs you $n$ refits; AIC gives you the same answer in closed form from a single fit. So when the goal is genuinely prediction, which model will forecast best on data it has not seen, AIC is doing exactly its job, and doing it cheaply, which is why it became the standard tool. The trouble in this exercise is not that AIC predicts badly; it is that we asked a prediction criterion an inference question, "which variable is real?", that it was never built to answer. Much of the ecology literature slips here, reading a low-$\Delta$AIC predictor as an established effect. Keep the two jobs apart: AIC (≈ LOOCV) ranks models for prediction; coefficients, intervals, and study design tell you whether an effect is real.
(d) Not a defect, and no. With eight candidate models and $n=50$, three noise predictors will produce spurious in-sample fit some of the time, and any criterion that ranks models on fit to this one dataset will sometimes rank noise first. The criteria are answering the question they were asked, "which of these eight predicts best?", and dutifully returning an answer even though the honest answer is "none of them, and they are all the same." Selection returns a winner whether or not one deserves to win.
What helps is not a cleverer criterion but a different question. Once a table is in front of you, the rank is the least informative thing in it. Make the winning variable justify itself with its coefficient and interval, as in (b), where x3's CI comfortably contains zero (this is Arnold's 2010 point). And upstream of that, keep the candidate set small and tied to hypotheses you held before seeing the data. The 42% failure rate is a direct consequence of dredging eight models out of pure noise. Fewer, better-motivated models is the only move here that changes the failure rate rather than relabeling it.
Caveat: both criteria are about prediction. If your question is "is variable X causally important," neither AIC nor CV answers it; you need a causal frame and (often) a designed experiment.
LRT vs AICc for a random-slope decision
Return to the trophic-position dataset. Compare two nested random-effects structures using both LRT and AICc.
(1 + Z_Length || Fish_Species) gives species their own intercepts and their own slopes, but fixes the correlation between the two at zero. With only three species there is not enough information to estimate that correlation on top of the two variances. The single-bar form (1 + Z_Length | Fish_Species) returns boundary (singular) fit, with the correlation pinned at exactly 1.000. You work through why in the morning problem set (Problem 4); here we use the version that converges.# Both fit with REML because they share the same fixed effects
m_int <- lmer(Z_TP ~ Z_Length + (1|Fish_Species) + (1|Lake), data=dat, REML=TRUE)
m_slop <- lmer(Z_TP ~ Z_Length + (1+Z_Length||Fish_Species) + (1|Lake), data=dat, REML=TRUE)
anova(m_int, m_slop, refit=FALSE)
AICcmodavg::aictab(list(intercepts_only=m_int, with_species_slope=m_slop))
- Why
refit = FALSE? - If LRT and AICc agree, you're in easy territory. If they disagree (LRT says "not significant" but AICc favors the more complex model), how should you decide? What does each statistic actually claim?
- Why might the LRT $p$-value here be conservative? (Hint: boundary test.)
Reveal solution
(a) The two models share fixed effects but differ in random structure. We compare REML log-likelihoods because they are unbiased for variance components. Setting refit = FALSE prevents anova from refitting them under ML.
(b) Run them. Here the two agree emphatically. The species-level random slope is strongly supported both ways:
anova(m_int, m_slop, refit=FALSE)
# npar AIC logLik Chisq Df Pr(>Chisq)
# m_int 5 82.47 -36.23
# m_slop 6 41.88 -14.94 42.59 1 6.7e-11 ***
AICcmodavg::aictab(list(intercepts_only=m_int, with_species_slope=m_slop))
# K AICc Delta_AICc AICcWt
# with_species_slope 6 42.36 0.00 1.00
# intercepts_only 5 82.81 40.45 0.00
The LRT gives $\chi^2 = 42.6$ on 1 df, $p \approx 7\times10^{-11}$; AICc favors the random-slope model by $\Delta$AICc $= 40.5$ (Akaike weight $\approx 1.00$). This is easy territory, keep the slope. But notice what each statistic claimed, because they answer different questions and will not always agree. The LRT asks "is the larger model significantly better at maximizing likelihood?", an inference question about whether the slope variance is really nonzero. AICc asks "is the larger model expected to predict better out of sample?" When they disagree (LRT says "not significant" but AICc still prefers the bigger model), let the question decide. For inference (does the random slope matter biologically?) lean on the LRT and the variance-component CI; for prediction, trust AICc (which, from Exercise A3, is ≈ LOOCV).
(c) One catch makes the LRT $p$-value untrustworthy in borderline cases. The null hypothesis is that the slope variance is exactly zero, but a variance cannot be negative, so zero sits on the very edge of the values the parameter is allowed to take. When you test a parameter at the boundary of its space, the usual $\chi^2$ reference distribution is the wrong one, and it makes the reported $p$-value too large (conservative). A genuinely important random slope can therefore come back looking "not significant."
Here it does not matter. The effect is so strong ($p \approx 7\times10^{-11}$) that no correction would change the verdict. But in a borderline case the boundary correction can flip your conclusion. The practical rule: for a boundary test ("is this variance zero?") do not trust anova()'s $p$-value. Use RLRsim::exactRLRT() or a parametric bootstrap, which build the correct reference distribution by simulation and give you an honest $p$-value.
How should we make inference?
By the end of today, you should be skeptical of three habits:
- Dredging: fitting every subset of predictors with
dredge()or stepwise selection, then reporting the "best" model as if its coefficients were honest. The simulations above show how this manufactures false discoveries. - Reporting only p-values or $\Delta\text{AIC}$ instead of the effect size. A coefficient with a tight CI bounded well away from zero is a meaningful effect; a coefficient with a wide CI is uncertain no matter what any criterion says. (For a Wald CI and a Wald test built from the same SE, "the 95% CI overlaps zero" and "$p > 0.05$" are the same statement, so they cannot disagree. That equivalence is not general. A profile-likelihood or bootstrap CI is built differently and can perfectly well sit off zero while an LRT returns $p > 0.05$, or vice versa, which is exactly why, in the singular-fit and boundary cases above, we prefer the profile/bootstrap interval to the Wald one.) The science lives in the magnitude and direction of the effect and how sure you are of it, not in whether it cleared a $p = 0.05$ or $\Delta\text{AIC} = 2$ threshold.
- Confusing prediction quality with effect support. Two different questions, two different criteria. Cross-validation tells you about prediction; coefficient CIs (and study design) tell you about effects.
A defensible workflow:
- State the question first. Back in the razor-clam scenario from this morning (badjuice, the fictitious toxin, measured on 10 Oregon beaches): "Does badjuice affect clam abundance, controlling for beach?" is a different question from "Predict clam abundance at a new beach next year."
- Decide the model structure from biology and design, not from automated selection. Beach and year are random effects because you want to generalize beyond the particular beaches you sampled. Badjuice is a fixed effect because you care about its coefficient. That slope is the answer to the student's question.
- Fit one principal model; check assumptions; report the coefficient of interest with a CI.
- If competing structures are scientifically interesting, compare them, but match the tool to the question. For inference (is this structure real?), use an LRT or BIC. For prediction (which structure forecasts best out of sample?), use AIC, AICc, or LOOCV, and since AIC is asymptotically LOOCV (Exercise A3), AIC gives you the cross-validation answer from a single fit, which is why it is the standard and easiest prediction criterion. Either way, show the coefficient of interest under each candidate: does the conclusion change?
This is the philosophical stance you'll see again in Day 4 (likelihood/Bayes) and Day 5 (full Bayesian inference). The Bayesian framework makes points 2–4 explicit and quantitative. You specify priors, get a full posterior on every parameter, and the "uncertainty" you report is just the spread of that posterior.
R cheat sheet
Mixed models
| Task | nlme | lme4 |
|---|---|---|
| Random intercept | lme(y ~ x, random = ~1|g) | lmer(y ~ x + (1|g)) |
| Random intercept & slope (correlated) | lme(y ~ x, random = ~x|g) | lmer(y ~ x + (1+x|g)) |
| Uncorrelated random int + slope | lme(y~x, random=list(g=pdDiag(~x))) | lmer(y ~ x + (1|g) + (0+x|g)) |
| Two crossed random effects | limited support | lmer(y ~ x + (1|g1) + (1|g2)) |
| Nested random effects | random = ~1|g1/g2 | (1|g1/g2) or (1|g1) + (1|g1:g2) |
| REML vs ML | method = "REML" / "ML" | REML = TRUE / FALSE |
| BLUPs of random effects | ranef(fit) | ranef(fit) |
| Group-level fitted intercepts | coef(fit) | coef(fit) |
| Variance components | VarCorr(fit) or intervals(fit) | VarCorr(fit) or confint(fit) |
| Nonlinear mixed | nlme(...) | — |
Model selection
| Task | Function |
|---|---|
| LRT for nested models | anova(m0, m1) (use REML=FALSE for fixed-effect comparisons) |
| AIC / AICc / BIC | AIC(), AICcmodavg::AICc(), BIC() |
| Model selection table | AICcmodavg::aictab(list(m1, m2, ...)) |
| All subsets ("dredge") | MuMIn::dredge(global_model) (use sparingly, see warning above) |
| LOOCV / k-fold CV for GLMs | boot::cv.glm(data, glm_fit) |
anova(lmer1, lmer2)with REML fits will silently refit them in ML. That is usually what you want for a fixed-effect LRT, but be aware. For random-effect comparisons, fit both with REML and passrefit = FALSE.dredge()requires you to setoptions(na.action = "na.fail")globally. Otherwise different submodels can be fit to slightly different rows of your data afterna.omit, and the AIC values are not comparable.