Conjugate Bayesian linear regression: prior checks, posterior draws, and credible bands
How the normal / scaled-inverse-chi-squared prior makes Bayesian linear regression exact, how to check a prior by drawing regression curves from it, and why a credible band for the regression line shouldn't contain most of the data.
University lab From my coursework in the MSc in Statistics and Machine Learning at Linköping University, rewritten as a note to review later.
Linear regression is the one model where Bayesian inference is exact and cheap: with the right prior, the posterior has a closed form and you can sample from it directly, no MCMC. In the second Bayesian Learning lab (pair work) we fitted a quadratic curve to a year of daily temperatures this way. The useful lessons weren’t the formulas so much as how to pick a prior by looking at it, and how to read the bands you get at the end.
The model and the conjugate prior
The model is ordinary regression:
where is the -vector of responses, the design matrix (for a quadratic in time the columns are ), the coefficients and the noise variance.
The conjugate prior comes in two layers:
Here is your prior guess for the coefficients, is a precision matrix (bigger = more confident), is a prior guess for the noise variance and says how many “observations” that guess is worth.
The posterior has the same form, with updated hyperparameters:
where is the least-squares estimate. I like reading as a precision-weighted average of the data’s answer and the prior’s answer .
A mistake in my draft. When sampling from the posterior, I used the sample variance of as the scale instead of . That ignores the regression completely: the variance of the raw temperatures includes the whole seasonal swing, which the curve is supposed to explain. The scale has to be from the formula above, which is (roughly) the residual variance around the fitted curve, blended with the prior.
Checking a prior by looking at it
Numbers like "" mean nothing to me on their own. What helped was drawing from the prior many times and plotting the regression curve for each draw. If the curves include summers at °C, the prior is too vague; if they’re all the same line, it’s too confident. You adjust , , , until the cloud of curves looks like something you’d actually believe before seeing the data. This is a prior predictive check, and it’s a habit worth keeping for any Bayesian model.
Sampling the posterior
set.seed(2)
n <- 100; t <- (1:n) / n
X <- cbind(1, t, t^2)
y <- drop(X %*% c(-5, 90, -85)) + rnorm(n, 0, 4) # synthetic seasonal data
mu0 <- c(0, 0, 0); Omega0 <- diag(0.01, 3); nu0 <- 4; s20 <- 10
XtX <- crossprod(X)
bhat <- solve(XtX, crossprod(X, y))
Omegan <- XtX + Omega0
mun <- solve(Omegan, XtX %*% bhat + Omega0 %*% mu0)
nun <- nu0 + n
s2n <- drop(nu0 * s20 + crossprod(y) + t(mu0) %*% Omega0 %*% mu0 -
t(mun) %*% Omegan %*% mun) / nun
draws <- t(replicate(5000, {
sigma2 <- nun * s2n / rchisq(1, nun) # scaled Inv-chi2
beta <- mun + t(chol(sigma2 * solve(Omegan))) %*% rnorm(3)
c(beta, sigma2)
}))
t_peak <- -draws[, 2] / (2 * draws[, 3]) # where the curve peaks
quantile(t_peak, c(0.025, 0.5, 0.975)) # 0.497 0.517 0.537
The last two lines show the same trick as in any simulation-based posterior: the time of the maximum is (set the derivative to zero), so its posterior is that formula applied to every draw.
Another slip. In my draft I also wrote the maximum value as . Plugging back in actually gives
Credible band vs prediction band
For each time point you can compute for every posterior draw, and take the 2.5% and 97.5% quantiles. Connecting these gives a 95% band for the regression function. It’s narrow, and most data points fall outside it. That’s correct, not a failure: the band describes uncertainty about the mean curve, and with a year of data the mean is pinned down well. Individual days scatter around the mean with variance .
If you want a band that should contain about 95% of observations, you need the posterior predictive: for each draw, add noise, with using that draw’s , then take quantiles. That band is much wider. (Our report described the narrow band as “the interval the median falls into”, which isn’t quite it: it’s a pointwise interval for , the expected temperature.)
A prior that guards against overfitting
Suppose you fit a degree-7 polynomial but suspect the high-order terms aren’t needed. The conjugate prior can express that directly: set the prior mean of the high-order coefficients to zero and give them a large precision in (small prior variance), while keeping the low-order terms loose. The posterior then shrinks those coefficients towards zero unless the data really demand them. This is ridge regression in disguise: with and , the posterior mean is exactly the ridge estimate.
In my draft I suggested non-zero prior means for the extra terms, and our report talked about putting the prior mean “far from the data”. Both miss the point. Shrinkage means pulling towards zero (no effect), not towards some other value.
Key takeaways
- With the normal / Inv- prior, the posterior of is exact: draw first, then .
- The posterior scale for is , not the raw variance of .
- Check a prior by plotting curves drawn from it.
- A credible band for is not a prediction band; add noise for that.
- Zero prior means plus high prior precision on extra terms = shrinkage = ridge regression.
Resources
- Andrew Gelman et al., Bayesian Data Analysis, 3rd ed., Section 14.2 (Bayesian analysis of classical regression) and Section 14.8 (including numerical prior information): http://www.stat.columbia.edu/~gelman/book/
- Kevin P. Murphy, Machine Learning: A Probabilistic Perspective, Section 7.6 (Bayesian linear regression)
- Jonah Gabry et al., “Visualization in Bayesian workflow”, JRSS A 182(2) (2019), on prior predictive checks: https://doi.org/10.1111/rssa.12378
- 732A91 Bayesian Learning, Linköping University (course lab, spring 2020).