Master the foundational algorithm of machine learning. Learn to predict continuous values with linear models, optimize using gradient descent, handle multiple features with matrix operations, and prevent overfitting with L1/L2 regularization.
Linear regression is arguably the most important algorithm to understand deeply. Not because it's the most powerful—it's not—but because it introduces nearly every concept you'll need for more complex models: loss functions, optimization, overfitting, regularization, and the bias-variance tradeoff.
The core idea is beautifully simple: model the relationship between inputs and outputs as a weighted sum plus a bias term. The weights tell us how much each feature contributes to the prediction. The challenge is finding the optimal weights—those that minimize the prediction errors.
For simple problems, we can solve for optimal weights analytically using calculus. But this approach doesn't scale. Gradient descent provides an iterative alternative: start with random weights, compute how the loss changes with small weight adjustments (the gradient), then nudge weights in the direction that decreases loss. Repeat until convergence.
Real problems have many features interacting in complex ways. Multiple regression extends the model to handle this, fitting a hyperplane in high-dimensional space. The normal equation gives a closed-form solution, but gradient descent is more practical for large datasets.
Regularization addresses a critical problem: models can fit training data too well, capturing noise rather than signal. By penalizing large weights, L2 (Ridge) regularization shrinks coefficients toward zero, while L1 (Lasso) can eliminate features entirely. This tradeoff between fitting the data and keeping the model simple is fundamental to all of machine learning.
This chapter covers:
Click any topic to jump in
The starting point — fit a line through data by minimizing squared errors with a closed-form solution.
Optimization for large data and extending to multiple features
Iterative optimization when closed-form solutions don't scale — follow the negative gradient to minimize loss.
Extend to many features with matrix notation, the normal equation, and feature scaling for stable training.
Nonlinear patterns and controlling model complexity
Capture nonlinear patterns while staying inside the linear regression framework via feature transformations.
Prevent overfitting by penalizing large weights — L1 for sparsity, L2 for shrinkage, Elastic Net for both.
When linear regression is appropriate and how to verify — residual analysis, influential points, and model checks.
You have two columns of numbers — house size and sale price, study hours and exam score — and you are asked what the second column would be for a value of the first that nobody recorded. Looking it up is impossible; you have to invent a rule that turns any input into a plausible output, and fit that rule to the data you do have.
That rule is a model: a formula containing a few unknown numbers called parameters. Choosing them from data is fitting, and "best fit" only means something once you define a loss — one number saying how wrong the model currently is. Chapter 1's Introduction to Machine Learning named these words; this is the first topic where you see all of them made concrete on a model you can solve by hand.
The arc follows the order you would actually derive it. We write down the straight-line model, define the residual (one point's error), average the squared residuals into MSE, defend the squaring, solve for the parameters exactly with calculus, and close with — the score that says whether fitting the line was worth it at all.
Simple linear regression models a numeric target as an affine function of one numeric input , , choosing the parameters and to minimise the mean squared error between predictions and observations. Because that objective is a convex quadratic, the minimiser is unique and available in closed form — no iterative search needed.
Without a model you can only repeat values you have already observed. A model is a formula with unknown numbers. Here is the single input feature and — "y-hat" — is the predicted output, hatted to separate it from an observed . The parameters and are what we choose: the intercept is the prediction at , the slope is how far moves per one-unit increase in . This is chapter 0's in ML notation. Its assumption is strong: if the truth curves, no repairs it and the leftover errors are systematic, not random.
The model defines an affine mapping from input space to output space . The parameter is the rate of change , meaning each unit increase in shifts the prediction by exactly . The intercept anchors the line at . With data points, we have 2 free parameters and constraints — the system is overdetermined when , which is why we need a loss function to define "best fit" rather than exact interpolation.
Model: ŷ = 50 + 10x. What's the prediction when x=3?
A model can only be fitted if you can measure how wrong it is at each point; the residual is that per-point measurement. For training example , is the observed target, is what the line predicts at that example's input, and is the signed vertical gap: positive means the model underpredicted, negative means it overpredicted. Residuals are not properties of the data: move the line and every changes, which is what fitting exploits. They measure vertical error only, so is assumed noise-free; residuals that curve or fan out warn that the linear model above is the wrong shape.
The residual measures the signed vertical distance from observation to the fitted line. For the OLS estimator, and — these are the normal equations. The first says residuals balance out on average; the second says residuals are uncorrelated with the predictor. Together, these two conditions uniquely determine and . Violations of these orthogonality conditions indicate the model has not converged or was computed incorrectly.
Actual y=100, predicted ŷ=85. What's the residual? Interpretation?
Residuals give numbers, but choosing parameters needs one number to minimise — and simply adding residuals fails, because positive and negative misses cancel and a terrible line can total zero. Squaring destroys the signs, so the mean of the squared residuals over the training examples is zero only for a perfect fit. That number is the loss. Dividing by makes it per-example, so datasets of different sizes stay comparable. Its units are the square of 's units, which is why people report (RMSE) instead. The price of squaring is outlier sensitivity: one point ten units off costs as much as a hundred points one unit off.
MSE is a convex, differentiable function of the weights. Squaring amplifies large errors: an error of 4 contributes 16 to the sum, while four errors of 1 contribute only 4. This makes MSE sensitive to outliers — a single point far from the line can dominate the entire loss. Statistically, minimizing MSE is equivalent to maximum likelihood estimation when the noise , connecting the geometric idea of "closest line" to the probabilistic idea of "most likely parameters."
Residuals: [2, -3, 1, -2]. Calculate MSE.
Squaring residuals is a choice, not a law, with three defences. Probabilistic: assume every observation is the line plus independent noise , where is the noise variance. Each point's likelihood is proportional to , the dataset's likelihood is their product, and taking the logarithm turns that product into plus constants — so maximising likelihood is literally minimising MSE. Computational: is differentiable everywhere, while has a corner at zero. Behavioural: doubling an error quadruples its cost. That last is also the flaw — MSE estimates the conditional mean, so one outlier drags the line, whereas MAE estimates the median and shrugs.
The MSE loss surface is a paraboloid in parameter space — it has exactly one global minimum and no local minima. The Hessian matrix is positive semi-definite, guaranteeing convexity. The absolute error has a corner at zero where the derivative is undefined, making gradient-based optimization problematic. MSE's smoothness everywhere means the gradient exists at every point, providing a well-defined direction toward the optimum.
Why not use |error| (MAE) instead of error²?
Because MSE is a convex bowl in , its one flat point is the minimum: set both partial derivatives to zero and solve. Differentiating with respect to gives — residuals must sum to zero — which rearranges to , where and are sample means. Substituting back and differentiating with respect to produces the formula shown: the covariance over the variance of . It fails only when — every identical, so there is no slope to estimate; near-constant makes it numerically fragile.
Setting yields . This has a clean geometric interpretation: the slope equals the correlation coefficient times the ratio of standard deviations, . When features are perfectly correlated (), the line passes through every point. When , the slope is zero and the best prediction is just . The closed-form solution requires time for simple regression, making it efficient for small feature counts.
Cov(x,y) = 15, Var(x) = 5, x̄ = 10, ȳ = 25. Find the line.
MSE answers "how wrong?" in squared units of , so its value alone cannot say whether a fit is good. fixes that by comparing against the laziest model: ignore and always predict . The denominator is that baseline's squared error — the total variation in ; the numerator is what your line leaves. Their ratio is the fraction of baseline error still unexplained, so is the fraction removed: 0.8 means four fifths of the variation in is explained by . It goes negative when a model beats nothing, and never falls when you add a feature, even a useless one.
decomposes total variance into explained and unexplained parts: . For simple regression, — the square of the Pearson correlation. Adding features can only increase (or keep it the same), which is why adjusted penalizes model complexity by accounting for the number of parameters . A negative means the model fits worse than a horizontal line at .
SSres = 200, SStot = 1000. Calculate and interpret R².
Fitting by hand, and checking the two conditions the optimum must satisfy
import numpy as np
x = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
y = np.array([2.0, 4.0, 5.0, 4.0, 5.0])
xb, yb = x.mean(), y.mean()
w1 = np.sum((x - xb) * (y - yb)) / np.sum((x - xb) ** 2)
w0 = yb - w1 * xb
e = y - (w0 + w1 * x)
print(f"w0 = {w0:.4f} w1 = {w1:.4f}")
print(f"sum of residuals = {e.sum():.2e}")
print(f"sum of x_i * e_i = {np.dot(x, e):.2e}")
mse = lambda a, b: np.mean((y - (a + b * x)) ** 2)
print(f"MSE at optimum = {mse(w0, w1):.6f}")
for d in (-0.2, 0.2):
print(f"MSE at w1 {d:+.1f} = {mse(w0, w1 + d):.6f}")The same five points as the theory exercise, so you can check the hand arithmetic: it prints w0 = 2.2000 and w1 = 0.6000. The two sums come out at the 1e-16 level — not merely small. They are the stationarity conditions from the derivation, exact up to floating point. MSE at the optimum is 0.480000, and nudging the slope by either -0.2 or +0.2 raises it to 0.920000: moving away from the minimum costs you in both directions and by the same amount, which is what a symmetric convex bowl looks like numerically.
Outliers, negative R², and why R² never goes down
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score
rng = np.random.default_rng(1)
x = rng.uniform(0, 10, 60)
y = 2.0 * x + 1.0 + rng.normal(0, 1.0, 60)
X1 = x.reshape(-1, 1)
base = LinearRegression().fit(X1, y)
print(f"clean slope = {base.coef_[0]:.3f}")
y_out = y.copy(); y_out[x.argmax()] += 60.0 # corrupt the highest-x point
print(f"slope w/ 1 outlier = {LinearRegression().fit(X1, y_out).coef_[0]:.3f}")
X2 = np.column_stack([x, rng.normal(0, 1, 60)]) # add a pure-noise feature
fit2 = LinearRegression().fit(X2, y)
print(f"R2, 1 feature = {r2_score(y, base.predict(X1)):.6f}")
print(f"R2, + noise column = {r2_score(y, fit2.predict(X2)):.6f}")
print(f"R2 of always-zero = {r2_score(y, np.zeros_like(y)):.3f}")Three of the topic's claims, verified. The clean slope is 2.031, close to the true 2.0. Adding 60 to the single highest-x target drags it to 2.597 — one corrupted point in sixty, and the fit chases it. That is MSE's outlier sensitivity, and the point is corrupted at the edge of the x-range because leverage is highest there. Appending a column of pure random noise moves R² from 0.980120 to 0.980122: a rise in the sixth decimal, and never a fall, because the extra parameter can only reduce training error. That is exactly why later topics need adjusted R² and regularisation. The always-zero predictor scores -3.961, far below the mean baseline of 0.
Given data points (1,2), (2,4), (3,5), (4,4), (5,5), calculate the best-fit line using the closed-form solution.
Generate noisy data from y = 2.5x + 1 with a fixed seed, then implement simple linear regression from scratch using the closed-form (least-squares) formulas for slope and intercept. Verify your weights against sklearn's LinearRegression and report the R² of your fit.