NewTurn any lesson into a live trading bot with one prompt, using AgenKitagenkit.xyz

Part 3 · Data scienceLesson 1210 minQuant Bible §4.4

Principal components

Rotating the data to the directions where it actually varies, then keeping only the important ones.

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 XX (subtract each column’s mean) and decompose it:

X=UDV⊤,X⊤X=VD2V⊤,X = U D V^\top, \qquad X^\top X = V D^2 V^\top ,

where UU and VV have orthonormal columns and DD is diagonal with d1≥d2≥⋯≥0d_1 \ge d_2 \ge \dots \ge 0. The columns v1,v2,…v_1, v_2, \dots of VV are the eigenvectors of X⊤XX^\top X (the covariance matrix up to a factor N−1N-1): new axes, each perpendicular to the ones before.

The principal components are the data expressed on those axes, z1=Xv1z_1 = X v_1, z2=Xv2z_2 = X v_2, … The variance of zjz_j is dj2/(N−1)d_j^2/(N-1), so the first component has the largest variance, the second the largest of what’s left, and so on.

Figure 12.1Principal components of a 3D cloud
The three arrows are the eigenvectors of the covariance matrix, each 2σ long. Choose “Keep PC1 + PC2” and watch every point slide onto the plane they span. The readout says how much variance survives.
Figure 12.2PCA rotator in two dimensions
Arrows show PC1 and PC2, each 2σ long. Rotate and squash the cloud: PC1 always finds the long axis. Switch to “Keep only PC1” to see the one-dimensional approximation, and read off how much variance it keeps.

Three ways PCA appears

  • Unsupervised compression. Transform the inputs to their first MM components before fitting anything. No target needed.
  • Principal components regression (PCR). Regress yy on z1,…,zMz_1, \dots, z_M with M<pM < p. The components are orthogonal, so this is MM separate one-variable regressions. Then map the coefficients back to the original inputs.
  • Ridge, seen through PCA. Ridge shrinks the coefficient on component jj by the factor dj2/(dj2+λ)d_j^2/(d_j^2 + \lambda): it barely touches the big components and squashes the small ones. PCR is the hard-threshold version: it keeps the first MM 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?

Progress is saved in this browser only.