AI Knowledge Tree

Linear regression and OLS

Set up linear regression, derive the OLS estimator from the normal equations, and read it as projection onto the column space.

Linear regression is the simplest supervised learner: model a target as a linear function of features plus noise, and fit the coefficients to minimize squared error. The closed form falls out of the least-squares lesson, but interpreting it as a projection is what makes the rest of the curriculum (ridge, LASSO, GLMs, calibration) click into place.

The model

Given nn examples with feature vectors xi∈Rdx_i \in \mathbb{R}^d and targets yi∈Ry_i \in \mathbb{R}, the linear regression model assumes

yi=xi⊤β+εi,y_i = x_i^\top \beta + \varepsilon_i,

where β∈Rd\beta \in \mathbb{R}^d are the unknown coefficients and εi\varepsilon_i is zero-mean noise. Stacking rows, write X∈Rn×dX \in \mathbb{R}^{n \times d} for the design matrix and y∈Rn\mathbf{y} \in \mathbb{R}^n for the target vector; the model is

y=Xβ+ε.\mathbf{y} = X\beta + \boldsymbol\varepsilon.

A column of ones in XX absorbs the intercept, so the formulas below cover the intercept case without extra notation.

The OLS objective

Ordinary least squares (OLS) picks the coefficients that minimize the sum of squared residuals:

β^=arg⁡min⁡β  ∥y−Xβ∥22.\hat\beta = \arg\min_\beta\; \lVert \mathbf{y} - X\beta \rVert_2^2.

Squared error is convex in β\beta (Hessian 2X⊤X⪰02X^\top X \succeq 0), so the minimum is wherever the gradient vanishes.

The normal equations

Differentiating with respect to β\beta using matrix calculus,

∇β ∥y−Xβ∥2=−2X⊤(y−Xβ).\nabla_\beta\, \lVert \mathbf{y} - X\beta \rVert^2 = -2 X^\top(\mathbf{y} - X\beta).

Setting it to zero gives the normal equations

X⊤X β^=X⊤y.X^\top X\, \hat\beta = X^\top \mathbf{y}. [1]

When XX has full column rank, X⊤XX^\top X is invertible and

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

If columns of XX are collinear, X⊤XX^\top X is singular and the minimizer is not unique; that is the gap ridge regression will close.

Geometric reading: projection onto the column space

The fitted values are y^=Xβ^\hat{\mathbf{y}} = X\hat\beta. Substituting,

y^=X(X⊤X)−1X⊤y=P y,\hat{\mathbf{y}} = X(X^\top X)^{-1} X^\top \mathbf{y} = P\,\mathbf{y},

where P=X(X⊤X)−1X⊤P = X(X^\top X)^{-1}X^\top is the projection matrix onto the column space of XX (idempotent, P2=PP^2 = P, and symmetric)[2]. The residual r=y−y^\mathbf{r} = \mathbf{y} - \hat{\mathbf{y}} lives in the orthogonal complement: X⊤r=0X^\top \mathbf{r} = 0 (this is exactly the normal equations rewritten).

The geometric picture: y^\hat{\mathbf{y}} is the closest point in col⁡(X)\operatorname{col}(X) to y\mathbf{y}, and OLS is least-squares projection. The whole rest of the lesson chain is a refinement of this picture.

Numerical route

Forming X⊤XX^\top X squares the condition number; the conditioning lesson explains why. The numerically stable route uses the QR factorization X=QRX = QR:

β^=R−1Q⊤y,\hat\beta = R^{-1} Q^\top \mathbf{y},

solved by back-substitution. Production code uses QR (numpy's lstsq) or the SVD, not the explicit inverse.

Ordinary least squares fits the line that minimizes the sum of squared residuals: the vertical gaps from each point to the line.
Ordinary least squares fits the line that minimizes the sum of squared residuals: the vertical gaps from each point to the line.

Check it on arrays

python · numpy
import numpy as np

rng = np.random.default_rng(0)
n, d = 200, 4
X = rng.normal(size=(n, d))
X[:, 0] = 1.0                                  # intercept
beta_true = np.array([2.0, -1.5, 0.7, 0.3])
y = X @ beta_true + 0.2 * rng.normal(size=n)

# Closed form via the normal equations
beta_normal = np.linalg.solve(X.T @ X, X.T @ y)
print("normal-eq beta:", np.round(beta_normal, 4))

# Stable route: QR factorization
Q, R = np.linalg.qr(X)
beta_qr = np.linalg.solve(R, Q.T @ y)
print("QR beta:       ", np.round(beta_qr, 4))

# Reference: numpy's least-squares solver (SVD-based)
beta_lstsq, *_ = np.linalg.lstsq(X, y, rcond=None)
print("lstsq beta:    ", np.round(beta_lstsq, 4))
print("agree?", np.allclose(beta_qr, beta_lstsq))

# Residuals are orthogonal to every column of X
y_hat = X @ beta_qr
r = y - y_hat
print("X^T r (should be ~0):", np.round(X.T @ r, 6))

# Projection matrix: P y == y_hat, and P^2 == P
P = X @ np.linalg.solve(X.T @ X, X.T)
print("P y == y_hat:", np.allclose(P @ y, y_hat))
print("P^2 == P:    ", np.allclose(P @ P, P, atol=1e-10))

The three routes recover the same β^\hat\beta, the residual is numerically orthogonal to every feature column, and PP is idempotent.

Exercises

Exercise 1. Fit OLS by hand for a single feature with no intercept. Given the three points (x,y)=(1,2),(2,2),(3,4)(x, y) = (1, 2), (2, 2), (3, 4) and the model y=βxy = \beta x (scalar β\beta, design matrix X=(1,2,3)⊤X = (1, 2, 3)^\top), solve the normal equation X⊤X β^=X⊤yX^\top X\,\hat\beta = X^\top \mathbf{y} for β^\hat\beta.

Solution

Step 1. Compute the two scalars in the normal equation. With X=(1,2,3)⊤X = (1, 2, 3)^\top and y=(2,2,4)⊤\mathbf{y} = (2, 2, 4)^\top,

X⊤X=12+22+32=14,X⊤y=1⋅2+2⋅2+3⋅4=18.X^\top X = 1^2 + 2^2 + 3^2 = 14, \qquad X^\top \mathbf{y} = 1\cdot 2 + 2\cdot 2 + 3\cdot 4 = 18.

Step 2. Solve the scalar normal equation 14 β^=1814\,\hat\beta = 18:

β^=1814=97≈1.2857.\hat\beta = \frac{18}{14} = \frac{9}{7} \approx 1.2857.

The fitted line y=97xy = \tfrac97 x minimizes the squared vertical gaps; no other slope through the origin does better on these three points.

Exercise 2. Prove that the OLS residual r=y−Xβ^\mathbf{r} = \mathbf{y} - X\hat\beta is orthogonal to the column space of XX, i.e. X⊤r=0X^\top \mathbf{r} = 0, directly from the normal equations.

Solution

Step 1. Start from the normal equations X⊤X β^=X⊤yX^\top X\,\hat\beta = X^\top \mathbf{y}, which hold at the OLS minimizer by definition.

Step 2. Move both terms to one side and factor out X⊤X^\top:

X⊤y−X⊤X β^=X⊤(y−Xβ^)=X⊤r.X^\top \mathbf{y} - X^\top X\,\hat\beta = X^\top(\mathbf{y} - X\hat\beta) = X^\top \mathbf{r}.

Step 3. The left side is zero by the normal equations, so X⊤r=0X^\top \mathbf{r} = 0. Each entry (X⊤r)j=x⋅j⊤r(X^\top \mathbf{r})_j = x_{\cdot j}^\top \mathbf{r} is the inner product of feature column jj with the residual, so the residual is orthogonal to every column, hence to all of col⁡(X)\operatorname{col}(X). This is the geometric statement that y^\hat{\mathbf{y}} is the projection of y\mathbf{y}.

Exercise 3 (code). A rank-deficient XX breaks the explicit inverse but not the SVD-based solver. Build a design matrix whose third column is an exact copy of its second, then show that np.linalg.solve(X.T @ X, ...) fails (singular matrix) while np.linalg.lstsq still returns a valid least-squares fit, and verify that its residual is orthogonal to the columns of XX.

Solution
python · numpy
import numpy as np

rng = np.random.default_rng(0)
n = 50
X = rng.normal(size=(n, 3))
X[:, 2] = X[:, 1]                          # column 3 duplicates column 2: rank 2
beta_true = np.array([1.0, 2.0, -0.5])
y = X @ beta_true + 0.1 * rng.normal(size=n)

# Explicit normal-equation solve fails: X^T X is singular.
singular = False
try:
    np.linalg.solve(X.T @ X, X.T @ y)
except np.linalg.LinAlgError:
    singular = True
assert singular                            # X^T X is not invertible

# lstsq (SVD) returns the minimum-norm least-squares solution regardless.
beta_hat, *_ = np.linalg.lstsq(X, y, rcond=None)
r = y - X @ beta_hat
assert np.allclose(X.T @ r, 0.0, atol=1e-8)   # residual still orthogonal
print("residual orthogonal, max |X^T r| =", round(np.abs(X.T @ r).max(), 10))

The collinear column makes X⊤XX^\top X singular, so the explicit solve raises LinAlgError. The SVD-based lstsq sidesteps the inverse and still returns a β^\hat\beta whose residual is orthogonal to the column space, the defining property of a least-squares fit.

The next lesson asks where this estimator comes from probabilistically: it is the MLE under Gaussian noise.


References

  1. [1]Hastie, T., Tibshirani, R., & Friedman, J. (2009). The Elements of Statistical Learning (2nd ed.), §3.2. Springer. doi:10.1007/978-0-387-84858-7↩
  2. [2]James, G., Witten, D., Hastie, T., & Tibshirani, R. (2021). An Introduction to Statistical Learning (2nd ed.), §3.1. Springer. The projection/geometry reading of least squares.↩