Course contents 05 / 27

05 / 27 · Linear Regression

Least squares

Linear regression fitted by minimizing the sum of squared residuals: the normal equations and when their solution is unique, the fit as an orthogonal projection, the reading as maximum likelihood under Gaussian noise with the sampling distribution of the coefficients, collinearity and numerical conditioning, R² and its traps, and robust losses for data with outliers.

On this page 13

The nearest-neighbours note ended with a model that answers every query from a handful of nearby points and learns nothing about the relationship as a whole; in many dimensions the nearby points disappear. This note takes the opposite bet. It assumes that the target is, up to noise, a weighted sum of the features, one weight per feature, and fits the weights to all the data at once by minimizing the squared errors. The fit has a closed form, a geometric meaning and a probabilistic meaning, and each of the three explains a different way it can fail: on collinear features, on badly scaled numbers and on outliers. The failures set up the rest of the section.

Notation. The training set is (x1,y1),…,(xn,yn)(x_1, y_1), \dots, (x_n, y_n) with xi∈Rdx_i \in \mathbb R^d and yi∈Ry_i \in \mathbb R. The design matrix X∈Rn×dX \in \mathbb R^{n \times d} has the xi⊤x_i^\top as rows and y∈Rny \in \mathbb R^n collects the targets. When the model has an intercept, the first feature is the constant 1, so dd counts the intercept. A weight vector w∈Rdw \in \mathbb R^d predicts y^i=⟨w,xi⟩\hat y_i = \langle w, x_i\rangle, all at once XwXw. The residuals are r=y−Xwr = y - Xw, the residual sum of squares is RSS(w)=∥y−Xw∥2\mathrm{RSS}(w) = \lVert y - Xw\rVert^2, and the mean squared error is MSE=RSS/n\mathrm{MSE} = \mathrm{RSS}/n. w^\hat w is the minimizer and y^=Xw^\hat y = X\hat w.

A linear model#

The model is

a(x)=⟨w,x⟩=w1x(1)+⋯+wdx(d).a(x) = \langle w, x\rangle = w_1 x^{(1)} + \dots + w_d x^{(d)} .

Each weight says how much the prediction changes when one feature grows by one unit and the others stay fixed. The model is linear in ww, not necessarily in the original inputs: the features can be powers of a number, logarithms, products of two inputs or the one-hot columns of a category from the features note. Everything below holds for any such fixed set of features, because it only uses the matrix XX.

The loss is the squared error, averaged over the training set:

Q(w)=1n∑i=1n(⟨w,xi⟩−yi)2=1n∥Xw−y∥2.Q(w) = \frac1n \sum_{i=1}^n \big(\langle w, x_i\rangle - y_i\big)^2 = \frac1n \lVert Xw - y\rVert^2 .

Why squares rather than absolute values or another penalty? Three answers follow in this note: the minimizer has a formula, it is an orthogonal projection, and it is the maximum-likelihood estimate when the noise is Gaussian. The last section shows the price.

The normal equations#

Expand the residual sum of squares: ∥y−Xw∥2=y⊤y−2w⊤X⊤y+w⊤X⊤Xw\lVert y - Xw\rVert^2 = y^\top y - 2 w^\top X^\top y + w^\top X^\top X w. The gradient of the linear term is −2X⊤y-2X^\top y and that of the quadratic form, with X⊤XX^\top X symmetric, is 2X⊤Xw2X^\top X w, so

∇w∥y−Xw∥2=2X⊤(Xw−y).\nabla_w \lVert y - Xw\rVert^2 = 2X^\top (Xw - y) .

The Hessian is 2X⊤X2X^\top X, and v⊤X⊤Xv=∥Xv∥2≥0v^\top X^\top X v = \lVert Xv\rVert^2 \ge 0 for every vv: the function is convex, and every point where the gradient vanishes is a global minimum. Setting the gradient to zero gives the normal equations

X⊤X w^=X⊤y.X^\top X\, \hat w = X^\top y .

If the columns of XX are linearly independent (which needs n≥dn \ge d), then ∥Xv∥2>0\lVert Xv\rVert^2 > 0 for every v≠0v \ne 0, the matrix X⊤XX^\top X is positive definite and invertible, and the minimizer is unique:

w^=(X⊤X)−1X⊤y.\hat w = (X^\top X)^{-1} X^\top y .

If the columns are dependent, for example when one feature is the sum of two others or when d>nd > n, the normal equations have infinitely many solutions, all with the same fitted values; the section on stability returns to that case.

Worked example. Four points: x=(0,1,2,3)x = (0, 1, 2, 3) and y=(1,3,2,5)y = (1, 3, 2, 5), model y^=w1+w2x\hat y = w_1 + w_2 x. The design matrix has columns (1,1,1,1)(1, 1, 1, 1) and (0,1,2,3)(0, 1, 2, 3), so

X⊤X=(46614),X⊤y=(1122).X^\top X = \begin{pmatrix} 4 & 6 \\ 6 & 14 \end{pmatrix}, \qquad X^\top y = \begin{pmatrix} 11 \\ 22 \end{pmatrix} .

The determinant is 4⋅14−6⋅6=204 \cdot 14 - 6 \cdot 6 = 20, and w^=120(14−6−64)(1122)=(1.1,1.1)\hat w = \frac{1}{20}\begin{pmatrix} 14 & -6 \\ -6 & 4\end{pmatrix}\begin{pmatrix} 11 \\ 22\end{pmatrix} = (1.1, 1.1). The fitted line is y^=1.1+1.1x\hat y = 1.1 + 1.1x, the residuals are (−0.1,0.8,−1.3,0.6)(-0.1, 0.8, -1.3, 0.6) and RSS=0.01+0.64+1.69+0.36=2.7\mathrm{RSS} = 0.01 + 0.64 + 1.69 + 0.36 = 2.7.

Solving the normal equations costs O(nd2)O(nd^2) to form X⊤XX^\top X and O(d3)O(d^3) to solve the d×dd \times d system. For ten features that is nothing; for a million sparse text features it is impossible, which is where the next note starts.

The geometry: a projection#

The normal equations can be rewritten as X⊤(y−Xw^)=0X^\top (y - X\hat w) = 0: the residual vector is orthogonal to every column of XX. Read the nn targets as one point y∈Rny \in \mathbb R^n. As ww varies, the predictions XwXw sweep the column space col⁡(X)\operatorname{col}(X), a dd-dimensional subspace of Rn\mathbb R^n. Least squares picks the point of that subspace closest to yy, and the closest point is the foot of the perpendicular.

Figure

Least squares as a projection

Projection of the response vector onto the column spaceA plane spanned by the two feature columns; the point y above it; the residual drops vertically to ŷ at a right angle; a dashed segment from y to another point Xw of the plane is longer.col(X)x₁ = 1x₂ = x0y = (1, 3, 2)ŷ = Xŵ = (1.5, 2, 2.5)y − ŷ ⊥ x₁, x₂‖y − ŷ‖² = 1.5Xw, w = (1, 1)‖y − Xw‖² = 2 = 1.5 + 0.5Projection of the response vector onto the column spaceA plane spanned by the two feature columns; the point y above it; the residual drops vertically to ŷ at a right angle; a dashed segment from y to another point Xw of the plane is longer.col(X)x₁x₂0yŷy − ŷXw
Three observations, x = (0, 1, 2), y = (1, 3, 2), and the model ŷ = w₁ + w₂x. The vector y lives in R³, and all possible predictions Xw fill the plane col(X) spanned by the columns x₁ = (1, 1, 1) and x₂ = (0, 1, 2). The solution of the normal equation, ŵ = (1.5, 0.5), gives the foot of the perpendicular from y to the plane: the residual (−0.5, 1, −0.5) is orthogonal to both columns. Every other point of the plane is farther: for w = (1, 1) the squared distance is 2 = 1.5 + 0.5, by Pythagoras.

The orthogonality gives a proof of optimality without calculus. For any ww, split y−Xw=(y−Xw^)+X(w^−w)y - Xw = (y - X\hat w) + X(\hat w - w). The first term is orthogonal to the column space and the second lies in it, so by Pythagoras

∥y−Xw∥2=∥y−Xw^∥2+∥X(w^−w)∥2 ≥ ∥y−Xw^∥2,\lVert y - Xw\rVert^2 = \lVert y - X\hat w\rVert^2 + \lVert X(\hat w - w)\rVert^2 \ \ge\ \lVert y - X\hat w\rVert^2 ,

with equality exactly when Xw=Xw^Xw = X\hat w. In the three-point example of the figure the extra term is 0.50.5 for w=(1,1)w = (1, 1).

The map from yy to y^\hat y is linear: y^=Hy\hat y = Hy with the hat matrix H=X(X⊤X)−1X⊤H = X(X^\top X)^{-1}X^\top. It is the orthogonal projection onto col⁡(X)\operatorname{col}(X), so it is symmetric and idempotent (H2=HH^2 = H: projecting twice changes nothing), and its trace is tr⁡((X⊤X)−1X⊤X)=d\operatorname{tr}\big((X^\top X)^{-1}X^\top X\big) = d, the dimension of the subspace. The diagonal entry hiih_{ii}, the leverage of point ii, is how much y^i\hat y_i moves when yiy_i moves by one. In the four-point example the leverages are (0.7,0.3,0.3,0.7)(0.7, 0.3, 0.3, 0.7), summing to d=2d = 2: the end points pull on the line more than the middle ones.

Two consequences of orthogonality are used constantly. When the model has an intercept, the constant column is one of the columns, so ∑iri=0\sum_i r_i = 0: the residuals average to zero and the mean of y^\hat y equals the mean of yy. In the worked example, −0.1+0.8−1.3+0.6=0-0.1 + 0.8 - 1.3 + 0.6 = 0, and also 0⋅(−0.1)+1⋅0.8+2⋅(−1.3)+3⋅0.6=00 \cdot (-0.1) + 1 \cdot 0.8 + 2 \cdot (-1.3) + 3 \cdot 0.6 = 0. And y=y^+ry = \hat y + r with y^⊥r\hat y \perp r, so the total variation splits into an explained and an unexplained part, which is what R2R^2 below measures.

The probability: Gaussian noise and the conditional mean#

Suppose the data come from yi=⟨w,xi⟩+εiy_i = \langle w, x_i\rangle + \varepsilon_i with εi\varepsilon_i independent and N(0,σ2)N(0, \sigma^2). The negative log-likelihood is RSS(w)/(2σ2)\mathrm{RSS}(w)/(2\sigma^2) plus a constant, as derived in the maximum likelihood note, so minimizing squared error is maximizing the likelihood. Without assuming a model at all, squared error has another justification: its population minimizer over all functions is the conditional mean E[Y∣X=x]E[Y \mid X = x] (the best predictor). Least squares restricted to linear functions estimates the linear function closest to E[Y∣X]E[Y \mid X] in mean square, which is E[Y∣X]E[Y \mid X] itself when that is linear.

The distribution of the coefficients. Here the design XX is treated as fixed and only the noise is random: the statements below are about repeated draws of ε\varepsilon for the same inputs. Substitute y=Xw+εy = Xw + \varepsilon into the formula:

w^=(X⊤X)−1X⊤(Xw+ε)=w+(X⊤X)−1X⊤ε.\hat w = (X^\top X)^{-1}X^\top (Xw + \varepsilon) = w + (X^\top X)^{-1}X^\top \varepsilon .

The estimate is the true weight plus a fixed linear map of the noise. Three facts follow, each under its own assumption:

  • Unbiased if E[ε]=0E[\varepsilon] = 0: E[w^]=wE[\hat w] = w.
  • Covariance σ2(X⊤X)−1\sigma^2 (X^\top X)^{-1} if the noise is uncorrelated with equal variances, Var⁡ε=σ2I\operatorname{Var}\varepsilon = \sigma^2 I: with A=(X⊤X)−1X⊤A = (X^\top X)^{-1}X^\top, Var⁡w^=A σ2I A⊤=σ2(X⊤X)−1\operatorname{Var}\hat w = A\,\sigma^2 I\,A^\top = \sigma^2 (X^\top X)^{-1}.
  • Gaussian if the noise is Gaussian, since an affine map of a Gaussian vector is Gaussian: w^∼N(w,σ2(X⊤X)−1)\hat w \sim N\big(w, \sigma^2 (X^\top X)^{-1}\big). For other independent noise with finite variance, the distribution is approximately Gaussian for large nn by the central limit theorem, provided no single point dominates the fit: the largest leverage max⁡ihii\max_i h_{ii} (defined above) must tend to 0.

The noise variance is unknown and is estimated from the residuals. Since r=(I−H)y=(I−H)εr = (I - H)y = (I - H)\varepsilon (because (I−H)X=0(I - H)X = 0), RSS=ε⊤(I−H)ε\mathrm{RSS} = \varepsilon^\top (I - H)\varepsilon and E[RSS]=σ2tr⁡(I−H)=σ2(n−d)E[\mathrm{RSS}] = \sigma^2 \operatorname{tr}(I - H) = \sigma^2 (n - d). So

σ^2=RSSn−d\hat\sigma^2 = \frac{\mathrm{RSS}}{n - d}

is unbiased: dd degrees of freedom are spent on the fit, as the n−1n - 1 of the sample variance spends one on the mean. The square roots of the diagonal of σ^2(X⊤X)−1\hat\sigma^2 (X^\top X)^{-1} are the standard errors of the coefficients.

Worked example. In the four-point example σ^2=2.7/(4−2)=1.35\hat\sigma^2 = 2.7/(4 - 2) = 1.35 and (X⊤X)−1=120(14−6−64)(X^\top X)^{-1} = \frac{1}{20}\begin{pmatrix} 14 & -6 \\ -6 & 4\end{pmatrix}, so the slope 1.11.1 has standard error 1.35⋅4/20=0.520\sqrt{1.35 \cdot 4/20} = 0.520 and the intercept 1.35⋅14/20=0.972\sqrt{1.35 \cdot 14/20} = 0.972. With four points the slope is barely two standard errors from zero. A simulation confirms the formula: 30 equally spaced points on [0,1][0, 1], true w=(1,2)w = (1, 2), σ=0.5\sigma = 0.5 and 20,000 noise draws give coefficient means (1.001,2.000)(1.001, 2.000) and standard deviations (0.177,0.303)(0.177, 0.303), against (0.178,0.306)(0.178, 0.306) from σdiag⁡(X⊤X)−1\sigma\sqrt{\operatorname{diag}(X^\top X)^{-1}} (the Code section).

The Gauss–Markov theorem adds that, with uncorrelated equal-variance noise, no other estimator that is linear in yy and unbiased has a smaller variance for any linear combination of the coefficients (Hastie, Tibshirani and Friedman, 2009, section 3.2.2). The qualifier matters: estimators that accept a little bias can have a much smaller variance and a smaller mean squared error, the trade-off of the estimators note. The regularization note builds such estimators.

When the solution is unstable#

The covariance σ2(X⊤X)−1\sigma^2 (X^\top X)^{-1} is large in the directions where X⊤XX^\top X has small eigenvalues, that is, where some combination of features is nearly constant across the data. Two features that almost repeat each other produce exactly that.

Collinearity. Take 100 points with x(2)=x(1)+0.01 ξx^{(2)} = x^{(1)} + 0.01\,\xi, where ξ\xi is standard normal noise, and y=x(1)+x(2)+εy = x^{(1)} + x^{(2)} + \varepsilon with σ=1\sigma = 1. The correlation of the two features is 0.999940.99994 and the condition number of X⊤XX^\top X is 3.5⋅1043.5 \cdot 10^4. Three draws of the noise give the weights (−5.00,6.88)(-5.00, 6.88), (11.88,−9.90)(11.88, -9.90) and (−8.83,10.94)(-8.83, 10.94), with sums 1.881.88, 1.981.98 and 2.112.11. The data pin down the sum w1+w2w_1 + w_2, the direction in which the features vary, and say almost nothing about the difference, the direction in which they do not. The standard error of each weight is 9.749.74, against 0.100.10 for a model with one of the two features alone. The predictions on data like the training data hardly change from draw to draw; the coefficients, and any interpretation of them, are noise. A weight of −9.90-9.90 on a feature that helps the target is the typical symptom.

Rank deficiency. When the columns are exactly dependent, or d>nd > n, X⊤XX^\top X is singular and the normal equations have a whole affine set of solutions. The standard choice is the one with the smallest norm, w^=X+y\hat w = X^+ y with the Moore–Penrose pseudoinverse X+X^+, which is what numpy.linalg.lstsq returns. The choice is a preference, not something the data decide, and the regularization note makes the preference explicit.

Numerical conditioning. Even when X⊤XX^\top X is invertible in exact arithmetic, forming it squares the condition number: κ(X⊤X)=κ(X)2\kappa(X^\top X) = \kappa(X)^2. Double precision carries about 16 significant digits, and a linear solve loses roughly log⁡10κ\log_{10}\kappa of them. For polynomial features 1,t,…,t101, t, \dots, t^{10} on 50 points of [0,1][0, 1], κ(X)=2.0⋅107\kappa(X) = 2.0 \cdot 10^7 and κ(X⊤X)=4.1⋅1014\kappa(X^\top X) = 4.1 \cdot 10^{14}. Solving the normal equations recovers coefficients that are all equal to 1 with an error of 4⋅10−34 \cdot 10^{-3}; an SVD-based solver applied to XX directly, as lstsq does, gets 4⋅10−104 \cdot 10^{-10} (Trefethen and Bau, 1997, lectures 11 and 19). The formula (X⊤X)−1X⊤y(X^\top X)^{-1}X^\top y is for derivations; numerical code factorizes XX. Centring and scaling the features, as in the features note, also lowers the condition number, and the next note shows that the same number governs the speed of gradient descent.

Measuring a regression#

The mean squared error is in squared units of the target; its root, the RMSE, is in the target’s units. The coefficient of determination compares the fit with the best constant, the mean yˉ\bar y:

R2=1−∑i(yi−y^i)2∑i(yi−yˉ)2.R^2 = 1 - \frac{\sum_i (y_i - \hat y_i)^2}{\sum_i (y_i - \bar y)^2} .

On the training data of a model with an intercept, the Pythagorean split of the previous sections puts R2R^2 between 0 and 1, the share of the variation of yy that the fit explains. In the four-point example yˉ=2.75\bar y = 2.75, the total sum of squares is 8.758.75, and R2=1−2.7/8.75=0.691R^2 = 1 - 2.7/8.75 = 0.691.

On the diabetes data bundled with scikit-learn (442 patients, 10 centred and scaled measurements, the target a measure of disease progression after a year), least squares has a training R2R^2 of 0.5180.518 and a 5-fold cross-validated R2R^2 of 0.4890.489. Nearest neighbours on standardized features reach at best 0.4540.454 (at k=20k = 20; 0.3820.382, 0.4440.444 and 0.4280.428 for k=5k = 5, 10 and 40). Eleven coefficients fitted to all the data beat the local vote here, because the relationship is close to additive and 442 points are few for neighbourhoods in ten dimensions.

R2R^2 has three traps:

  • Training R2R^2 never decreases with features. Adding a column can only keep or enlarge the column space, so the projection’s residual never grows. With 50 training points, one useful feature and kk columns of pure noise, the training R2R^2 goes 0.5720.572, 0.6490.649, 0.7470.747, 0.9210.921 for k=0,10,20,40k = 0, 10, 20, 40, while on 50 fresh points it goes 0.3250.325, 0.1540.154, −0.158-0.158, −0.71-0.71. A negative R2R^2 means worse than predicting the mean, and it only appears on data the model did not see. Report R2R^2 on validation data, as the validation note requires of every metric.
  • R2R^2 depends on the spread of xx. For y=x+εy = x + \varepsilon with σ=1\sigma = 1, the same model with the same noise has R2=(1/12)/(1/12+1)=0.077R^2 = (1/12)/(1/12 + 1) = 0.077 when xx is uniform on [0,1][0, 1] and 0.8930.893 when it is uniform on [0,10][0, 10]; the RMSE is 1 in both cases. R2R^2 compares with the mean, and the mean is a worse predictor when yy varies more.
  • A high R2R^2 does not mean a correct model. A straight line through points on a parabola can have R2R^2 near 1 and residuals that are all positive at the ends and negative in the middle. Look at the residuals.

Squared error and outliers#

Squared error estimates the conditional mean, and a mean follows its largest values. Other losses estimate other targets (other losses, other targets): the best constant under absolute error is the median. For the five values 1,2,4,8,161, 2, 4, 8, 16 the best constant under squared error is their mean 6.26.2, under absolute error their median 44. One wrong value can therefore move a least-squares fit arbitrarily far, while it moves the median-based fit only until it crosses the other points.

Figure

One outlier and three losses

Least-squares, Huber and absolute-error lines with one outlierA scatter of ten points; the point at x = 8 lies far above the rest. The red least-squares line is visibly steeper than the blue Huber line, the green absolute-error line and the grey dashed least-squares line without the outlier, which nearly coincide. Beside it, the three losses as functions of the residual: a parabola, the piecewise Huber function and the absolute value.0246804812xyoutlierleast squares: 0.37 + 0.82xHuber, δ = 1: 0.99 + 0.53xabsolute error: 1.27 + 0.47xleast squares without the outlierloss ρ(r) against the residual r−3−113123r²/2|r|HuberLeast-squares, Huber and absolute-error lines with one outlierA scatter of ten points; the point at x = 8 lies far above the rest. The red least-squares line is visibly steeper than the blue Huber line, the green absolute-error line and the grey dashed least-squares line without the outlier, which nearly coincide. Beside it, the three losses as functions of the residual: a parabola, the piecewise Huber function and the absolute value.0246804812xyoutlierleast squares: 0.37 + 0.82xHuber, δ = 1: 0.99 + 0.53xabsolute error: 1.27 + 0.47xleast squares without the outlierloss ρ(r) against the residual r−3−113123r²/2|r|Huber
Ten points close to a line, one of which (x = 8, y = 13) is a gross error. Left: the lines that minimize the sum of squared residuals, the Huber loss with δ = 1, and the sum of absolute residuals; the dashed line is least squares on the nine points without the outlier, slope 0.48. The outlier gets a residual of 6.07, and squared it outweighs all the other points together, so least squares turns the line towards it: slope 0.82. Huber (0.53) and absolute error (0.47) barely move. Right: the losses themselves. The square grows quadratically; the absolute value, and Huber outside [−1, 1], grow linearly, so a single distant point pulls on the line with bounded force.

The outlier in the figure has a least-squares residual of 6.076.07; squared, 36.936.9, it is larger than the squared residuals of the other nine points together. Least squares tilts the line towards it, from slope 0.480.48 without the point to 0.820.82 with it. Two losses limit the influence of large residuals:

  • Absolute error, ρ(r)=∣r∣\rho(r) = \lvert r\rvert, least absolute deviations. Each point pulls with the same force whatever its distance. The fitted line here is 1.27+0.47x1.27 + 0.47x; the minimizer is not always unique, and the loss is not differentiable at 0.
  • The Huber loss (Huber, 1964): ρδ(r)=r2/2\rho_\delta(r) = r^2/2 for ∣r∣≤δ\lvert r\rvert \le \delta and δ(∣r∣−δ/2)\delta(\lvert r\rvert - \delta/2) beyond. Quadratic for small residuals, so it keeps the efficiency of least squares on clean Gaussian data; linear for large ones, so an outlier’s pull is capped at δ\delta. With δ=1\delta = 1 the line is 0.99+0.53x0.99 + 0.53x.

The cap is on the derivative with respect to the residual. The gradient with respect to the weights multiplies that derivative by xix_i, so a point with an extreme input, a high-leverage point, still pulls hard. Ten points on the line y=xy = x and one gross error at (100,0)(100, 0) flatten all three fits alike: the slopes of least squares, Huber and least absolute deviations are all −0.04-0.04. These losses protect against outliers in yy, not in xx.

Neither has a closed form. Both can be fitted by repeatedly solving weighted least squares with weights that shrink for large residuals, which is how the figure computes them, or by the general method of the next note.

What changed#

Nearest neighboursLeast squares
Modelthe average of nearby targetsa global linear function with dd coefficients
Trainingstore the datasolve X⊤Xw=X⊤yX^\top X w = X^\top y, O(nd2+d3)O(nd^2 + d^3)
Predictionsearch the training setone dot product, O(d)O(d)
Diabetes, cross-validated R2R^20.4540.454 at best (k=20k = 20)0.4890.489
Uncertaintynone built inVar⁡w^=σ2(X⊤X)−1\operatorname{Var}\hat w = \sigma^2 (X^\top X)^{-1}, standard errors
Interpretationnoneone weight per feature, if the features are not collinear
Weak pointmany dimensions, scalingnonlinear relationships, collinearity, outliers, dd close to nn

Limitations#

  • Linear in the chosen features. The model sees interactions and curvature only if someone puts them into XX; the trees section and the networks section learn them instead.
  • Unstable with correlated features or dd close to nn. The coefficients’ variance blows up along nearly constant directions; with d≥nd \ge n and rank⁡X=n\operatorname{rank} X = n the training error is zero, so the fit on the training data is no evidence of generalization. Which of the many interpolating solutions is chosen (the minimum-norm one, for example) and the geometry of the data still decide whether its predictions are useful, as the double-descent caveat shows.
  • Sensitive to outliers. A single gross error can turn the line, because the squared loss weighs residuals by their size; robust losses help against outliers in yy, not against extreme inputs.
  • The variance formula assumes uncorrelated, equal-variance noise. With heteroscedastic or correlated errors (time series, grouped data) the coefficients stay unbiased but the standard errors are wrong.
  • The closed form costs O(nd2+d3)O(nd^2 + d^3) and exists only for squared error.

What you should remember#

  • Least squares minimizes ∥y−Xw∥2\lVert y - Xw\rVert^2; the normal equations X⊤Xw^=X⊤yX^\top X\hat w = X^\top y have the unique solution (X⊤X)−1X⊤y(X^\top X)^{-1}X^\top y when the columns of XX are independent.
  • Geometrically, y^\hat y is the orthogonal projection of yy onto the column space; the residual is orthogonal to every feature, and with an intercept the residuals sum to zero.
  • Under Gaussian noise least squares is maximum likelihood, and w^∼N(w,σ2(X⊤X)−1)\hat w \sim N\big(w, \sigma^2 (X^\top X)^{-1}\big); estimate σ2\sigma^2 by RSS/(n−d)\mathrm{RSS}/(n - d).
  • Nearly collinear features make individual coefficients meaningless while the predictions stay stable; this is the opening for regularization.
  • Never solve the normal equations numerically for ill-conditioned features: forming X⊤XX^\top X squares the condition number. Use QR or SVD (lstsq).
  • R2R^2 compares with predicting the mean; on training data it never decreases as features are added, so report it on validation data.
  • Squared error estimates the conditional mean and follows outliers; absolute error estimates the median, and the Huber loss interpolates between the two.

Code#

The worked examples, the sampling distribution of the coefficients, the diabetes comparison with nearest neighbours, the traps of R2R^2, collinearity, conditioning and robust fits:

import numpy as np
from scipy import optimize
from sklearn.datasets import load_diabetes
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import KFold, cross_val_score
from sklearn.neighbors import KNeighborsRegressor
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler

rng = np.random.default_rng(0)
r2 = lambda y, p: 1 - ((y - p) ** 2).sum() / ((y - y.mean()) ** 2).sum()

# the worked example: four points, the normal equations, residuals orthogonal to the columns
x = np.array([0., 1, 2, 3]); y = np.array([1., 3, 2, 5])
X = np.column_stack([np.ones(4), x])
w = np.linalg.solve(X.T @ X, X.T @ y)
r = y - X @ w
H = X @ np.linalg.inv(X.T @ X) @ X.T
print(w, r.round(2), (X.T @ r).round(12) + 0, round(r @ r, 2), round(r2(y, X @ w), 3), np.diag(H).round(2))
# [1.1 1.1] [-0.1  0.8 -1.3  0.6] [0. 0.] 2.7 0.691 [0.7 0.3 0.3 0.7]
s2 = r @ r / (4 - 2)                                  # unbiased noise variance, n - d = 2
print(round(s2, 2), np.sqrt(s2 * np.diag(np.linalg.inv(X.T @ X))).round(3))   # 1.35 [0.972 0.52 ]

# the sampling distribution of w-hat: 30 points on [0, 1], w = (1, 2), sigma = 0.5, 20,000 noise draws
Xs = np.column_stack([np.ones(30), np.linspace(0, 1, 30)])
W = np.array([np.linalg.lstsq(Xs, Xs @ [1, 2] + 0.5 * rng.normal(size=30), rcond=None)[0] for _ in range(20_000)])
print(W.mean(0).round(3), W.std(0).round(3), (0.5 * np.sqrt(np.diag(np.linalg.inv(Xs.T @ Xs)))).round(3))
# [1.001 2.   ] [0.177 0.303] [0.178 0.306]: simulated means, simulated and theoretical standard deviations

# diabetes (442 patients, 10 features): the closed form is what scikit-learn computes; linear model against kNN
Xd, yd = load_diabetes(return_X_y=True)
A = np.column_stack([np.ones(len(yd)), Xd])
wd = np.linalg.lstsq(A, yd, rcond=None)[0]
lr = LinearRegression().fit(Xd, yd)
print(f'{np.abs(wd - np.r_[lr.intercept_, lr.coef_]).max():.0e}', round(r2(yd, A @ wd), 3))   # 2e-12 0.518
cv = KFold(5, shuffle=True, random_state=0)
print(round(cross_val_score(LinearRegression(), Xd, yd, cv=cv, scoring='r2').mean(), 3),
      [round(float(cross_val_score(make_pipeline(StandardScaler(), KNeighborsRegressor(k)), Xd, yd, cv=cv, scoring="r2").mean()), 3) for k in (5, 10, 20, 40)])
# 0.489 [0.382, 0.444, 0.454, 0.428]

# R² on the training data never decreases with useless features; on fresh data it collapses (50 + 50 points)
z = rng.normal(size=(100, 1)); t = z[:, 0] + rng.normal(size=100)
for k in (0, 10, 20, 40):
    Z = np.column_stack([np.ones(100), z, rng.normal(size=(100, k))])
    v = np.linalg.lstsq(Z[:50], t[:50], rcond=None)[0]
    print(k, round(r2(t[:50], Z[:50] @ v), 3), round(r2(t[50:], Z[50:] @ v), 3))
# 0 0.572 0.325 | 10 0.649 0.154 | 20 0.747 -0.158 | 40 0.921 -0.71

# two nearly identical features: the coefficients swing, their sum and the predictions do not
x1 = rng.normal(size=100); x2 = x1 + 0.01 * rng.normal(size=100); X2 = np.column_stack([x1, x2])
print(round(np.corrcoef(x1, x2)[0, 1], 5), f'{np.linalg.cond(X2.T @ X2):.1e}')   # 0.99994 3.5e+04
for _ in range(3):
    v = np.linalg.lstsq(X2, x1 + x2 + rng.normal(size=100), rcond=None)[0]
    print(v.round(2), round(v.sum(), 2))
# [-5.    6.88] 1.88 | [11.88 -9.9 ] 1.98 | [-8.83 10.94] 2.11
print(np.sqrt(np.diag(np.linalg.inv(X2.T @ X2))).round(2), round(1 / np.sqrt(x1 @ x1), 2))   # [9.74 9.73] 0.1: standard errors for sigma = 1

# conditioning: polynomial features of degree 10 on 50 points; normal equations against QR/SVD (lstsq)
V = np.vander(np.linspace(0, 1, 50), 11, increasing=True); yv = V @ np.ones(11)
print(f'{np.linalg.cond(V):.1e} {np.linalg.cond(V.T @ V):.1e}',
      f'{np.abs(np.linalg.solve(V.T @ V, V.T @ yv) - 1).max():.0e} {np.abs(np.linalg.lstsq(V, yv, rcond=None)[0] - 1).max():.0e}')
# 2.0e+07 4.1e+14 4e-03 4e-10

# one outlier: least squares, Huber (delta = 1) and least absolute deviations
xo = np.arange(10.); yo = np.array([1.3, 1.1, 2.2, 3.0, 2.7, 3.6, 3.5, 4.9, 13.0, 5.3]); Xo = np.column_stack([np.ones(10), xo])
huber = lambda r: np.where(np.abs(r) <= 1, 0.5 * r ** 2, np.abs(r) - 0.5)
fits = {'ls': np.linalg.lstsq(Xo, yo, rcond=None)[0],
        'ls without x=8': np.linalg.lstsq(np.delete(Xo, 8, 0), np.delete(yo, 8), rcond=None)[0],
        'huber': optimize.minimize(lambda v: huber(yo - Xo @ v).sum(), [0, 0], method='BFGS', options={'gtol': 1e-10}).x,
        'lad': optimize.linprog(np.r_[0, 0, np.ones(10)], A_ub=np.block([[Xo, -np.eye(10)], [-Xo, -np.eye(10)]]),
                                b_ub=np.r_[yo, -yo], bounds=[(None, None)] * 2 + [(0, None)] * 10).x[:2]}
for k, v in fits.items(): print(k, v.round(3))
# ls [0.373 0.819] | ls without x=8 [1.107 0.477] | huber [0.986 0.533] | lad [1.267 0.467]

# a gross error at an extreme input: ten points on y = x and one at (100, 0)
xl = np.r_[np.arange(10.), 100]; yl = np.r_[np.arange(10.), 0]; Xl = np.column_stack([np.ones(11), xl])
print(round(float(np.linalg.lstsq(Xl, yl, rcond=None)[0][1]), 2),
      round(float(optimize.minimize(lambda v: huber(yl - Xl @ v).sum(), [0, 1], method='BFGS', options={'gtol': 1e-10}).x[1]), 2),
      round(float(optimize.linprog(np.r_[0, 0, np.ones(11)], A_ub=np.block([[Xl, -np.eye(11)], [-Xl, -np.eye(11)]]),
                                   b_ub=np.r_[yl, -yl], bounds=[(None, None)] * 2 + [(0, None)] * 11).x[1]), 2))
# -0.04 -0.04 -0.04: the slopes of least squares, Huber and least absolute deviations

Next#

The normal equations need the whole matrix X⊤XX^\top X and a d×dd \times d solve, which is out of reach for a million features, and they exist only for squared error: the Huber and absolute losses of the last section, and the logistic loss of the classification section, have no closed form at all. The next note replaces the formula by an iteration that only needs the gradient, 2X⊤(Xw−y)2X^\top(Xw - y) here, and shows that its speed is set by the same condition number that made the normal equations inaccurate.

Least squares reappears across the courses: GloVe word vectors are fitted by weighted least squares on log co-occurrence counts, the least-squares GAN replaces the discriminator’s cross-entropy by squared error, and alternating least squares fits the matrix factorization of recommender systems.

References#