Counts are not normal, proportions live in \([0,1]\), presences are binary. The Gaussian linear model treats all of them as if they were continuous and unbounded, and fails in predictable ways: confidence intervals that include negative richness, misspecified variance, fan-shaped residuals.
The GLM fixes this with two choices: the distribution of the response and the link function connecting the mean to the linear predictor.
The AIC drops by about 9, so hydro earns its place. The simulation added 0.22 to the log mean of permanent ponds; the model estimates −0.19 for temporary ones, the same effect seen from the other side.
TipInterpreting coefficients on the log scale
A coefficient \(\beta\) under a log link means that a one-unit increase in the predictor multiplies the mean by \(e^\beta\). For canopy:
exp(coef(g1)[3]), (exp(coef(g1)[3]) -1) *100
(0.9885114593513831, -1.148854064861693)
That is, each additional percentage point of canopy reduces expected richness by about 1%.
NoteYour turn 9.2 — Temporary ponds, in plain numbers
Using the model from 9.1, by what factor does expected richness change in a temporary pond compared with a permanent one, all else equal? Pass that factor to check("9.2", ...).
TipHint
The hydro: temporary coefficient is the fifth. Under a log link, a coefficient \(\beta\) multiplies the mean by \(e^\beta\).
CautionSolution
factor_temp =exp(coef(g_hydro)[5])
0.8273060956543652
check("9.2", factor_temp)
✓ Correct!
About 0.83: temporary ponds are expected to hold about 17% fewer species than permanent ones.
9.3 Overdispersion
The Poisson assumes \(\text{Var}(Y) = \text{E}(Y)\). Ecological data rarely cooperate.
If \(\hat\phi \gg 1\), the alternatives are the negative binomial or a mixed model with an observation-level random effect.
ImportantOverdispersion is a symptom, not a diagnosis
ponds.csv was generated as a pure Poisson process — there is no extra-Poisson variance in the data-generating code. Yet \(\hat\phi \approx 1.95\). Why?
Because the generating model included a region effect that g1 omits. Unmodelled heterogeneity inflates the dispersion statistic exactly as genuine overdispersion does, and the statistic cannot tell you which one you have.
This matters practically: the reflex of reaching for a negative binomial whenever \(\hat\phi > 1.5\) can paper over a missing predictor. Check your model structure before you change your distribution. The GLMM in Section 9.6 addresses the actual cause here.
NoteYour turn 9.3 — Testing the warning
The box above claims that the overdispersion of g1 comes from a missing predictor. Test it: fit a Poisson GLM with log_area, canopy, temp_c, hydro and region, compute its dispersion statistic as in the block above, and pass it to check("9.3", ...).
TipHint
Copy the dispersion block, replacing g1 with your model. predict(g) gives the fitted means.
About 0.94: with the predictors of the generating model in place, the “overdispersion” is gone. Adding hydro alone (9.1) barely moved it; region was the missing piece.
The odds ratio for one percentage point of canopy is close to 1, which is hard to interpret. Compute the odds ratio for an increase of 10 percentage points, from g4, and pass it to check("9.4", ...).
TipHint
Ten points multiply the odds by \(e^{10\beta}\), not by \(10\,e^{\beta}\).
CautionSolution
or_10 =exp(10*coef(g4)[2])
1.1881878414800107
check("9.4", or_10)
✓ Correct!
About 1.19: each extra 10 points of canopy multiply the odds of finding the focal species by 1.19, an increase of 19%.
Figure 9.1: Predicted probability of focal-species occurrence along the canopy gradient.
NoteYour turn 9.5 — Predicting a new pond
A temporary pond has 80% canopy and water at 26 °C. According to g4, what is the probability of finding the focal species there? Pass it to check("9.5", ...).
TipHint
Build a one-row DataFrame with the columns canopy, temp_c and hydro, and pass it to predict(g4, ...), as with grid above.
The formula notation is the same, (1 | group) included. For the estimation method used and the options available, consult the MixedModels.jl documentation (Bates et al. 2026): these are details that change between versions, and not worth reproducing here from memory.
NoteYour turn 9.6 — A GLMM with hydroperiod
Add hydro to gm1 and pass the fixed effects of the new model to check("9.6", ...). Compare the hydro estimate with the one from 9.1.
TipHint
Add + hydro before the random-effect term. fixef(gm) returns the fixed effects.
This is the point where being honest is worth more than being enthusiastic. The table below is an assessment as of August 2026, made by checking the public package registries; check before concluding that something does not exist.
You need
In R
In Julia today
Zero-inflation, hurdle
glmmTMB, pscl
no mature equivalent
Beta regression
betareg, glmmTMB
no mature equivalent
Additive models (GAM)
mgcv
no mature equivalent
Simulated quantile residuals
DHARMa
none; implementable by hand
Marginal means, contrasts
emmeans
Effects.jl, partial coverage
Ordinal regression
ordinal, MASS::polr
partial coverage
9.7.1 The pragmatic escape hatch: RCall.jl
There is no shame in calling R from inside Julia when the right package only exists there. The workflow stays reproducible, and data crosses the boundary automatically.
usingRCall@rput ponds # send the DataFrame to RR"""library(mgcv)m <- gam(richness ~ s(canopy) + s(log_area) + region, family = poisson, data = ponds)summary(m)"""
NoteWhere this leaves you
For the repertoire covered by this chapter — Poisson, negative binomial, binomial, gamma, offsets, GLMMs — Julia covers what you need, and this chapter has demonstrated it with executed code. Outside it, RCall.jl is the bridge. Naming the boundary clearly serves the reader better than hiding it.
Challenges
Compute the dispersion statistic for g2. Did the negative binomial fix the overdispersion? After 9.3, would you still choose it?
Build the predicted-probability curve of Figure 9.1 for each hydroperiod at three temperatures (22, 24.5 and 27 °C). How much does temperature shift the curve?
Implement DHARMa-style quantile residuals for g1: simulate 250 datasets from the fitted model and, for each pond, compute the proportion of simulated values below the observed one. If the model is right, these proportions are uniform. Are they? Repeat for the model from 9.3.
Bates, Douglas, Phillip Alday, Dave Kleinschmidt, et al. 2026. MixedModels.jl: A Julia Package for Fitting (Statistical) Mixed-Effects Models. V. 5.8.2. Released. https://github.com/JuliaStats/MixedModels.jl.