Supervised · regression Least squares · Legendre 1805 · Gauss 1809

Linear
regression

Draw a straight line through a cloud of points so that the total squared vertical distance from the points to the line is as small as it can possibly be. That is the entire idea. Everything below is consequence, machinery, and caution.

It is the first model most people learn, the baseline every serious project starts from, and — as a single artificial neuron with no activation function — the smallest piece of a neural network.

The model

ŷ = β0 + β1x1 + ⋯ + βpxp

A weighted sum of the inputs, plus a constant. Learning means choosing the β's. Prediction means plugging in x and doing arithmetic.

Move the line. Watch the error.

Drag either endpoint. The amber line is your model; the vermilion sticks are residuals — the gap between what happened and what the line predicts. Least squares finds the one line that makes the sum of their squares smallest.

x — hours studied y — exam score
your line residual (y − ŷ) observation least-squares optimum
Current line
ŷ = 0.00 + 0.00x
Sum of squared errors

The dashed line marks the optimum. No line you can draw will beat it on this data — that is what least squares guarantees.

01Anatomy

Every symbol, named

Single feature

y = β0 + β1x + ε
y
Target. The number you want to predict. Continuous — price, temperature, score.
x
Feature. The input. Also called predictor, covariate, independent variable.
β₀
Intercept / bias. Prediction when every feature is zero. Often meaningless alone — it anchors the line vertically.
β₁
Coefficient / weight. Expected change in y per one-unit increase in x, everything else held fixed.
ε
Irreducible error. Everything the features cannot explain. Assumed random, mean zero.
ŷ
Prediction. What the fitted model outputs — the line's height at that x.

Many features — matrix form

y = Xβ + ε

Past one input, stacking into matrices is the only sane notation — and it's exactly how the code runs.

X
Design matrix, n × (p+1). One row per observation, one column per feature, plus a leading column of 1s so the intercept falls out of the same multiplication.
β
Column vector of p+1 weights — the only thing being learned.
n, p
Observations, features. When p ≥ n, ordinary least squares breaks down and you must regularize.
"Linear" refers to the parameters, not the picture. y = β₀ + β₁x + β₂x² is still linear regression — it's linear in β. Bend the curve as much as you like, as long as the weights enter additively.
02The objective

What "best fit" optimizes

Fitting is a minimization problem. Define a number that measures how wrong the model is, then search for the weights that make it smallest. Here that number is the sum of squared residuals.

Cost function

SSE = ∑i=1n (yiŷi
MSE = 1n ∑ (yiŷi

Same minimum, different scale. MSE is the average; RMSE is its square root and reads in the units of y.

Why squared

  • Signs cancel otherwise. Raw errors sum to roughly zero for any sensible line.
  • Smooth and convex. Differentiable everywhere, one global minimum, no local traps.
  • Closed-form solution exists. Absolute error gives you none.
  • Maximum likelihood under Gaussian noise. If errors are normal, least squares is the most likely explanation.
The cost: squaring makes one point that misses by 10 count as much as a hundred that miss by 1. Outliers dominate the fit. If that's a problem, change the loss — Huber or absolute error.

The loss surface

Plot cost against the two parameters and you get a bowl. Convex, one bottom. Every fitting method is a different way of reaching it.

Contours of squared error over (intercept, slope) · path shows gradient descent steps
03Two solvers

Closed form vs. gradient descent

Linear regression is unusual: it has an exact algebraic answer. Most models don't. Learn both routes — the iterative one generalizes to everything else in machine learning.

Normal equation — solve directly

β̂ = (XX)−1Xy

Set the derivative of SSE to zero and solve. One shot, no tuning, exact.

  • No learning rate, no iterations, no convergence worry
  • Roughly O(p³) — painful past a few thousand features
  • Fails when XᵀX is singular: perfectly correlated features, or p > n
  • Real libraries use QR or SVD rather than literally inverting

Gradient descent — walk downhill

ββαβMSE
∇ = −2n X(y)

Start anywhere, step against the gradient until the cost stops improving.

  • Scales to millions of rows and features; works in mini-batches and streaming
  • Needs a learning rate α — too big diverges, too small crawls
  • Requires feature scaling, or the bowl becomes a ravine and progress zig-zags
  • The same algorithm that trains every neural network
VariantUpdate usesCharacter
Batch GDAll n rows per stepSmooth, stable, slow on big data
Stochastic GDOne row per stepNoisy path, very fast, needs decaying α
Mini-batch GD32–512 rows per stepThe practical default everywhere
04Evaluation

How good is the fit?

MetricDefinitionRead it as
1 − SSE / SSTFraction of variance explained. 1 = perfect, 0 = no better than predicting the mean, negative = worse than the mean.
Adjusted R²Penalizes extra featuresUse when comparing models with different feature counts — plain R² never decreases when you add a feature, even a random one.
RMSE√(SSE / n)Typical error in the units of y. Punishes large misses. The usual headline number.
MAEmean |y − ŷ|Typical error, outlier-tolerant. Report next to RMSE — a big gap between them signals outliers.
MAPEmean |y − ŷ| / |y|Percentage error. Convenient for business, explodes when y is near zero.
p-values, CIsPer-coefficient inferenceIs this weight distinguishable from zero? Statistics cares deeply; pure prediction work often ignores them.
Any metric computed on training data is a self-assessment. Hold out data or cross-validate. A model scoring 0.98 on data it has already seen tells you nothing about tomorrow.

Residual plots say more than R²

Plot residuals against predicted values. You want structureless noise. Any pattern is the model telling you what it failed to capture.

Healthy — no pattern

Constant spread, centred on zero. Nothing left to model.

Funnel — heteroscedasticity

Error grows with the prediction. Try log(y), or weighted least squares.

Curve — wrong functional form

A straight line can't reach the bend. Add polynomial or interaction terms.

05Assumptions

Five conditions, and what breaks without them

These matter most when you want to interpret coefficients or quote confidence intervals. For raw prediction accuracy, violations are less fatal — but they still usually mean a better model exists.

AssumptionMeaningDetectFix
LinearityThe relationship really is a weighted sumResiduals vs fitted; partial plotsTransform features, add polynomial or interaction terms, switch model
IndependenceObservations don't influence each otherDurbin–Watson; residuals in time orderTime-series models, mixed effects, clustered errors
HomoscedasticityError spread is constant across predictionsFunnel shape; Breusch–PaganLog-transform y, weighted least squares, robust standard errors
Normality of εErrors are GaussianQ–Q plot of residualsOnly affects inference; large n makes it largely moot
No multicollinearityFeatures aren't near-duplicatesCorrelation matrix; VIF above ~5–10Drop or combine features, use PCA, use Ridge
Multicollinearity is the subtle one. Predictions stay fine, but coefficients become unstable and untrustworthy — the model can't tell which of two twin features deserves the credit, so it splits it arbitrarily and signs may even flip. If your story depends on the coefficients, check this first.
06Regularization

Shrinking the weights on purpose

Add a penalty on coefficient size to the cost. The model trades a little training accuracy for weights that don't swing wildly — usually better performance on data it hasn't seen. The bias–variance tradeoff, made into a dial.

Ridge · L2

SSE + λβj²

Shrinks all coefficients smoothly toward zero, never exactly to zero. Handles correlated features gracefully by splitting weight between them. Keeps the closed form and fixes singular XᵀX.

Lasso · L1

SSE + λ ∑ |βj|

Drives some coefficients to exactly zero — automatic feature selection. Sparse, readable models. With correlated features it arbitrarily picks one and discards the rest.

Elastic Net

SSE + λ1∑|β| + λ2β²

Both penalties. Sparsity from L1, stability from L2. The default when you have many correlated features and want selection anyway.

Why L1 zeroes things out

The penalty defines a region the coefficients must stay inside. Cost contours grow outward from the unpenalized solution until they touch that region — and where they touch is the answer.

L2's region is a circle, so contact happens almost anywhere. L1's is a diamond with corners on the axes — and expanding ellipses hit corners first. A corner means a coefficient of exactly zero.

Always scale features before regularizing. The penalty applies to raw coefficient magnitudes, so a feature in metres is punished a thousand times harder than the same feature in millimetres. Never penalize the intercept.

Choosing λ: cross-validate over a logarithmic grid. λ = 0 is plain OLS; as λ → ∞ every coefficient collapses to zero and the model predicts the mean. The sweet spot is empirical.

07Fit quality

Underfit, right, overfit

Same data, three models. The middle one is the goal — and you can only identify it with data the model never trained on.

Underfit · high bias

Too rigid to follow the signal. Poor on training and test. Add features or complexity.

Balanced

Follows the trend, ignores the noise. Training and test scores are close and both decent.

Overfit · high variance

Memorized the noise. Near-perfect on training, bad on test. Regularize or simplify.

Diagnostic shortcut: a large gap between training and validation score is a variance problem — regularize, get more data, cut features. Both scores poor is a bias problem — more expressive model, better features.

08Preparation

Getting data ready

Scaling

Standardize (mean 0, sd 1) or min–max normalize. Mandatory for gradient descent and any regularized fit; irrelevant for the plain normal equation. Fit the scaler on training data only, then apply it to the rest.

Categorical features

One-hot encode, dropping one level to avoid the dummy-variable trap. For high-cardinality categories consider target encoding — carefully, with cross-fitting, or it leaks.

Missing values

Impute with median or a model, and add a binary "was missing" indicator — absence often carries signal. Dropping rows quietly biases the sample.

Transforming the target

Right-skewed targets (income, price, counts) often behave far better as log(y). Exponentiate predictions back, and note that coefficients then read as approximate percentage changes.

Outliers & leverage

Squared loss makes single points powerful. A high-leverage point — extreme in x — can pivot the whole line. Check Cook's distance; investigate before deleting.

Leakage

The most common way a great model turns out worthless. If a feature encodes information unavailable at prediction time, R² looks spectacular and the model fails in production.

09The family

Extensions and close relatives

ModelWhat changesUse when
PolynomialAdd x², x³ … as featuresCurved relationship, still fit by least squares
InteractionsAdd x₁·x₂ termsOne feature's effect depends on another's value
Splines / GAMPiecewise smooth basis functionsFlexible curves with interpretability intact
LogisticSigmoid output, log-lossBinary classification — same linear core
PoissonLog link, count distributionCounts and rates
HuberSquared near zero, absolute in the tailsOutliers you can't remove
QuantilePinball lossYou want the median or the 90th percentile, not the mean
Bayesian linearPriors on β, posterior distributionSmall data, or you need honest uncertainty
PLS / PCRRegress on componentsMany highly correlated features
10Where it sits

Its role in machine learning

Why it stays relevant

  • The baseline. Fit it first, always. If a gradient-boosted ensemble can't beat it meaningfully, the complexity isn't earning its keep.
  • Interpretable by construction. Each coefficient is a sentence: one more bedroom, £14,000 more. Regulated domains often require exactly this.
  • Cheap. Trains in milliseconds, predicts with a dot product, deploys anywhere, needs no GPU.
  • The atom of deep learning. A single neuron is a linear regression; an activation function is what makes stacking them worthwhile.
  • A teaching device. Loss functions, gradients, regularization, bias–variance, cross-validation — every ML concept appears here in its simplest form.

When to reach for something else

  • Genuinely non-linear relationship of unknown shape → gradient boosting, random forests
  • Complicated interactions you can't enumerate → tree ensembles find these automatically
  • Unstructured input: images, audio, text → neural networks
  • Very high dimension with strong correlation → regularized variants, or reduce dimensions first
  • Calibrated class probabilities → logistic regression or a probabilistic classifier
Rule of thumb: on small-to-medium tabular data with mostly additive effects, a well-prepared regularized linear model often lands within a few percent of anything fancier — and you can explain it to a stakeholder.
11In code

The whole workflow, minimally

# scikit-learn: pipeline keeps scaling inside cross-validation, so no leakage
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression, RidgeCV
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.metrics import mean_squared_error, r2_score
import numpy as np

X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.2, random_state=42)

# baseline
ols = LinearRegression().fit(X_tr, y_tr)

# regularized, with lambda chosen by cross-validation
model = make_pipeline(
    StandardScaler(),
    RidgeCV(alphas=np.logspace(-3, 3, 25)),
).fit(X_tr, y_tr)

pred = model.predict(X_te)
print("RMSE", mean_squared_error(y_te, pred, squared=False))
print("R2  ", r2_score(y_te, pred))
print("CV  ", cross_val_score(model, X_tr, y_tr, cv=5, scoring="r2").mean())

# read the model: coefficients compare only because features were scaled
coefs = model[-1].coef_
for name, w in sorted(zip(feature_names, coefs), key=lambda t: -abs(t[1])):
    print(f"{name:>22}  {w:+.3f}")

Use statsmodels.OLS when you want the inference table — standard errors, t-statistics, p-values, confidence intervals, diagnostics. scikit-learn is built for prediction; statsmodels is built for explanation.

12Pitfalls

Mistakes that look like success

Reading coefficients as causes. A coefficient is an association within this dataset, under this set of controls. Ice cream sales predict drownings. Nothing in the arithmetic separates correlation from causation.
Chasing R². It rises every time you add a feature, including pure noise. Compare on held-out data, or use adjusted R².
Scaling before splitting. Test-set statistics leak into training. Split first, fit the scaler on train, transform the rest.
Extrapolating. The line continues forever; the data doesn't. Predictions far outside the observed range of x are unsupported guesses.
Ignoring the residual plot. Two datasets with identical R², slope and means can look completely different — Anscombe's quartet exists to make this point. Always look at the picture.
Dummy-variable trap. One-hot encoding every level plus an intercept creates perfect collinearity. Drop a level.
Random splits on time-series data. Shuffling lets the model see the future. Split chronologically.
Skipping the plain model. If you never fit OLS first, you have no idea whether your ensemble adds value.
13Learning path

An order that works

StepDo thisYou'll know it when
1Fit a one-feature model by hand: compute slope and intercept from the formulasThe numbers match what sklearn returns
2Implement least squares in NumPy — normal equation first, then gradient descentBoth converge to the same β
3Plot cost against iterations for three learning ratesYou recognize divergence, crawling, and healthy descent on sight
4Take a real dataset. Full loop: EDA, split, scale, fit, residual plots, metricsYour residual plot is structureless
5Add Ridge and Lasso, sweep λ, plot the coefficient pathsYou can watch coefficients shrink and, under L1, hit zero
6Deliberately break an assumption and observe the damageYou can diagnose the problem from the residuals alone
7Move to logistic regressionYou can explain what changed: the link function and the loss, not the linear core

The one-paragraph summary

Linear regression predicts a continuous number as a weighted sum of inputs. Fitting means choosing weights that minimize squared error, either by solving a matrix equation directly or by walking downhill on the loss surface. Evaluate on held-out data with RMSE and R², and always look at the residuals. Add an L1 or L2 penalty when you have many features or limited data. Its assumptions govern how far you can trust the coefficients as explanations. It is simultaneously the simplest useful model in machine learning, the baseline everything else must beat, and the single neuron that deep learning is built from.