Module 7: Orthogonality
Most real-world systems are overdetermined — more data points than unknowns. There's no exact solution. Least squares finds the best approximate one.
We have n data points and want to fit y=mx+b. For each point (xᵢ, yᵢ), the error is yi−(mxi+b). We want to minimize the total squared error:
Stack the equations into a matrix: Ax=b where each row is one data point. When there's no exact solution, the least squares solution is:
This is called the normal equation. The term A(ATA)−1AT is the projection matrix onto the column space of A.
The vertical distances from each data point to the fitted line are the residuals. Least squares minimizes the sum of their squares — not their absolute values, not their maximum. Squaring penalizes large errors more heavily.
Click on the canvas to add points. Click an existing point to remove it. The green line updates in real-time. The yellow dashed lines are the residuals. Move points far off the line and watch the residual sum grow.
import numpy as np
# x values, y values
x = np.array([-3, -2, -1, 0, 1, 2, 3])
y = np.array([-2, -1.5, -0.5, 0.5, 1, 2.5, 2])
# Build design matrix: [x, 1] for each point
A = np.column_stack([x, np.ones_like(x)])
# Normal equation: x = (AᵀA)⁻¹Aᵀb
m, b = np.linalg.lstsq(A, y, rcond=None)[0]
print(f"y = {m:.2f}x + {b:.2f}")Best-fit line: y = 0.77x + 0.29
Sum of squared residuals = 0.92
Click to add a point · click a point to remove it. Yellow dashes = residuals (vertical errors the line minimizes).