Generalized linear models
Wrap linear regression, logistic regression, and Poisson regression into one exponential-family framework with link functions.
Linear, logistic, and softmax regression look like distinct models, but they are three instances of the same template: a linear predictor inside an exponential-family distribution, connected by a link function. The generalized linear model (GLM) framework formalizes this and turns model choice into picking a distribution and a link.
The three ingredients
A GLM is specified by:
- Random component: follows an exponential-family distribution with mean .
- Linear predictor: .
- Link function: , an invertible function connecting the mean to the linear predictor.
Equivalently, . The link's job is to match the support of to the real line that lives on[1].
The natural (canonical) link
The exponential-family lesson defined the natural parameter of a distribution. The canonical link sets : the linear predictor is the natural parameter[2]. With the canonical link the math simplifies dramatically:
- Gradient: , a clean data-residual expression.
- Hessian: with , always PSD, so the log-likelihood is concave.
- IRLS has the same shape across all canonical-link GLMs.
The standard catalog
| Response | Distribution | Canonical link | Inverse link | Result |
|---|---|---|---|---|
| Continuous | Gaussian | identity | Linear regression | |
| Binary | Bernoulli | logit | sigmoid | Logistic regression |
| Counts | Poisson | log | exp | Poisson regression |
| Positive continuous | Gamma | reciprocal (or log) | Gamma regression | |
| Multi-class | Categorical | log | softmax | Softmax regression |
Each row is a model you have already met or are about to meet. The framework makes their relationship explicit, and the implementation generalizes: iteratively reweighted least squares (IRLS) with the right and fits any of them.
Why pick a different link
Two reasons to use a noncanonical link:
- Match the data scale. For positive continuous responses, the log link keeps the predicted mean positive even when the linear predictor is large negative. The reciprocal canonical link can produce negative means.
- Interpretation. A log link on counts (Poisson regression) means coefficients are multiplicative effects on the rate. A logit link on binary outcomes means coefficients are log-odds-ratios. These are the units of the conclusions you want to report.
Canonical links give the cleanest math; the right link gives the cleanest inference.
The deviance
The GLM analogue of squared error is the deviance, twice the gap between the log-likelihood of the fitted model and the log-likelihood of a saturated model that perfectly fits every observation:
[3]For Gaussian + identity link, the deviance is exactly the residual sum of squares. For other GLMs it generalizes appropriately, and is the goodness-of-fit quantity that hypothesis tests and information criteria are built on.
Check it on arrays
import numpy as np
rng = np.random.default_rng(0)
def fit_glm(X, y, link, inverse_link, var_fn, steps=20):
"""Generic IRLS for a canonical-link GLM.
link: g(mu), inverse_link: g^{-1}(eta), var_fn: variance V(mu)."""
n, d = X.shape
mu = (y + y.mean()) / 2 + 1e-3 # init
eta = link(mu)
for _ in range(steps):
W = 1.0 / var_fn(mu) # canonical-link weights
z = eta + (y - mu) / mu * 0 + (y - mu) * (1 / mu) * 0 # placeholder
# working response for canonical link: z = eta + (y - mu) / (dmu/deta)
# canonical link has dmu/deta = var(mu), so z = eta + (y - mu) / var(mu)
z = eta + (y - mu) / var_fn(mu)
beta = np.linalg.solve(X.T @ (W[:, None] * X), X.T @ (W * z))
eta = X @ beta
mu = inverse_link(eta)
return beta, mu
n, d = 800, 3
X = np.column_stack([np.ones(n), rng.normal(size=(n, d - 1))])
# Gaussian + identity = linear regression
beta_lin_true = np.array([1.0, 2.0, -1.0])
y_lin = X @ beta_lin_true + 0.3 * rng.normal(size=n)
b_lin, _ = fit_glm(X, y_lin, link=lambda m: m, inverse_link=lambda e: e, var_fn=lambda m: np.ones_like(m))
print("Gaussian/identity beta:", np.round(b_lin, 3), " (vs OLS)")
# Bernoulli + logit = logistic regression
beta_log_true = np.array([-0.3, 1.5, -1.0])
p_true = 1 / (1 + np.exp(-X @ beta_log_true))
y_bin = (rng.random(n) < p_true).astype(float)
b_log, _ = fit_glm(X, y_bin,
link=lambda m: np.log(m / (1 - m)),
inverse_link=lambda e: 1 / (1 + np.exp(-e)),
var_fn=lambda m: m * (1 - m) + 1e-8)
print("Bernoulli/logit beta: ", np.round(b_log, 3), " (vs true ", beta_log_true, ")")
# Poisson + log = Poisson regression
beta_pois_true = np.array([0.5, 0.4, -0.3])
mu_true = np.exp(X @ beta_pois_true)
y_count = rng.poisson(mu_true)
b_pois, _ = fit_glm(X, y_count,
link=lambda m: np.log(m),
inverse_link=lambda e: np.exp(e),
var_fn=lambda m: m)
print("Poisson/log beta: ", np.round(b_pois, 3), " (vs true", beta_pois_true, ")")A single IRLS routine, parameterized by link and variance function, recovers linear, logistic, and Poisson regression.
Exercises
Exercise 1. Derive the canonical link for the Bernoulli distribution from the exponential-family form. Write as with natural parameter , read off as a function of , and confirm the canonical link is the logit.
Solution
Step 1. The Bernoulli pmf is for . Take logs and exponentiate:
Step 2. Matching to , the natural parameter is the coefficient of : , and .
Step 3. The canonical link sets , the logit. Inverting, is the sigmoid, matching the catalog row for logistic regression.
Exercise 2. For a canonical-link GLM the score is . Show that at the MLE the residual vector is orthogonal to every column of , and explain why this generalizes the OLS normal equations.
Solution
Step 1. The MLE is a stationary point of the log-likelihood, so . With the canonical-link gradient this reads , where .
Step 2. Each component says the residual is orthogonal to column . The residual lies in the orthogonal complement of the column space of .
Step 3. For the Gaussian/identity GLM, , so the condition becomes , the OLS normal equations. The canonical-link GLM keeps the same residual-orthogonality structure, with a nonlinear function of instead of a linear one.
Exercise 3 (code). Fit a Poisson/log GLM by Newton's method (which equals IRLS for the canonical link) and verify the orthogonality condition from Exercise 2: at the fitted optimum.
Solution
import numpy as np
rng = np.random.default_rng(0)
n, d = 600, 3
X = np.column_stack([np.ones(n), rng.normal(size=(n, d - 1))])
beta_true = np.array([0.3, 0.5, -0.4])
y = rng.poisson(np.exp(X @ beta_true)).astype(float)
beta = np.zeros(d)
for _ in range(50):
mu = np.exp(X @ beta) # inverse log link
g = X.T @ (y - mu) # canonical-link score
H = X.T @ (mu[:, None] * X) # -Hessian = X^T diag(mu) X
beta = beta + np.linalg.solve(H, g) # Newton step
mu = np.exp(X @ beta)
score = X.T @ (y - mu)
assert np.max(np.abs(score)) < 1e-6 # residuals orthogonal to every column
print("max |X^T(y - mu)| at MLE =", float(np.max(np.abs(score))))
print("beta:", np.round(beta, 3), " true:", beta_true)The fitted residuals are orthogonal to every column to machine precision, the GLM generalization of the OLS normal equations, and the recovered coefficients sit near the truth.
The next lesson zeroes in on the last two GLMs from the table: Poisson for counts and Gamma for durations.
References
- [1]Nelder, J. A., & Wedderburn, R. W. M. (1972). "Generalized linear models". JRSS-A, 135(3), 370-384. doi:10.2307/2344614. The paper that introduced the GLM framework.↩
- [2]McCullagh, P., & Nelder, J. A. (1989). Generalized Linear Models (2nd ed.), §2. Chapman & Hall. Exponential family, canonical links, and the catalog of GLMs.↩
- [3]Hastie, T., Tibshirani, R., & Friedman, J. (2009). The Elements of Statistical Learning (2nd ed.), §4.4. Springer. doi:10.1007/978-0-387-84858-7. Deviance as the GLM goodness-of-fit.↩