Many inputs move together. Ten points on the yield curve, five hundred stock returns, the beds, baths and square footage of a house: most of the variation lives in a few directions. Principal component analysis finds them.
The singular value decomposition
Centre the data matrix (subtract each column’s mean) and decompose it:
where and have orthonormal columns and is diagonal with . The columns of are the eigenvectors of (the covariance matrix up to a factor ): new axes, each perpendicular to the ones before.
The principal components are the data expressed on those axes, , , … The variance of is , so the first component has the largest variance, the second the largest of what’s left, and so on.
Three ways PCA appears
- Unsupervised compression. Transform the inputs to their first components before fitting anything. No target needed.
- Principal components regression (PCR). Regress on with . The components are orthogonal, so this is separate one-variable regressions. Then map the coefficients back to the original inputs.
- Ridge, seen through PCA. Ridge shrinks the coefficient on component by the factor : it barely touches the big components and squashes the small ones. PCR is the hard-threshold version: it keeps the first untouched and drops the rest completely.
In code
import numpy as np
rng = np.random.default_rng(10)
# Fake yield-curve changes: level, slope and curvature factors plus noise
tenors = np.array([0.25, 1, 2, 5, 10, 30])
level, slope, curve = np.ones(6), (tenors - 7) / 10, -((np.log(tenors) - 1.3) ** 2) + 1.5
F = rng.standard_normal((2500, 3)) * [8, 4, 2]
dY = F @ np.vstack([level, slope, curve]) + rng.standard_normal((2500, 6))
dY = dY - dY.mean(axis=0)
U, d, Vt = np.linalg.svd(dY, full_matrices=False)
explained = d**2 / np.sum(d**2)
print(np.round(explained, 3)) # the first three components explain almost everything
print(np.round(Vt[0], 2)) # PC1 ≈ equal weights: a parallel "level" shift
Check yourself
You run PCA on 50 stock returns and PC1 has roughly equal positive weights on every stock. What is PC1?