Day 3 · Two assessed problem sets · 20 pts each

Mixed models & model selection: the graded hand-in

Two separately submitted 20-point problem sets, 40 points across Day 3. Ten problems, six on hierarchical (mixed) models in the morning, four on hypothesis tests and model selection in the afternoon. Three problems are worked on real datasets that live in this folder; four ask you to simulate, exactly as in the lab; the rest are worked from printed output. Write every answer in the R Markdown hand-in template, knit to HTML, and submit on Canvas.

This is the assessed problem set. Answers are not shown here. Write your work in the hand-in templates: morning_lab_template.Rmd for the morning (mixed-model) problems and afternoon_lab_template.Rmd for the afternoon (model-selection) problems. Knit each to HTML, then upload to the matching Canvas assignment.

For worked-example study with visible answers, see the practice problem set and the plain-language summary.

This problem set is designed to take roughly the same time as the main lab. Work each problem in the matching R Markdown template, knit to HTML, and submit on Canvas. Where simulations are requested, exact numbers depend on the seed; "approximately" is in the spirit of the exercise.

Datasets for this assignment

Click a file to download it, then put it in a data/ subfolder beside your .Rmd so the read.csv() calls resolve.

length_weight.csvLength and weight per individual, grouped by subject. Used in Problem 2.
qcbs_w6_data.csvQCBS fish trophic position: three species across six lakes. Used in Problems 4 and 9.

Problems 1, 3, 7 and 8 simulate their own data in the code block given with each problem, so they need no file.

Part 1 · Mixed models (morning · 20 pts)

Problem 1 · simulation · shrinkage and effort

Which streams get pulled hardest toward the mean?

The walkthrough used a balanced design, with every stream sampled the same number of times. Real survey effort is never balanced, and the imbalance is exactly where partial pooling earns its keep. Here you simulate an unbalanced design, so you know the truth, and watch what the model does with it.

Setup: 24 streams, deliberately unequal effort
library(nlme)
set.seed(413)

nvisit <- c(rep(2, 8), rep(5, 8), rep(30, 8))   # 8 streams each at 2, 5, 30 visits
tau <- 12;  sig <- 20;  mu <- 80              # TRUE among-stream SD, within SD, grand mean

stream_mean <- rnorm(length(nvisit), mu, tau)      # each stream's real density
Streams <- do.call(rbind, lapply(seq_along(nvisit), function(i)
  data.frame(Stream = factor(i),
             Density = rnorm(nvisit[i], stream_mean[i], sig))))

m <- lme(Density ~ 1, random = ~ 1 | Stream, data = Streams)

nopool  <- tapply(Streams$Density, Streams$Stream, mean)   # each stream on its own
partial <- coef(m)[, 1]                                    # partially pooled
n_i     <- as.numeric(table(Streams$Stream))
  1. Predict before you compute. Partial pooling keeps a fraction $B_i$ of each stream's own mean and pulls the rest toward the grand mean, where
    $B_i = \dfrac{\tau^2}{\tau^2 + \sigma^2/n_i}$
    Using the true $\tau = 12$ and $\sigma = 20$, work out $B_i$ by hand for a stream with 2 visits and for one with 30. Which group will be pulled further, and roughly how many times further? Write the numbers down before running anything else.
  2. Now check. Extract $\hat\tau$ and $\hat\sigma$ with VarCorr(m), compute $B_i$ for every stream, and tabulate the mean $|$nopoolpartial$|$ separately for the 2-visit, 5-visit and 30-visit streams. Did your prediction hold?
  3. Explain in two or three sentences why the formula behaves this way. What is $\sigma^2/n_i$ measuring, and what happens to $B_i$ as $n_i$ grows?
  4. One of the 2-visit streams will have an unusually extreme raw mean, simply because two observations are not many. Find it, report its no-pooling and partially-pooled estimates, and say which you would put in a report and why.
  5. A colleague proposes dropping every stream with fewer than 5 visits, "because those means are unreliable." Using your answer to (b), explain what partial pooling already does about unreliable means, and what dropping the streams would cost.
Your answer goes in the R Markdown hand-in. Report your hand-computed $B$ values, the table from (b), the extreme stream from (d), and your reasoning in (c) and (e).
Problem 2 · reading output · variance components

Reading a mixed model someone else fitted

Part (a) needs no computer. Most of the mixed models you meet in your career will arrive as printed output in a paper or a collaborator's email, and reading one is a different skill from fitting one.

A colleague weighs nestlings in 18 broods and asks whether chicks in larger broods are lighter. They send you this and nothing else:

Linear mixed model fit by REML ['lmerMod']
Formula: mass ~ broodsize + (1 | brood)

Random effects:
 Groups   Name        Variance Std.Dev.
 brood    (Intercept) 7.218    2.687
 Residual             2.249    1.500
Number of obs: 74, groups:  brood, 18

Fixed effects:
            Estimate Std. Error t value
(Intercept)  22.2315     2.0053  11.087
broodsize    -0.6663     0.4560  -1.461
  1. From that output alone: (i) how much of the variation in chick mass is between broods rather than within them? Compute the ICC and say it in a sentence a field biologist would use. (ii) What is the estimated effect of one extra chick in the brood, and how confident would you be that it is real? (iii) The colleague concludes "brood size doesn't matter." Give one reason that conclusion might be premature, given the design they used.

Now back to the length–weight data from the walkthrough, where you already have m1 and m1b fitted:

Setup
TheData <- read.csv("data/length_weight.csv")
LenW <- data.frame(TheData); LenW$Subject <- as.factor(LenW$Subject)

m1  <- lme(Weight ~ Length, data=LenW, random = ~ 1 | Subject, method="REML")
m1b <- lmer(Weight ~ Length + (1 | Subject), data=LenW)   # same model, lme4 syntax
  1. Report the within-subject residual SD and compute the ICC. Contrast it with the ICC implied by Problem 1's true values ($\tau = 12$, $\sigma = 20$) and explain what the difference tells you about the two designs.
  2. Fit a random-slope model lmer(Weight ~ Length + (1 + Length | Subject)) and compare it to m1b with anova(m1b, m_slope, refit = FALSE). Is the random slope supported? Explain why refit = FALSE is correct here.
Your answer goes in the R Markdown hand-in. Report the ICC and interpretation for the nestling output, the ICC comparison in (b), and the random-slope verdict with your reasoning about refit.
Problem 3 · simulation · where the variation goes

If you leave the fish out of the model, where does the fish-to-fish variation go?

Fish differ from one another, and they also get measured imperfectly. Those are two separate sources of variation, and a mixed model can tell them apart. A fixed-effects fit has only one place to put variation, the residual, so it has to blend them.

Here you build the data yourself, so you know exactly how big each source really is, and then watch what each fit reports.

Simulate 12 fish, measured at ages 1 to 8
library(nlme)
set.seed(77)

nfish <- 12; ages <- 1:8
Kap <- 0.25; T0 <- 0
sd_Linf <- 12    # fish really do differ: SD of 12 in asymptotic length
sd_obs  <- 3     # and each measurement is off by about 3

Linf_i <- rnorm(nfish, 100, sd_Linf)      # each fish's own Linf
sim <- do.call(rbind, lapply(1:nfish, function(i) data.frame(
  Subject = factor(i), Age = ages,
  Length  = Linf_i[i]*(1-exp(-Kap*(ages - T0))) + rnorm(length(ages), 0, sd_obs))))
gd <- groupedData(Length ~ Age | Subject, data = sim)

# Fit 1: one curve for all fish. No way to say that fish differ.
fit_nls  <- nls(Length ~ Linf*(1-exp(-Kappa*(Age-Tzero))), data = sim,
                start = c(Linf=100, Kappa=.2, Tzero=0))

# Fit 2: each fish gets its own Linf, drawn from a distribution.
fit_nlme <- nlme(Length ~ Linf*(1-exp(-Kappa*(Age-Tzero))),
                 fixed = Linf + Kappa + Tzero ~ 1, random = Linf ~ 1 | Subject,
                 data = gd, start = c(Linf=100, Kappa=.2, Tzero=0))
  1. What does each fit say the measurement error is? Run summary(fit_nls)$sigma and VarCorr(fit_nlme). You built the data with a measurement error of 3 and a fish-to-fish SD of 12. Which fit recovers both numbers, and what does the other one report instead?
  2. Work out where that wrong number came from. No calculus needed. Just look at the growth equation. Length is $L_\infty$ multiplied by the factor $(1 - e^{-\kappa a})$, and that factor is the fraction of its final size a fish has reached by age $a$.

    So two fish whose $L_\infty$ differ by 12 are not 12 apart at every age. At age $a$ they are $12 \times (\text{that fraction})$ apart, close together when young and far apart when old.

    1. Compute the fraction at each age: 1 - exp(-0.25 * 1:8). How far apart are two such fish at age 1? At age 8?
    2. At any age the fish are spread out by both that gap and the measurement error. Squares add, so the spread at age $a$ is sqrt((12*fraction)^2 + 3^2). Compute all eight.
    3. nls must describe all eight ages with one number. Take sqrt(mean(SD^2)) of your eight values and compare it with the $\sigma$ that nls reported in (a). Close?
  3. What that does to the residual plot. Your eight numbers in (b) should grow with age. But nls used a single $\sigma$ for all of them, so its residuals must be too small at young ages and too large at old ones. Draw plot(fitted(fit_nls), resid(fit_nls)) and describe the shape.

    Here is the trap. That picture looks exactly like non-constant variance, and the usual fixes are a variance function or a log transform. Neither would help. Say in one or two sentences what is actually wrong with the model.

  4. What you gain by separating the two. Compare the standard errors of Kappa and Tzero between the fits (summary(fit_nls)$coefficients and summary(fit_nlme)$tTable). Neither parameter was given a random effect, yet one fit gives much tighter values. Every standard error is scaled by how noisy the model thinks the data are. Use that to explain the difference.
  5. How many fish do you need? Re-run the whole thing with nfish <- 4, then with nfish <- 20, refitting fit_nlme each time, and report the estimated fish-to-fish SD. It was built as 12 in every case. What does the pattern say about how many groups you need before a random effect is worth fitting?
Watch out. Part (e) estimates a spread, which needs far more groups to pin down than an average does. One run at nfish = 4 proves nothing on its own. If you can, run each setting a few times and look at how much the answer jumps around.
Your answer goes in the R Markdown hand-in. Report the three SDs from (a), your eight numbers and the comparison in (b), the residual-plot description, the standard-error comparison, and the pattern from (e).
Problem 4 · real data · crossed random effects · when a model asks for too much

Fish trophic position, and a random-effect structure the data cannot support

The QCBS dataset qcbs_w6_data.csv gives trophic position vs body length for three fish species (S1, S2, S3) sampled across six lakes (L1L6). The biological question is whether trophic position increases with body length, and does that relationship differ by species and by lake?

This problem has a second purpose. One of the candidate models below asks the data for something it cannot give, and it is the model that wins the model-selection table. Learning to spot that is the point.

Setup & z-scoring
dat <- read.csv("data/qcbs_w6_data.csv")
dat$Fish_Species <- as.factor(dat$Fish_Species)
dat$Lake         <- as.factor(dat$Lake)
dat$Z_Length     <- scale(dat$Fish_Length)[,1]   # z-score for numerical stability
dat$Z_TP         <- scale(dat$Trophic_Pos)[,1]

M1 <- lmer(Z_TP ~ Z_Length + (1|Fish_Species) + (1|Lake), data=dat, REML=TRUE)
M3 <- lmer(Z_TP ~ Z_Length + (1|Fish_Species), data=dat, REML=TRUE)
M4 <- lmer(Z_TP ~ Z_Length + (1|Lake), data=dat, REML=TRUE)
M7 <- lmer(Z_TP ~ Z_Length + (1|Fish_Species) + (1+Z_Length|Lake), data=dat, REML=TRUE)
M8 <- lmer(Z_TP ~ Z_Length + (1+Z_Length|Fish_Species) + (1|Lake), data=dat, REML=TRUE)

library(AICcmodavg)
aictab(list(M1=M1,M3=M3,M4=M4,M7=M7,M8=M8))
  1. Why are both Lake and Fish_Species candidates for random effects rather than fixed? Give the argument that would push you the other way.
  2. What does the term (1 + Z_Length | Fish_Species) assume about the population of slopes across species? Write out the implied bivariate Normal for the (intercept, slope) pair, and count how many parameters that costs. Two variances plus what?
  3. Report the AICc table and name the winner. Then run isSingular() on all five fits:
    sapply(list(M1=M1,M3=M3,M4=M4,M7=M7,M8=M8), lme4::isSingular)
    Two of them come back TRUE, and one of those two is the model that just won. What did R print when you fitted them, and did you notice it at the time?
  4. Find the parameter that broke. Run VarCorr(M8) and look at the Corr column. The estimated correlation between species intercepts and species slopes is exactly $1.000$, not "close to 1" but sitting precisely on the largest value a correlation is allowed to take. That is what boundary (singular) fit means.

    Why did the correlation break rather than one of the two variances? You have three species, so three (intercept, slope) pairs, which is three points. Rather than reason about it in the abstract, watch what three points can and cannot tell you. Both simulations below use data with a known answer:

    set.seed(4)
    
    # Correlation from 3 points, when the TRUE correlation is zero
    r3 <- replicate(20000, cor(rnorm(3), rnorm(3)))
    median(abs(r3))        # the typical |r| you get from three points
    mean(abs(r3) > 0.9)     # how often it looks nearly perfect
    
    # Standard deviation from 3 points, when the TRUE sd is 1
    s3 <- replicate(20000, sd(rnorm(3)))
    median(s3)
    mean(abs(s3 - 1) < 0.25)  # how often it lands within 25% of the truth
    1. Run the first block. Every one of those 20,000 correlations came from data with no relationship at all. What is the typical $|r|$, and how often does it come back above 0.9?
    2. Run the second. How far off is a standard deviation estimated from three points, and how often is it roughly right?
    3. Now put the two together. In two or three sentences, say why M8's correlation was the parameter that failed. Which of the two quantities can three groups say something useful about, and which one will happily return an extreme answer no matter what the truth is?

    If you want to see it directly, plot one of the samples: plot(rnorm(3), rnorm(3)). Three points often look like a line.

  5. Ask for less: the || notation. Writing a double bar instead of a single one keeps both random effects but forces their correlation to zero, so the model estimates two parameters instead of three:
    # (1 + Z_Length | Fish_Species)   intercepts, slopes, AND their correlation  — 3 parameters
    # (1 + Z_Length || Fish_Species)  intercepts and slopes, correlation fixed at 0 — 2 parameters
    
    M8u <- lmer(Z_TP ~ Z_Length + (1+Z_Length||Fish_Species) + (1|Lake), data=dat, REML=TRUE)
    lme4::isSingular(M8u)
    VarCorr(M8u)
    Does it converge? Compare its two standard deviations with M8's. Has dropping the correlation cost you anything you actually wanted to know?
  6. The judgment call. Add M8u to the AICc table. M8 still comes out ahead by about 6 AICc units, and anova(M8u, M8, refit = FALSE) returns $p = 0.004$, so both criteria say the correlation parameter is "worth it". Yet that parameter is pinned at its boundary.

    Which model do you report, and why? Your answer should say what a likelihood-ratio test and an AICc difference can and cannot tell you about a parameter sitting on the edge of its allowed range.

  7. Three species and six lakes is on the edge of what should be treated as random at all. When would you switch species to a fixed effect instead, and what would you lose by doing so?
Carry this forward. You will meet || again in the afternoon walkthrough, where the same species-slope model appears in a model-comparison exercise. The habit worth forming today is that after every lmer fit with a random slope, check isSingular() before you believe anything the model tells you.
Your answer goes in the R Markdown hand-in. Report the AICc table, the singularity check, the correlation from VarCorr(M8), the converging M8u fit, and your reasoning in (d), (f) and (g).
Problem 5 · variance partitioning · binomial GLMM

Detection probability across regions, a binomial GLMM

You fit a binomial mixed model to detection/non-detection data (a camera-trap or PIT-array design; the algebra is identical). Cameras are nested within regions:

m <- glmer(Detect ~ scale(Covariate) + (1 | Region/Camera), data=d, family=binomial)
VarCorr(m)
# Groups        Name        Variance Std.Dev.
# Camera:Region (Intercept) 1.05     1.02
# Region        (Intercept) 0.46     0.68
# Fixed effects:
#                   Estimate Std.Error z
# (Intercept)       -1.4      0.30     -4.6
# scale(Covariate)   0.62     0.13      4.8
  1. Interpret the output in words. (i) The fixed-effect estimate for scale(Covariate) is $0.62$ on the logit scale. In which direction does detection change as the covariate increases, and is the effect statistically clear (look at the estimate relative to its standard error)? (ii) Compare the two random-effect standard deviations, Region ($\sqrt{0.46}=0.68$) and Camera-within-Region ($\sqrt{1.05}=1.02$): at which level, among regions, or among cameras within a region, is there more unexplained variation in detectability, and what would that suggest biologically?
  2. For a camera at mean covariate value with average region and camera intercepts, what is the expected detection probability? (Use plogis().)
  3. Translate the covariate slope into an odds ratio per 1 SD, with an approximate 95% CI.
  4. Why include the camera-level (rather than only the region-level) random intercept at all? What does dropping it do to your standard errors?
Your answer goes in the R Markdown hand-in. Write your reasoning, R code, numeric answer, and biological interpretation in the matching section of the .Rmd template, then knit to HTML and upload to Canvas.
Problem 6 · nested random effects · overdispersion

Nested counts and the overdispersion check

An agency flies aerial surveys that produce counts nested three deep: 4 management units × 6 transects per unit × 3 flights per transect = 72 transect-flights, each a single count. Counts vary among units, among transects within units, and among flights within transects.

  1. Diagram the nesting, then write the equation for a Poisson GLMM with random intercepts at each level. With one count per flight, what happens to the flight-level term, and what is the standard trick for using it anyway?
  2. In lme4 syntax, what is the difference between (1 | unit/transect) and (1 | unit) + (1 | transect)? If transect IDs are reused across units (transect "1" exists in every unit but they are different transects), which do you use?
  3. For the Poisson GLMM, how do you check for overdispersion? Write the Pearson-dispersion calculation and state the threshold that should worry you.
  4. If the data are overdispersed, name two concrete fixes and say what each does.
Your answer goes in the R Markdown hand-in. Write your reasoning, R code, numeric answer, and biological interpretation in the matching section of the .Rmd template, then knit to HTML and upload to Canvas.

Part 2 · Model selection (afternoon · 20 pts)

Problem 7 · simulation · Type I error of AIC/AICc/BIC

How often does each criterion pick noise as "best"?

Generate a response that is completely unrelated to its predictors, fit every subset with dredge(), and record how often the top model retains at least one noise variable under each criterion.

Code
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))
  1. Start from the walkthrough loop. You built this simulation in the afternoon walkthrough and found roughly p 0.16, AIC 0.45, AICc 0.39, BIC 0.16. Bring that loop across. There is nothing new to discover in re-running it, and the rest of this problem extends it rather than repeating it.
  2. Now apply the rule the lecture warns about. Taking the AICc-best model is one decision rule; a stricter one is only accept the winner if it beats the runner-up by more than 2 AICc units, and otherwise decline to choose. Modify the loop to record both whether the top model contains a predictor and the gap dd$AICc[2] - dd$AICc[1]:
    dd  <- dredge(lm(y ~ ., data=d), rank="AICc")
    noise_top[i] <- sum(!is.na(dd[1, 2:4]))
    gap[i]       <- dd$AICc[2] - dd$AICc[1]
    Report three numbers: how often the winner is more than 2 units clear; among those runs, how often it still contains a noise predictor; and the overall fraction of runs in which the strict rule keeps a noise predictor.
  3. The strict rule cuts the overall false-positive rate a long way. Explain how it does that. Look at how often it declines to pick anything at all, and at the noise rate conditional on a clear winner existing. Is the rule choosing better models, or mostly refusing to choose? What does the median gap between best and runner-up tell you about how often a clear winner exists when nothing is real?
  4. Is AICc uniquely bad, or is this just Type I error? Every selection rule keeps noise sometimes, so the 2-unit rule only means something next to a benchmark. Repeat the gap calculation for BIC (dredge(reg, rank="BIC"), gap db$BIC[2] - db$BIC[1]) and record the same three numbers, plus the plain p < 0.05 rate you already have. Fill in this table:
                          picks noise   winner >2 clear   noise GIVEN clear
    p < 0.05 (any of 3)      ____%            --                 --
    AICc best                ____%          ____%              ____%
    BIC  best                ____%          ____%              ____%
    
    median gap to runner-up:  AICc ____    BIC ____
  5. Two things in that table need explaining. (i) BIC declares a clear winner far more often than AICc does. Work out why from the size of the two penalties at $n = 50$, and check your reasoning against the median gaps. (ii) BIC is wrong less often when it commits, yet its overall rate of "confident and wrong" is higher than AICc's. Explain how both can be true at once, and say which of the two numbers you would want to know before trusting a published model-selection result.
Your answer goes in the R Markdown hand-in. Write your reasoning, R code, numeric answer, and biological interpretation in the matching section of the .Rmd template, then knit to HTML and upload to Canvas.
Problem 8 · simulation · BIC vs AIC on weak effects

When BIC misses a weak-but-real effect

Three predictors have known effect sizes, one strong, one modest, one weak. Ask which criterion keeps the weak one.

Code
library(MuMIn); options(na.action="na.fail")
set.seed(11); n <- 60
strong <- runif(n); modest <- runif(n); weak <- runif(n)
y <- 0.8*strong - 0.4*modest + 0.1*weak + rnorm(n, 0, 0.5)
d <- data.frame(y, strong, modest, weak)
m <- lm(y ~ strong + modest + weak, data=d)
dredge(m, rank="AIC"); dredge(m, rank="AICc"); dredge(m, rank="BIC")
  1. Run the single simulation. Which predictors does each criterion retain in its top model?
  2. Wrap it in a 500-rep loop (resampling y and the predictors each time) and report the proportion of reps in which each criterion retains weak. Do the same for modest and strong.
  3. Which criterion would you use if the science question is "is the weak predictor worth studying further?", and which if it is "does the weak signal generalize out of sample?" Justify each choice.
  4. Now change the sample size. Run the loop from (b) again with n = 500, and also rerun the pure-noise loop from Problem 7 at n = 500. Fill in this table with the rate at which each criterion keeps the weak-but-real predictor (its power, one minus the Type II error) and the rate at which it keeps at least one pure-noise predictor (its Type I error):
                    keeps weak (real)      keeps noise (Type I)
                    n = 60    n = 500      n = 50    n = 500
    AIC             ____      ____         ____      ____
    AICc            ____      ____         ____      ____
    BIC             ____      ____         ____      ____
    One criterion's Type I error barely moves with $n$ and one collapses. Explain both from the size of the penalties, $2$ against $\ln n$, and then say what that means for a criterion's ability to find a weak effect as data accumulate. Which of the two behaviours would you want from a criterion used for inference, and which for prediction?
Your answer goes in the R Markdown hand-in. Write your reasoning, R code, numeric answer, and biological interpretation in the matching section of the .Rmd template, then knit to HTML and upload to Canvas.
Problem 9 · real data · AIC vs cross-validation

AIC vs LOOCV on the trophic-position data

Return to qcbs_w6_data.csv from Problem 4, but now treat species and lake as ordinary fixed factors so we can rank candidate fixed-effect models by both an information criterion and cross-validation. The question is predictive. Which set of predictors best forecasts a fish's trophic position?

Setup & candidate models
library(boot); library(AICcmodavg)
dat <- read.csv("data/qcbs_w6_data.csv")
dat$Fish_Species <- as.factor(dat$Fish_Species)
dat$Lake         <- as.factor(dat$Lake)
dat$Z_Length     <- scale(dat$Fish_Length)[,1]

forms <- list(
 null    = Trophic_Pos ~ 1,
 length  = Trophic_Pos ~ Z_Length,
 len_sp  = Trophic_Pos ~ Z_Length + Fish_Species,
 len_lk  = Trophic_Pos ~ Z_Length + Lake,
 full    = Trophic_Pos ~ Z_Length + Fish_Species + Lake,
 interact= Trophic_Pos ~ Z_Length * Fish_Species + Lake)

# LOOCV MSE (delta[1]) and AICc for each candidate
cv   <- sapply(forms, function(f) cv.glm(dat, glm(f, data=dat))$delta[1])
aicc <- sapply(forms, function(f) AICc(glm(f, data=dat)))
data.frame(cv_MSE = round(cv, 4), AICc = round(aicc, 1))
  1. Report the table. Which model minimizes AICc, and which minimizes the LOOCV MSE? Do they agree?
  2. Compute $\Delta$AICc for every model and the Akaike weights. Is there a single clearly-best model, or a cluster within $\Delta\text{AICc} < 2$?
  3. Compare the best model's LOOCV MSE to var(dat$Trophic_Pos). Roughly what fraction of the response variance does the model's prediction error remove? Is the "best" model actually good in absolute terms, or just best of a weak field?
  4. If AICc and LOOCV disagreed, which would you trust for a pure prediction task, and why? State one reason AICc could mislead on a dataset this size.
Your answer goes in the R Markdown hand-in. Write your reasoning, R code, numeric answer, and biological interpretation in the matching section of the .Rmd template, then knit to HTML and upload to Canvas.
Problem 10 · multimodel inference · the "right question" trap

Model averaging, evidence ratios, and asking the right question

A size-at-age analysis is fit with four competing candidate models. M1 has a fixed temperature effect, M2 a fixed regional effect, M3 both, and M0 is intercept-only. The AICc table:

Model   K   AICc     deltaAICc   weight
M3      5   1240.0   0.0         0.45
M1      4   1240.6   0.6         0.33
M2      4   1241.9   1.9         0.17
M0      3   1244.7   4.7         0.04
  1. Write the Akaike-weight formula. Confirm the weights in the table from the $\Delta$AICc column, and list which models are "competitive" by the $\Delta\text{AICc} < 2$ rule.
  2. Why can model-averaging coefficients mislead when the candidate models contain different, correlated predictors? Why is model-averaging predictions usually safer?
  3. The biologist's actual question is "does temperature affect size-at-age?" Re-frame the table to answer that question directly. Compute the summed weight of models containing temperature vs those without, and interpret it as an evidence ratio rather than "which model wins."
  4. If the temperature coefficient in M3 is $\hat\beta_T = 0.03$ with SE 0.02, what does that say about the practical importance of temperature, regardless of which model "wins"? What single number would you also report so a reader can judge how much of the inference rides on one model?
Your answer goes in the R Markdown hand-in. Write your reasoning, R code, numeric answer, and biological interpretation in the matching section of the .Rmd template, then knit to HTML and upload to Canvas.
← Back to lab Plain-language summary →