Non-linear models: interactive
PLS 206 — Applied Multivariate Modeling
Three explorers for Week 4. They run in your browser with no R and no download, so they work on a phone too. Tick “Show R code” in any of them to get code that reproduces the current view in RStudio. The first two use the growth-chamber seedlings from Monday (seedling_temp.csv, standard variety); the third uses the soil collars (soil_season.csv).
Cheat sheet: reading summary() of a GAM
The numbers are from gam(mass_mg ~ s(temp), data = std, method = "REML") on the 150 standard-variety pots.
line of summary(m) |
here | what it means |
|---|---|---|
Family: gaussian, Link function: identity |
the GLM part: the distribution of \(y\) and the link, exactly as in Week 3 | |
(Intercept) |
42.68 | the mean of \(y\): every smooth is centred to average zero, so the intercept is the overall mean shoot mass |
edf |
6.87 | effective degrees of freedom: how many parameters the curve is worth after the penalty; 1 = a straight line |
Ref.df |
7.98 | reference degrees of freedom used for the test; not something to interpret |
F, p-value |
192.4, < 2e-16 | an approximate test of “is the smooth flat?” (no effect of temperature at all) |
R-sq.(adj) |
0.912 | adjusted R², as in lm() |
Deviance explained |
91.6% | the share of the null deviance the model explains (for a Normal GAM, close to R²) |
-REML |
450.4 | the score REML minimised to choose λ; only useful for comparing fits of the same data |
Scale est. |
21.26 | the residual variance \(\hat\sigma^2\) (here in mg²; its square root, 4.6 mg, is the residual SD) |
n |
150 | number of observations |
Is k big enough? k is a ceiling on wiggliness, not the wiggliness: the penalty decides how much of it is used.
- Start generous (the default
k = 10is usually fine for one predictor) and rungam.check(m)ork.check(m). - Worry only if the
k-indexis below 1 with a small p-value andedfis close tok'(that is, k − 1). - Then double k and refit. If the curve barely changes, you were fine. Here
k = 10passes (k-index 0.95, p well above 0.05; the p-value comes from a random shuffle, so it moves a little from run to run);k = 4fails (k-index 0.79, p = 0.0025, edf 2.99 of a possible 3).
Bumps, weights and the penalty
A spline is k bumps, each given a weight, added up. The thin coloured curves are the bumps after weighting; the thick blue curve is their sum, which is the fitted curve. The penalty λ is the price of a wiggle: move it and watch the weights shrink until the curve is a straight line. Switch “Who sets the penalty λ?” to REML to let the data choose, as gam(..., method = "REML") does, and then change k: once k is generous, the curve barely moves.
The edf readout is the trace of the hat matrix minus one (the intercept is counted separately, as in mgcv’s summary). The small plot underneath shows edf for every λ, with the current λ in red. The bumps here are P-splines (mgcv’s bs = "ps"), so the numbers differ a little from the default s(temp) in the slides, which uses a different set of bumps.
Global polynomials, local splines
Both models are lm() with extra columns. On the left the columns are powers of temperature, poly(temp, degree, raw = TRUE); on the right they are spline bumps, bs(temp, df). The bottom panels show those columns: every power of temperature is non-zero across the whole range, while each spline bump only lives in one neighbourhood. That difference shows up in two places. Past the edge of the data (the shaded band is where the pots are) a high-degree polynomial swings off to absurd values. And if you pick 30 pots and nudge the coldest one, the polynomial changes at the hot end too, while the spline only changes near the pot you moved. (Past the data, bs() carries on along its last cubic piece, so it drifts too, just far less; a natural spline, ns(), carries on as a straight line instead.)
The faint dashed line is the fit before the nudge.
Cycles: a curve that meets itself
Day of year goes round in a circle: 31 December sits next to 1 January. An ordinary spline does not know that, so its two ends are free to disagree. A cyclic spline uses bumps that wrap from December into January, so the fitted curve always joins up. “Wrap the year” repeats the data on either side of the year (faint points) so you can see the seam. λ is chosen by REML for both fits. These are cyclic P-splines (bs = "cp"); the lecture uses bs = "cc", which works the same way with a slightly different set of bumps. The model here ignores the eight collars; the lecture adds them with s(collar, bs = "re").
λ is chosen by REML for both.