← All tutorials

On this page

1 The linear model 2 The mean squared error cost 2.1 The gradient of the cost 2.2 The gradient descent update 2.3 The closed-form solution 3 Gradient descent on a 2D fit 4 Linear regression in practice 5 Failure modes of linear regression 6 Polynomial features and logistic regression 7 References

Linear Regression

Linear regression predicts a number, say a house price, as a weighted sum of features.

Features x1, x2size and bedrooms of one houseLinear modelprediction = w1·x1 + w2·x2 + bCost Javerage squared miss over all housesFind the best wgradient descent or the closed formFailure modesfar points, unscaled or twin featuresIn practicethe scikit-learn pipeline, cost and gotchas112245
Figure 1. Each box's marker is the number of the section that teaches it.

Gradient descent (Section 2.2) repeats one step over the whole data set, about two multiply-adds per feature per sample; the closed form (Section 2.3) solves once.

1 The linear model

For a house the features x1 and x2 are its size and bedrooms.

The prediction is a weighted sum of the features plus a constant shift.
ŷ = w1x1 + w2x2 + b
The prediction ŷ is the sum of each feature's value times its weight, shifted by the bias b. The weights w1 and w2, one per feature, say how much each feature moves the prediction, and b, also called the intercept, is the prediction when every feature is zero.

The Linear Regression notebook in the Machine-Learning-Concepts repo generates data from this model: 2,000 samples, weights 5 and 2, bias 2, no noise; its fit adds a small ridge penalty (0.01, Section 4) that the cost below leaves out.

2 The mean squared error cost

Training picks the weights and bias with the lowest cost J, the mean squared error.

The cost scores how wrong the current weights and bias are.
J = 12MΣi (ŷi − yi)²
The cost J is half the average, over all M samples, of the squared residual: Σ (sigma) means sum over every sample i, and ŷi minus yi is how far off we are on sample i, prediction minus truth. Squaring makes big misses hurt more than small ones while the sign stops mattering. The half, the 2 in 2M, is there so the slope comes out clean: squaring brings down a factor of 2 when you take the slope, and the half cancels it, which is why the gradient line divides by M alone.

Squared error suits noise that is bell-shaped (Gaussian) around the line; the Likelihood and EM page shows why.

costweight1gradient descent, many small stepsone matrix solve, one jump2
Figure 2. Gradient descent steps down the bowl from 1; one solve jumps to 2.

2.1 The gradient of the cost

This cost is convex: shaped like a bowl, with one minimum and no other. Walking downhill needs the slope, the gradient.

The gradient gives the slope of the cost along each weight.
∂J∂wj = 1MΣi (ŷi − yi) xij
For each weight wj, the slope is the average over samples of (how wrong we are) times (the feature value): the fraction is the partial slope, ∂ (the partial symbol) J over ∂ wj, how J changes when only that one weight moves, and Σ (sigma) means sum over every sample i. ŷi minus yi is how wrong we are on sample i, and xij is that sample's value of feature j. The sign does the steering: a negative residual with a positive feature gives a negative slope, so stepping against it pushes the weight up and shrinks the miss.

2.2 The gradient descent update

Gradient descent steps against the gradient, scaled by the learning rate, and repeats.

Gradient descent steps downhill, then repeats.
wj ← wj − lr · ∂J∂wj
The arrow means "gets replaced by", so wj becomes itself minus lr, the learning rate, times the slope, the partial slope ∂J over ∂wj from the gradient line, so every weight steps downhill at the same time, and the same update runs for the bias, with its own gradient. Raise lr and steps grow until they overshoot; lower it and the walk can stop short of the bottom; the notebook uses lr = 0.1 for 1,000 steps.

Gradient descent in NumPy for M rows and 2 features; the snippet and Figure 3 run 200 steps, the notebook 1,000.

import numpy as np
# X: (M, 2), y: (M,)
lr, n_steps = 0.1, 200
w, b = np.zeros(2), 0.0
M = len(y)
for step in range(n_steps):
    resid = X @ w + b - y  # (M,)
    grad_w = X.T @ resid / M
    grad_b = resid.mean()
    w = w - lr * grad_w
    b = b - lr * grad_b
  1. 1Sets the step size lr and starts the weights at 0.
  2. 2Residuals ŷ − y, the term inside the cost (Section 2).
  3. 3Gradients, the card in Section 2.1.
  4. 4One step downhill, the card in Section 2.2.

2.3 The closed-form solution

For squared error the bottom can be solved for directly: least squares, with one matrix inverse (the matrix that undoes a multiplication).

The closed form finds the best weights in one solve.
w = (XTX)−1XTy
X is the whole dataset stacked as a matrix, one row per sample, with a column of ones carrying the bias. The raised T is the transpose, X with its rows and columns flipped, y is the targets stacked alongside, and the −1 is the matrix inverse. One solve replaces hundreds of steps, and the solved w folds the bias in as one of its entries. The form comes from setting every slope of the cost to zero at once: XTX measures how the features overlap, XTy how each feature lines up with the targets, and the inverse undoes the overlap. When two features are near copies, XTX is close to having no inverse and the solved weights swing wildly.

On clean data this recovers the truth exactly, w1 = 5, w2 = 2 and b = 2.

The closed form on the same X and y, solved with lstsq, which stays accurate when features are near copies, unlike the inverse.

import numpy as np
lstsq = np.linalg.lstsq
ones = np.ones(len(X))  # for b
Xb = np.column_stack([ones, X])
sol = lstsq(Xb, y, rcond=None)
b, w1, w2 = sol[0]
  1. 1Adds a column of ones so the solve also finds b.
  2. 2Solves for every weight at once (Section 2.3).

3 Gradient descent on a 2D fit

Both routes on 300 samples (the notebook uses 2,000).

true target y prediction fitted line where the walk ends

Figure 3. The cost falls from the start 1 to the end of the walk 2 as the fitted line turns; Snap jumps to the closed form.

0.102 200

4 Linear regression in practice

The same fit in scikit-learn; R² is the share of the target's variation the line explains.

from sklearn.datasets import make_regression
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler

X, y = make_regression(2000, 2)
parts = train_test_split(X, y)
Xtr, Xte, ytr, yte = parts
scaler = StandardScaler()
ols = LinearRegression()
model = make_pipeline(scaler, ols)
model.fit(Xtr, ytr)  # one solve
r2 = model.score(Xte, yte)
  1. 1Makes 2,000 two-feature rows and holds out a test split.
  2. 2Scales the features, then ordinary least squares.
  3. 3Fits in one solve and scores R² on the test split.
SettingWhere it entersRaise itLower itDefault
Learning rate lrScales each step in the update cardFaster, until steps overshootSlower; tiny values stop short0.1 for 1,000 steps in the notebook
IterationsUpdate steps runWalks closer to the bottomStops above it1,000 notebook, 200 Figure 3
Ridge penalty αAdds α times the squared weights to the costShrinks weights toward 0 and calms twin featuresAt 0 it is plain least squares1.0 in scikit-learn's Ridge
eta0First step size of SGDRegressorFaster start, can divergeSlow progress per pass0.01, shrinking as eta0 / t0.25 (learning_rate="invscaling")

LinearRegression solves least squares with SciPy's lstsq: time grows with samples times features squared, and memory holds the data once. For data too big for memory, SGDRegressor takes the steps above in batches through partial_fit.

5 Failure modes of linear regression

A far point's cost grows with the square of its miss, so the fit bends toward it.

feature xy1one far pointfit with itfit without it (dashed)
Figure 4. One far point 1 tilts the fit from slope 5.4 to 3.7; without it the fit follows the rest.
CauseSymptomFix
A far pointThe line tilts toward one sampleCheck residuals; use a robust loss such as Huber, which grows only linearly for big misses
Unscaled featuresGradient descent zigzags and needs a tiny learning rateStandardize each feature first, shifting it to mean 0 and spread 1 (Gradient Descent)
Two features that move togetherTheir weights can trade off wildly while their combined effect stays putDrop one, or add an L2 penalty (Regularization)
Predicting past the dataThe line keeps going where no sample was seenTrust it only inside the range it was fit on

6 Polynomial features and logistic regression

Add squared features and the same code fits a polynomial curve.

Pass the line through the sigmoid, which maps any number into 0 to 1, and it gives a probability: logistic regression.

7 References

  1. Legendre, A.-M. (1805). Nouvelles méthodes pour la détermination des orbites des comètes. (the first published account of least squares)
  2. Hastie, T., et al. (2009). The Elements of Statistical Learning, Chapter 3 (Linear Methods for Regression). (least squares and the closed-form solution)