holehouse.org Blog Machine learning notes

04: Linear Regression with Multiple Variables

Linear regression with multiple features

New version of linear regression with multiple features

Gradient descent for multiple variables

J(θ0,θ1,,θn)=12mi=1m(hθ(x(i))y(i))2
Repeat { θ0θ0α1mi=1m(hθ(x(i))y(i)) θ1θ1α1mi=1m(hθ(x(i))y(i))x(i) } simultaneously update θ0 and θ1. The first update's sum is ∂/∂θ0 J(θ).
New algorithm (n ≥ 1) — Repeat { θjθjα1mi=1m(hθ(x(i))y(i))xj(i) } simultaneously update θj for j = 0, …, n. The sum is ∂/∂θj J(θ).
import numpy as np

grad = X.T @ (X @ theta - y) / m   # every partial derivative at once
theta = theta - alpha * grad       # every parameter updated at once

The whole update rule in two lines: X.T @ (X @ theta − y) computes the sum in the equation above for every j simultaneously.

Gradient Descent in practice: 1 Feature Scaling

xixiμisi μi is the average value of xi in the training set. si is the range (max − min), or the standard deviation.
mu = X[:, 1:].mean(axis=0)   # per-feature mean (skip the x0 column of 1s)
s  = X[:, 1:].std(axis=0)    # per-feature spread
X[:, 1:] = (X[:, 1:] - mu) / s   # every feature now centred, on a similar scale

Mean normalization and feature scaling in one step — broadcasting applies the subtraction and division to every row at once.

Learning Rate α

Make sure gradient descent is working

Features and polynomial regression

Normal equation

How does it work?

Example of normal equation

Training set — m = 4 examples, n = 4 features
Size in feet2 (x1) Number of bedrooms (x2) Number of floors (x3) Age of home in years (x4) Price ($1000) (y)
21045145460
14163240232
15343230315
8522136178
([11112104141615348525332122145403036][12104514511416324011534323018522136])1[11112104141615348525332122145403036][460232315178] That is XTX inverted, times XT, times y — the normal equation with the table above substituted in.
X = np.array([[1, 2104, 5, 1, 45],
              [1, 1416, 3, 2, 40],
              [1, 1534, 3, 2, 30],
              [1,  852, 2, 1, 36]], dtype=float)
y = np.array([460, 232, 315, 178], dtype=float)

theta = np.linalg.pinv(X.T @ X) @ X.T @ y

X @ theta   # [460., 232., 315., 178.]  -> reproduces every price exactly

The table above, solved in one line. With only four examples and five parameters the fit is exact — X @ theta returns the y column to machine precision.

General case

θ=(XTX)1XTy

When should you use gradient descent and when should you use the normal equation?

Normal equation and non-invertibility