Adam Dennett - a.dennett@ucl.ac.uk
Week GLM
CASA0007 Quantitative Methods
In week 1 we spent a long time on types of data, and on the distributions that go with them.
| Data type | Example from our data | Distribution |
|---|---|---|
| Real-valued | Attainment 8 | Normal |
| Binary | Is this school single-sex? | Bernoulli / Binomial |
| Count | How many pupils on free school meals? | Poisson |
| Count, overdispersed | … when the variance exceeds the mean | Negative binomial |
| Ordinal | Ofsted rating | (no single answer) |
We then spent three weeks modelling only the first row!
| If your outcome is… | …its distribution is | …the model is |
|---|---|---|
| A continuous number | Normal | OLS - weeks 5, 6, 7 |
| A yes/no | Binomial | Logistic regression |
| A proportion out of a known total | Binomial | Logistic regression |
| An ordered category | - | Ordinal logistic |
| An unordered category | - | Multinomial logistic |
| A count | Poisson | Poisson regression |
| A count that is too variable | Negative binomial | Negative binomial regression |
This is not seven new methods. It is one method, with a slot you fill differently depending on what you are trying to explain.
Every GLM has exactly three pieces. You already know the middle one.
OLS is just the GLM where the distribution is Normal and the link function does nothing at all.
With GLMs there is an \(E\) in most of the equations. \(E\) is for expectation, and \(E[y_i]\) reads “the expected value of y for school i”.
Ordinary regression, exactly as we wrote it in Vol 1:
\[y_i = \beta_0 + \beta_1x_i + \epsilon_i\]
The errors average out to zero. So take the average of both sides, and the error term disappears:
\[E[y_i] = \beta_0 + \beta_1x_i\]
That is the line you have been drawing through scatter plots since week 5. - A regression line was never an exact school prediction — It is a prediction of what the average school like it does - this is the expected value
So \(\log(E[y_i])\) is not anything new or different. Just more formalised in the GLM equation.
Every regression we have fitted works the same way: take each predictor, multiply it by a number, and add the results up.
\[y = \beta_0 + \beta_1x_1 + \beta_2x_2 + \dots\]
| Outcome | Its natural range | Link stretches it with | To get back, apply |
|---|---|---|---|
| A continuous number | \(-\infty\) to \(+\infty\) | nothing needed | nothing |
| A probability | 0 to 1 | \(\log\left(\frac{p}{1-p}\right)\) | the logistic curve |
| A count | 0 to \(+\infty\) | \(\log\) | \(\exp\) |
Back in Vol 1, when a relationship came out curved, we took logs of the variables and fitted OLS to the transformed numbers. That also puts a log in the model. It is not the same thing, and the difference is worth ten minutes.
What we did in Vol 1 - log(lm)
\[\log(y_i) = \beta_0 + \beta_1x_i + \epsilon_i\]
Change the data, then model it.
What a GLM does
\[\log\big(E[y_i]\big) = \beta_0 + \beta_1x_i\]
Model the data, and put the log on the model.
Read those two third points again. Average of the logs versus log of the average. They sound like the same sentence in a different order.
It comes down to which one you do first. Take three schools, with 1, 10 and 100 disadvantaged pupils.
lm - Log first, then average
(what transforming the data does)
GLM - Average first, then log
(what a log link does)
Same three numbers. 10 against 37. Nothing has gone wrong — the order of operations simply matters, and \(\log\) is the reason why.
The number of disadvantaged pupils across our 3,168 schools:
| What you do | Result | |
|---|---|---|
| LM - Log first, then average | log each school, average, undo the log | 38.2 pupils |
| GLM - Average first, then log | add them up and divide | 46.3 pupils |
Same 3,168 schools, same predictor, both models with a log in them — and two different curves. For a cohort of 50 the left-hand route predicts about 23% fewer disadvantaged pupils than the right-hand one. The two converge as schools get bigger, which is exactly what you would expect: the more skewed the slice of data, the wider the gap.
For counts, yes/no outcomes and proportions this is not a matter of taste. Logging is the wrong tool and a GLM is the right one.
For a continuous, strictly positive outcome both are defensible, and they answer slightly different questions. Four things to ask:
Logging assumes the error is multiplicative — roughly constant spread on the log scale.
A school is 20% above expectation, whatever its size.
A log-link GLM assumes the variance grows with the mean.
Bigger schools vary more in absolute terms — which is what counts actually do.
Plot the residuals against the fitted values. If the spread fans out on the raw scale but is flat once logged, logging is honest. If the variance tracks the mean, you want Poisson. This is a question you can answer with a plot, not a preference.
The published rule of thumb. O’Hara & Kotze simulated count data and compared the two approaches. Transformations performed poorly except when dispersion was small and the mean counts were large; Poisson and negative binomial models performed well throughout.
Which is exactly what the previous slide showed — 23% apart at a cohort of 50, converging to almost nothing by 400. Large counts, small gap. Small counts, big gap.
O’Hara, R.B. & Kotze, D.J. (2010) Do not log-transform count data. Methods in Ecology and Evolution, 1(2), 118–122. doi:10.1111/j.2041-210X.2010.00021.x
Even if you are happy with the geometric mean, transforming only works if every value can be logged. Often they cannot.
A GLM never asks you to touch the data. The zeros stay zeros, the 0s and 1s stay 0s and 1s, and the link function does its work on the average instead — where there is nothing awkward to divide by and nothing to drop.
In Vol 1 we did not just log the outcome. We logged the predictor too:
\[\log(y_i) = \beta_0 + \beta_1 \log(x_i) + \epsilon_i\]
A Poisson GLM looks different. The log sits on the left-hand side only:
\[\log\big(E[y_i]\big) = \beta_0 + \beta_1 x_i\]
The link is a statement about the outcome’s type. Counts cannot go negative, so we use a log link. That is all it says — and in particular it says nothing whatsoever about the predictors.
You are still free to log them, or not, exactly as you always were. That choice is untouched by the link, and we come to it next.
It is just a separate decision, made for the same old reason — the relationship is curved — and completely independent of the link.
| What goes in | How you read it | |
|---|---|---|
n_below ~ mean_abs |
absence, raw | one percentage point more absence multiplies the rate by 1.25 |
n_below ~ log(mean_abs) |
absence, logged | doubling absence multiplies the rate by 4.75 |
Both are Poisson models with a log link. Both leave the outcome untouched. They differ only in whether the predictor enters raw or logged — and that changes the sentence you write, from per unit to per doubling.
Here the logged version fits slightly better (AIC 756 against 761), so it is a real choice, not a formality.
AIC is a score for comparing models fitted to the same data — lower is better. We take it apart properly later today.
One predictor we always log. Later today we add offset(log(n_schools)) to account for how many schools an LA has. That is a logged predictor with its coefficient fixed at 1 — and it is what turns a model of counts into a model of rates.
Tempting, and a very common habit — but not because it is skewed.
Regression makes no assumption whatsoever about the distribution of your predictors. The assumptions are about the errors. A skewed x breaks nothing and is not, on its own, a problem to be fixed.
Three things that are real reasons to log a predictor:
| Predictor | Skew | Does logging help? |
|---|---|---|
| Pupils in the cohort | 0.37 | Yes, clearly |
| % disadvantaged | 0.79 | Yes, clearly |
| % English as an additional language | 1.59 | No - it makes it worse |
The least skewed predictor here is one where logging clearly helps. The most skewed is the one where logging actively makes the model worse.
Look at the relationship, not at the histogram of x. Skew in a predictor tells you how its values are spread out. It tells you nothing at all about whether its relationship with the outcome is straight — and that is the thing you are actually trying to fix.
Schools split into 18 equal groups along the x-axis; each teal dot is one group’s average. Dashed is the straight line the model would fit. Where the dots wander away from the dashed line, the relationship is curved.
Plot your outcome against the predictor twice — once raw, once logged — and keep whichever is straighter.
Put the outcome on a log axis while you do it, because that is the scale a log-link model actually works on. Straight on that plot means straight where the model cares.
On the previous slide, look at the top row: raw, the dots curve away from the line; logged, they drop neatly onto it. That is a predictor worth logging, and you can see it before fitting anything.
The bottom row does not improve. Logging the EAL figures just moves the scatter around — which is exactly why the AIC got worse when we logged it.
Three habits that will serve you all term
3,170 schools with complete data. Note immediately how lopsided this is - we will come back to that, because it causes more trouble than anything else today.
Call:
lm(formula = below_good ~ P8MEA, data = model_data)
Residuals:
Min 1Q Median 3Q Max
-1.05109 -0.19520 -0.10193 0.03523 1.13124
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.145824 0.005812 25.09 <2e-16 ***
P8MEA -0.274324 0.011145 -24.61 <2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.3271 on 3168 degrees of freedom
Multiple R-squared: 0.1606, Adjusted R-squared: 0.1603
F-statistic: 605.9 on 1 and 3168 DF, p-value: < 2.2e-16
The model runs. It produces coefficients. It produces an R². Nothing errors.
And its fitted values run from -0.504 to 1.051.
We need something that takes a straight line, which runs from \(-\infty\) to \(+\infty\), and squashes it into \([0,1]\).
\[\log\left(\frac{p}{1-p}\right) = \beta_0 + \beta_1x_1 + \beta_2x_2 + \dots\]
Worth pausing, because this trips people (including me!) up all the time.
| Probability | Odds | In words |
|---|---|---|
| 0.5 | 1.0 | Evens |
| 0.75 | 3.0 | Three to one on |
| 0.9 | 9.0 | Nine to one on |
| 0.1 | 0.11 | Nine to one against |
Probabilities are bounded above. Odds are not. That is the whole reason we work with them.
Odds describe one situation
\[\text{odds} = \frac{p}{1-p}\]
“This school’s odds of being rated below Good are 0.10”
An odds ratio compares two
\[\text{OR} = \frac{\text{odds}_A}{\text{odds}_B}\]
“…which is 0.07 times the odds of a school one Progress 8 point worse”
First, where the “one” comes from. A slope always answers the same question, in every model you have ever fitted:
If the predictor goes up by one unit, what happens to the outcome?
In Vol 1 that was “one more percentage point of absence costs 0.38 Attainment 8 points”. The one is not special — it is just the step size we have always quoted coefficients in.
So picture two schools, identical in every respect, except the second has one more unit of \(x\) — one more percentage point of absence, say.
Our model says the log-odds are a straight line:
\[\log(\text{odds}) = \beta_0 + \beta_1 x\]
| Predictor | Its log-odds | |
|---|---|---|
| School A | \(x\) | \(\beta_0 + \beta_1x\) |
| School B | \(x+1\) | \(\beta_0 + \beta_1x + \beta_1\) |
Subtract one from the other, and everything cancels except \(\beta_1\):
\[\log(\text{odds}_B) - \log(\text{odds}_A) = \beta_1\]
So the coefficient is a difference of two log-odds. Not a difference in probability, and not a difference in odds — a difference in logged odds.
We have a difference of logs. There is a rule from school algebra for exactly that:
\[\log(M) - \log(N) = \log\!\left(\frac{M}{N}\right)\]
Deliberately not A and B — those are taken. \(M\) and \(N\) are just placeholders for “whatever you are subtracting”.
Ours was \(\log(\text{odds}_B) - \log(\text{odds}_A)\), so \(M\) is School B’s odds and \(N\) is School A’s:
\[\beta_1 = \log(\text{odds}_B) - \log(\text{odds}_A) = \log\!\left(\frac{\text{odds}_B}{\text{odds}_A}\right)\]
Now undo the log on both sides — exponentiate:
\[e^{\beta_1} = \frac{\text{odds}_B}{\text{odds}_A}\]
That is the whole thing. A ratio of two odds — because subtracting logs is dividing, and the coefficient was a difference of logs all along. Nothing was smuggled in: just a one-unit step, and one rule about logarithms.
That curve we drew a few slides ago had a model behind it. Here it is — the same single predictor we gave lm(), fitted properly:
(Intercept) P8MEA
-2.323537 -2.698673
Two numbers. That is the entire model, and it says:
\[\log(\text{odds}) = -2.32 + (-2.70 \times \text{Progress 8})\]
Take a school with a Progress 8 of 0 and turn the handle. Three steps, and each one undoes a bit of the link function:
So a school on exactly average progress has about a 9% chance of being rated below Good.
Every row below is those same three steps, done at a different Progress 8 score.
| Progress 8 | Probability | Odds | Odds ÷ the row above |
|---|---|---|---|
| -1 | 0.593 | 1.4552 | - |
| 0 | 0.089 | 0.0979 | 0.067 |
| 1 | 0.007 | 0.0066 | 0.067 |
| 2 | 0.000 | 0.0004 | 0.067 |
Check the Progress 8 = 0 row against the slide before: probability 0.089, odds 0.0979. The last column simply divides each row’s odds by the one above it.
The coefficient on Progress 8 is -2.70, and \(e^{-2.70}\) = 0.067.
That is the last column, every time. One coefficient, one odds ratio, valid wherever you start from. Now look at the probabilities - they fall 0.59 → 0.09 → 0.007, doing nothing so tidy. Which is exactly why “the probability falls by X” is never a safe reading of a logistic coefficient.
Same formula interface you have used for three weeks. Two differences: glm() not lm(), and a family argument.
| Term | Coefficient | Std. error | p |
|---|---|---|---|
| (Intercept) | -5.087 | 1.029 | <0.001 |
| P8MEA | -2.253 | 0.225 | <0.001 |
| PTFSM6CLA1A | -0.019 | 0.006 | 0.002 |
| PERCTOT | 0.072 | 0.080 | 0.369 |
| PPERSABS10 | 0.048 | 0.025 | 0.056 |
| log(TPUP) | 0.265 | 0.176 | 0.131 |
| PTPRIORHI | -0.006 | 0.010 | 0.571 |
| MINORGROUPMaintained school | -0.041 | 0.170 | 0.812 |
One extra Progress 8 point multiplies the odds of being rated below Good by about 0.11 - that is, it cuts them by roughly 89%.
Anything whose interval crosses 1 is doing nothing detectable. Note how much work Progress 8 is doing compared with everything else.
For three weeks we judged models with R² — the share of the variation in the outcome the model managed to explain.
That worked because the outcome was a number, with variation in it to explain. Ours is a yes or no. There is no spread to account for, and R² as you know it simply does not exist here.
So we ask two questions instead, and they are genuinely different:
A model can do respectably on one and badly on the other. We take them in turn.
Every school in the data either was or was not rated below Good. The model assigns each one a probability. Likelihood asks the obvious question:
Given these coefficients, how probable was the data we actually saw?
Fitting the model is choosing the coefficients that make this number as large as possible — maximum likelihood. We report its log, because multiplying 2,219 probabilities together gives a number too small for a computer to hold.
For our model: log-likelihood = -717.2. Always negative; closer to zero is better.
A log-likelihood on its own is hard to read. Deviance rescales it into something more like an error score — how far this model sits from one that predicted every school perfectly.
\[\text{deviance} = -2 \times \text{log-likelihood}\]
| What it is | ||
|---|---|---|
| Null deviance | 1883.4 | with no predictors at all — just the overall rate |
| Residual deviance | 1434.3 | with our seven predictors in |
Lower is better, and the drop — 449 — is what the predictors bought us. This is the direct equivalent of the sum-of-squares drop you used to read off an OLS table.
There is a problem with judging a model on deviance alone: adding any predictor, however useless, will always lower it slightly. Left to itself, deviance always says “more variables”.
So we charge for them:
\[\text{AIC} = \text{deviance} + 2k \quad\text{where } k = \text{number of coefficients}\]
For our model: 1434.3 + 2 × 8 = 1450.3. A predictor only improves the AIC if it reduces the deviance by more than the 2 points it costs.
AIC has no meaning on its own. 1450 is neither good nor bad — it is only useful for comparing models fitted to the same data. Lower wins. That is exactly how we used it earlier to choose between a raw and a logged predictor.
People badly want an R², so several substitutes exist. The two you will meet in software output:
Cox & Snell — built from the likelihood ratio between your model and the null model. For us: 0.183.
That looks dismal — until you learn its catch. Cox & Snell cannot reach 1. With a binary outcome its ceiling here is 0.572, so 0.183 is really 0.183 out of a possible 0.572.
Nagelkerke fixes precisely that, by dividing by the ceiling:
\[R^2_{\text{Nagelkerke}} = \frac{0.183}{0.572} = \mathbf{0.320}\]
Now it can reach 1, and it reads much more like the R² you are used to.
Report them if the journal or the marker expects them — but know what you are saying.
Treat a pseudo-R² as a rough indication that the predictors are doing something, and nothing more. If you want to know whether the model is actually any use, ask the second question — the one we come to next.
Everything so far gives one number for the whole model. Hosmer–Lemeshow asks something more specific: is the model well calibrated across the whole range of risk, or only in parts of it?
Ours: \(\chi^2\) = 11.3 on 8 df, p = 0.186.
Read the direction carefully — it is the opposite of most tests. A small p-value means the model fits badly. Ours is 0.19, so there is no evidence of poor fit.
And “no evidence of poor fit” is not the same as “good fit”. The test is known to be sensitive to how many groups you choose, and to have little power on small samples. It is a flag worth checking, not a certificate.
The obvious way to answer that is to run the model over our schools and count how often it got the answer right.
The problem: it has already seen those schools. The coefficients were chosen to fit them as closely as possible. Scoring a model on the data it was fitted to is revising with the exam paper in front of you — you will do well, and it tells you nothing about the next paper.
2,219 schools to learn from, 951 kept back to test on. The model never sees the second group while it is being fitted, so how it does there is a fair sitting of a fresh paper.
That is what test-set accuracy means: of the 951 schools it had never met, what share did it classify correctly?
Test-set accuracy: 86.2%
Not bad! Nearly nine schools in ten classified correctly.
Now watch.
A model that makes the same prediction every single time, with no data at all, scores 85.3%. Our model beats it by 0.9 percentage points.
| Predicted below Good | Predicted Good or better | |
|---|---|---|
| Actually Below Good | 32 | 108 |
| Actually Good or better | 23 | 788 |
The 951 test schools — the ones the model never saw while it was being fitted.
Always, always compare your accuracy against the majority-class baseline. On imbalanced data, accuracy on its own is not evidence of anything.
The model does not output yes or no. It outputs a probability for every school. We turned that into a yes/no by flagging anything above 0.5 — and nothing made 0.5 the right number.
| Flag if probability above | Struggling schools caught | …and missed | False alarms |
|---|---|---|---|
| 0.50 | 32 | 108 | 23 |
| 0.30 | 57 | 83 | 75 |
| 0.20 | 91 | 49 | 134 |
| 0.10 | 121 | 19 | 316 |
Drop the threshold and you catch far more struggling schools — 32 up to 121 of the 140. But the false alarms go from 23 to 316.
There is no setting that is simply best. Which error hurts more is a policy question, and the model cannot answer it for you.
Rather than argue about one cut-off, plot all of them. Two numbers per threshold:
Each red dot is one row of the table above. Sweep the threshold from 1 down to 0 and you trace the whole curve. The dashed diagonal is what you would get by guessing at random — the further above it you sit, the more the model knows.
One curve is awkward to quote in a sentence, so we summarise it by the area under it — the AUC.
| AUC | What it means |
|---|---|
| 0.5 | the diagonal — no better than tossing a coin |
| 0.7–0.8 | useful |
| 0.9+ | very strong |
| 1.0 | perfect: every struggling school scored above every healthy one |
It also has a reading that needs no curve at all:
Pick one struggling school and one healthy school at random. AUC is the probability the model gives the struggling one the higher score.
Notice what that does not depend on: any threshold. AUC asks whether the model puts schools in the right order, which is a different and fairer question from whether it labels them correctly at one arbitrary cut-off.
Accuracy asks “did you get it right?” at one arbitrary cut-off. A better question is “do you rank schools sensibly?”
AUC = 0.818 - pick a below-Good school and a Good-or-better school at random, and the model gives the below-Good one a higher score 82% of the time. That is genuinely useful. The problem was never the model - it was the 0.5 threshold, which is a choice, not a law.
Drop the threshold and you catch more struggling schools, but more of your flags are false alarms. Which error is worse is a policy question, not a statistical one - and that is the right way round.
| Model | Accuracy | Baseline | AUC | Caught at p > 0.5 |
|---|---|---|---|---|
| Below Good vs Good+ | 86.2% | 85.3% | 0.818 | 32 of 140 |
| Outstanding vs rest | 88.3% | 85.6% | 0.896 | 52 of 137 |
Progress 8 is by far the strongest predictor in both models. So what have we actually built?
And a second problem: inspection dates in this file run from 2011 to 2024, median 2022. Some of these ratings were handed out a decade before the results we are using to “predict” them.
Ask these questions of your own models. They matter more than another decimal place of AUC.
Ordinal logistic regression uses the order without assuming the spacing.
We imagine a single continuous scale we cannot observe. The predictors move a school along it, and the cut points decide which rating it comes out as. Three cut points for four categories - and the model estimates them from the data rather than assuming them.
| Term | Value | t | p |
|---|---|---|---|
| P8MEA | 2.748 | 16.85 | <0.001 |
| PTFSM6CLA1A | 0.019 | 4.24 | <0.001 |
| PERCTOT | -0.048 | -0.74 | 0.459 |
| PPERSABS10 | -0.041 | -2.18 | 0.029 |
| log(TPUP) | 0.045 | 0.35 | 0.73 |
| PTPRIORHI | 0.013 | 3.44 | <0.001 |
| MINORGROUPMaintained school | -0.131 | -1.04 | 0.3 |
| Inadequate|Requires improvement | -5.572 | -7.11 | <0.001 |
| Requires improvement|Good | -3.136 | -4.10 | <0.001 |
| Good|Outstanding | 2.042 | 2.67 | 0.008 |
The last three rows are the cut points, not predictors. Everything above them reads like a logistic model: positive means more likely to be rated higher.
| Inadequate | Requires improvement | Good | Outstanding | |
|---|---|---|---|---|
| Inadequate | 0 | 5 | 13 | 0 |
| Requires improvement | 3 | 21 | 98 | 0 |
| Good | 2 | 25 | 628 | 19 |
| Outstanding | 0 | 0 | 92 | 45 |
Roughly, yes. Precisely, no. And the rare categories, not at all.
That is an honest, useful answer - and a far better one than a single accuracy figure would have given you.
Let’s fit it to Ofsted anyway, deliberately ignoring the order, to see what ignoring the order costs us.
| Model | Parameters | Test accuracy | AIC |
|---|---|---|---|
| Ordinal (proportional odds) | 10 | 73.0% | 2921 |
| Multinomial | 24 | 73.7% | 2877 |
Use the structure in your data when you have it. The ordinal model gets almost the same performance from a third of the coefficients, and you can actually interpret it.
Let’s change the question and move up a level.
How many below-Good schools does each local authority have?
Discrete, non-negative, right-skewed, with a pile-up at the low end - 24 LAs have no below-Good schools at all. This is a Poisson-shaped problem, exactly as week 1 described.
| Local authority | Secondary schools | Rated below Good | As a share |
|---|---|---|---|
| Lancashire | 78 | 22 | 28% |
| Bury | 13 | 6 | 46% |
On the raw count, Lancashire looks nearly four times worse. On the share, Bury is the one in trouble.
A count on its own tells you very little, because it depends on how many chances there were to begin with. Lancashire has six times as many schools, so it would take more below-Good ones even if nothing were wrong.
The obvious move is to model the share — n_below / n_schools — and be done with it. Two reasons not to:
22/79 = 0.28 is not a count of anything. We would be using a distribution for something it does not describeAn offset gets us both: the outcome stays a genuine count, so Poisson still applies and the sample sizes still count for something — but the model does the dividing internally.
Three lines of algebra, and nothing clever happens in any of them.
1. What we actually want to model — a rate, not a count:
\[\log\left(\frac{\text{expected count}}{\text{number of schools}}\right) = \beta_0 + \beta_1x\]
2. The log of a ratio is a difference of logs — ordinary school algebra:
\[\log(\text{expected count}) - \log(\text{number of schools}) = \beta_0 + \beta_1x\]
3. Move that term across to the other side:
\[\log(\text{expected count}) = \beta_0 + \beta_1x + \log(\text{number of schools})\]
That final term — \(\log(\text{number of schools})\) — is the offset.
So an offset is just a division, rewritten as an addition so it can sit inside a model that works on the log scale. In R that is offset(log(n_schools)).
Look at line 3 again. Every other term on the right gets a \(\beta\) in front of it that the model chooses. The offset does not — it is stuck there with a coefficient of exactly 1, because that is how it arrived.
In plain words, we are telling the model something rather than asking it:
Twice as many schools, twice as many below-Good ones expected, all else being equal.
That is a claim about arithmetic, not about education policy, so we spend no parameter finding it out.
Is that a fair thing to assume? Put log(n_schools) in as an ordinary predictor and let the model estimate it instead. It comes back with 0.95, with a 95% interval of 0.82 to 1.09 — 1 sits comfortably inside it. The assumption holds, and fixing it saves us a parameter.
Always worth checking. If that interval had excluded 1, the offset would have been the wrong tool.
| Term | Coefficient | Rate ratio | p |
|---|---|---|---|
| (Intercept) | -4.4903 | 0.011 | <0.001 |
| Mean % disadvantaged | -0.0017 | 0.998 | 0.751 |
| Mean % absence | 0.2834 | 1.328 | <0.001 |
The link function here is \(\log\), so exponentiating gives a rate ratio. And note the result: once average absence is in the model, average disadvantage adds nothing detectable - a confounding story of exactly the kind we met in week 6.
The Poisson distribution assumes something quite strong: that the variance equals the mean. Real data often disagrees.
A value near 1 means the assumption holds. Much above 1 means overdispersion - the data are more variable than Poisson allows, your standard errors are too small, and you will think results are significant when they are not.
Here we get 1.31, which is mild. So Poisson is adequate - but we should check rather than assume.
| Model | AIC | SE on absence |
|---|---|---|
| Poisson | 577 | 0.0485 |
| Negative binomial | 575 | 0.0528 |
Fit the Poisson, check the dispersion, escalate only if you need to.
Given their intake, some LAs have far more struggling schools than expected and some far fewer. The residuals of a count model are not a diagnostic afterthought here - they are the finding.
Back down to school level, and to a file we have not touched yet: what happens to pupils after Year 11?
| Value | |
|---|---|
| Schools | 3,081 |
| Median cohort | 175 |
| Median % sustaining a destination | 94.4% |
| Schools at exactly 100% | 48 (1.6%) |
Note the cbind() - we hand the model successes and failures, not a proportion, so it knows a school of 30 carries less weight than a school of 300.
Every 10 percentage points more disadvantage is associated with a 23% fall in the odds of a pupil sustaining a destination.
They agree almost exactly through the middle and diverge at the top end - the schools policy cares about most. Here OLS is not obviously broken. It is quietly wrong at the edges, and nothing in its output tells you so.
| Model | Dispersion | Verdict |
|---|---|---|
| LA below-Good counts (Poisson) | 1.31 | Mild - Poisson is fine |
| Destinations (binomial) | 2.72 | Overdispersed - use quasibinomial |
family = quasibinomial widens the standard errors by about 60% - the coefficients are unchanged, but our confidence in them was overstated| Outcome | family = |
Link | Interpret coefficients as |
|---|---|---|---|
| Continuous | gaussian |
identity | Units of y per unit of x |
| Yes / no | binomial |
logit | Odds ratios |
| x out of n | binomial |
logit | Odds ratios |
| Ordered categories | MASS::polr() |
logit | Odds of being in a higher category |
| Unordered categories | nnet::multinom() |
logit | Odds vs a reference category |
| Count | poisson |
log | Rate ratios |
| Overdispersed count | MASS::glm.nb() |
log | Rate ratios |
One framework. Change the family, change the link, and everything you learned about building and interpreting a linear model still applies.
Still true
Different now
glmer() - the intersection of this week and last week: a GLM with random effects, for grouped non-normal dataYou now have the two big extensions to OLS: last week we relaxed independence, this week we relaxed normality. Almost everything else is a combination of the two.
© CASA | ucl.ac.uk/bartlett/casa