Linear regression
Least squares three ways: algebra, geometry and probability
Linear regression is the first model you can derive completely — closed form, gradient descent and maximum likelihood all give the same answer — and the last model you will ever fully understand. It is also a single neural-network layer with no activation (4.1 From perceptron to MLP; universal approximation), the inner loop of ridge regression (3.6 Regularization and generalization) and LoRA (8.2 Fine-tuning and PEFT), and the "linear probe" used to read concepts out of LLM activations (8.11 Interpretability: what is happening inside). Every derivation here is reused.
You'll be able to
- Write the linear model in matrix form and derive the normal equations from the gradient of the MSE
- Explain least squares as projection onto the column space of X and read the orthogonality condition
- Derive the gradient-descent update, state when it converges, and explain why feature scaling speeds it up
- Show that MSE is maximum likelihood under Gaussian noise and say what that assumption implies
- Extend the model with polynomial/basis features and diagnose a fit with residual plots and R²
- Implement the closed form and gradient descent in NumPy and check them against scikit-learn
Key ideas
- Linear regression predicts ŷ = Xw; the MSE is a convex quadratic bowl with a unique minimum when X has full column rank.
- Setting the gradient (2/n) Xᵀ(Xw − y) to zero gives the normal equations XᵀX w = Xᵀy; solve with lstsq, never with an explicit inverse.
- Geometrically, ŷ is the projection of y onto the column space of X; residuals are orthogonal to every feature and sum to zero.
Show 5 more key ideas
- Gradient descent converges on this problem for η < 2/λ_max; standardizing features makes the bowl round and descent fast.
- MSE is maximum likelihood under Gaussian noise; heavy-tailed noise calls for MAE or Huber loss.
- Linear means linear in the parameters: polynomial and basis features keep the math and add capacity.
- Diagnose fits with residual plots and report RMSE in the target's units next to R² = 1 − SSE/SST.
- The gradient form Xᵀ(ŷ − y) is reused unchanged by logistic regression and by every neural network's output layer.
Suggested path through this lesson
The model and the loss
A linear model predicts a number as a weighted sum of features plus an offset:
Absorb the bias by appending a constant feature , so with . Stacking the training inputs as rows of the design matrix and the targets as , all predictions at once are (1.2 Matrices as transformations). The loss is the mean squared error,
a convex quadratic bowl in : it has exactly one minimum (when has full column rank), which is why three different methods must agree.
Way 1 — algebra: the normal equations
Expand the loss: . Using the identities for symmetric and (1.5 Multivariable and matrix calculus):
Setting the gradient to zero gives the normal equations and their solution:
is a matrix; it is invertible exactly when the columns of are linearly independent (no feature is a combination of others, and ). Forming and solving costs — instant for in the hundreds, impossible for in the millions. In code, never invert: np.linalg.lstsq(X, y) or np.linalg.solve(X.T @ X, X.T @ y) is more stable, and when columns are nearly collinear the SVD-based solver (or ridge, 3.6 Regularization and generalization) is the right tool (1.3 Eigen-things, SVD and low rank).
Way 2 — geometry: projection
ranges over the column space of — the set of all vectors that are linear combinations of the feature columns, a -dimensional flat inside . Least squares asks for the point of that flat closest to : its orthogonal projection. Closest means the residual is perpendicular to every column of :
which is the normal equations again. Two consequences you can check on any fit: because the constant column is in , the residuals sum to exactly zero; and the residuals are uncorrelated with every feature — if a residual plot shows a pattern against a feature, you need a transform of that feature, not the feature itself. The projection is linear in : with the hat matrix , a projection () whose diagonal entries measure each point's leverage (1.1 Vectors, dot products and norms for projections).
Worked example
Three points : . With a constant column, , .
So . Predictions , residuals — they sum to zero as promised. The sum of squared residuals is ; the total sum of squares around is ; so
the line explains 75% of the variance of .
Way 3 — gradient descent
For large or streaming data, iterate instead of solving (1.10 Optimization: from gradient descent to Adam):
Because is a convex quadratic, gradient descent converges to whenever , where is the largest eigenvalue of the Hessian (1.3 Eigen-things, SVD and low rank). The speed is governed by the ratio : a feature measured in millimetres next to one measured in kilometres makes the bowl a long narrow valley, and the iterates zig-zag. Standardizing features (subtract mean, divide by standard deviation) makes the bowl nearly round and lets you use a much larger step. Mini-batch SGD uses a random subset per step; its gradient is an unbiased estimate of the full gradient, which is all the theory needs (4.5 Optimizers and learning-rate schedules). The interactive demo lets you watch exactly this: add points, start descent, and see the path and the loss curve — then compare with the closed form.
Why squared error? Maximum likelihood
Assume the data were generated by a line plus Gaussian noise: , independently. Then and the log-likelihood of the dataset is
The first term does not depend on , so maximizing the likelihood (1.7 Probability II: Bayes, independence, MLE and MAP) is exactly minimizing the sum of squared errors. This tells you what MSE assumes: symmetric, light-tailed, constant-variance noise. When outliers are common (heavy tails), the Gaussian assumption is wrong and the squared loss lets a few points dominate; the MLE under Laplace noise is the absolute error, and the Huber loss interpolates (4.3 Loss functions catalog). The same recipe — write a likelihood, take the negative log — produces every loss function in this path (1.9 Information theory: entropy, cross-entropy and KL divergence, 3.3 Logistic regression and softmax classification).
Beyond straight lines, and reading a fit
"Linear" means linear in the parameters, not in the inputs. Replace by features — powers , interactions , logs, splines, or the output of a pretrained network — and everything above still holds with replaced by . Polynomial degree is the capacity knob from 3.1 What is learning? ERM, generalization and the ML workflow: degree 1 underfits a curve, degree 15 memorizes noise; 3.6 Regularization and generalization shows how to keep high degree and control the damage.
Diagnostics in three plots: predicted vs actual (should hug the diagonal), residuals vs predicted (should be a structureless band — a curve means a missing nonlinearity, a funnel means non-constant variance), and a histogram of residuals (roughly symmetric). Report RMSE in the units of alongside ; alone can be high on a useless model with a huge spread of , and it never decreases when you add features, which is why the adjusted version penalizes . Coefficients are comparable only when features are on the same scale.
import numpy as np
from sklearn.linear_model import LinearRegression
Xb = np.c_[np.ones(len(X)), X] # add the constant column
w_closed, *_ = np.linalg.lstsq(Xb, y, rcond=None) # normal equations, stably
w = np.zeros(Xb.shape[1]); lr = 0.1
for _ in range(2000): # gradient descent
w -= lr * (2 / len(y)) * Xb.T @ (Xb @ w - y)
model = LinearRegression().fit(X, y) # scikit-learn
np.allclose(w_closed[1:], model.coef_), np.allclose(w, w_closed, atol=1e-4)
Where this shows up later
- A linear layer with no activation is this model; stack them with nonlinearities and you have an MLP — 4.1 From perceptron to MLP; universal approximation; the same gradient reappears for logistic regression — 3.3 Logistic regression and softmax classification.
- Add and the normal equations become ridge — 3.6 Regularization and generalization; the SVD view of the inverse explains why collinearity hurts — 1.3 Eigen-things, SVD and low rank.
- MSE-as-Gaussian-MLE is the template for every loss — 4.3 Loss functions catalog; residual analysis is error analysis — 3.14 Project: end-to-end tabular ML with scikit-learn.
- Linear probes on LLM activations are linear regressions/classifiers — 8.11 Interpretability: what is happening inside; the LoRA update is a low-rank linear map — 8.2 Fine-tuning and PEFT.
Common pitfalls (5)
- Inverting XᵀX explicitly; it is numerically fragile and fails outright with collinear features — use lstsq or ridge.
- Running gradient descent on unscaled features with a single learning rate: it either diverges or crawls.
- Interpreting coefficient magnitudes as feature importance when features are on different scales.
- Trusting a high R² without looking at residual plots; R² never decreases when you add junk features.
- Using squared error on data with heavy outliers, letting a handful of points dictate the fit.
Recap: all 8 key points
- Linear regression predicts ŷ = Xw; the MSE is a convex quadratic bowl with a unique minimum when X has full column rank.
- Setting the gradient (2/n) Xᵀ(Xw − y) to zero gives the normal equations XᵀX w = Xᵀy; solve with lstsq, never with an explicit inverse.
- Geometrically, ŷ is the projection of y onto the column space of X; residuals are orthogonal to every feature and sum to zero.
- Gradient descent converges on this problem for η < 2/λ_max; standardizing features makes the bowl round and descent fast.
- MSE is maximum likelihood under Gaussian noise; heavy-tailed noise calls for MAE or Huber loss.
- Linear means linear in the parameters: polynomial and basis features keep the math and add capacity.
- Diagnose fits with residual plots and report RMSE in the target's units next to R² = 1 − SSE/SST.
- The gradient form Xᵀ(ŷ − y) is reused unchanged by logistic regression and by every neural network's output layer.
Watch
Least squares, R² and the intuition behind fitting a line.
Read
Try it live
Interactive demo
runs in your browserExercises
- Reproduce the worked example
Redo the three-point fit by hand (normal equations, predictions, residuals, SSE, SST, ), then confirm with
np.linalg.lstsq. Expected: , residuals summing to 0, . - Three solvers, one answer
Generate , data with known weights and Gaussian noise. Fit by (a) lstsq, (b) your own gradient descent on standardized features, (c)
LinearRegression. Expected: all three agree to 1e-3; then rerun (b) on unscaled features where one column is multiplied by 1000 and watch the learning rate that worked before diverge. - Residual diagnostics
Fit a line to on and plot residuals vs predicted. Then add an feature and repeat. Expected: the first residual plot shows a clear U-shape; the second is a structureless band.
- Outliers and the loss
Add three gross outliers to a clean linear dataset. Fit with squared error and with
sklearn.linear_model.HuberRegressor. Expected: the Huber fit stays near the true line while least squares tilts toward the outliers; explain which noise assumption each loss encodes.
Quiz
Flashcards
These cards are now in your spaced-repetition queue. Review all due cards →