PCA in Practice: Eigenfaces and Two Limits

Eigenfaces show PCA compressing face images a hundredfold. They also expose two limits: eigen-decomposing a d×d covariance matrix is too slow when d is huge, and PCA only finds linear structure. The first is fixed by working with the n×n matrix of dot products XᵀX, which quietly sets up the fix for the second.

Machine Learning Techniques

PCA earns its place by working on real data. This chapter shows it doing something striking with photographs of faces, then looks honestly at two things it does badly. Fixing the first one, a matter of speed, will hand us the key to fixing the second, a matter of shape.

Eigenfaces

Take a large collection of grey-scale photographs of faces, all the same size and all looking straight at the camera. A photo is a grid of pixels, each a brightness value from 0 to 255. Read the grid row by row into one long list and each photo becomes a vector. A modest 180 × 180 image already gives a vector with more than 32,000 coordinates, so the data set is a cloud of points in a space with tens of thousands of dimensions.

Run PCA on it. Each principal component is itself a vector with the same number of coordinates as an image, so it can be folded back into a grid and viewed as a picture. These pictures are called eigenfaces.

  • The first eigenface looks like a blurry, generic face: the direction along which face images vary most is, roughly, "how face-like and how brightly lit".
  • Later eigenfaces add detail: the outline of the nose, the shape of the mouth, shadows around the eyes, the effect of light from one side.

Now take a new face, one that was not in the data set, and reconstruct it from only its first kk coefficients. With 25 components you get a face, but not recognisably this face. Somewhere around a few hundred components the person becomes recognisable, and adding more only sharpens fine detail. The image had tens of thousands of numbers, but a few hundred carry what identifies the person: roughly a hundredfold compression. This is why PCA is often used as a first step before a classifier: train the classifier on a few hundred coefficients instead of tens of thousands of pixels.

A row of reconstructions of one face using 10, 50, 200 and 1000 principal components, growing sharper from left to right, and a second row where a dog's face is reconstructed from the same face components and stays face-like until many components are used
Reconstruction from the top k eigenfaces. A face is recognisable from a few hundred components; an image unlike the training data (here a dog) needs far more, because the top directions describe faces, not dogs.

A revealing experiment: reconstruct a photo of a dog from the same face components. With a few hundred components the result looks like the most dog-like human face, because the top directions describe how faces vary, not how dogs vary. Only with many more components does the dog appear. A random noise image would need every single component. PCA learns the subspace where this kind of data lives; points from elsewhere fit it badly, and that misfit is itself useful (it is the basis of PCA-based anomaly detection).

Limit 1: too many features

The expensive step in PCA is the eigen-decomposition of the d×dd \times d covariance matrix, which for a general matrix costs on the order of d3d^3 operations. With dd in the tens of thousands, d3d^3 is in the trillions. In the face example, though, there are often fewer images than pixels: n<dn < d. Can we pay for nn instead of dd?

Every principal component is a combination of the data points

Stack the centred data points as the columns of a matrix:

X=[ x1    x2    ⋯    xn ]∈Rd×n,C=1n∑i=1nxixi⊤=1nXX⊤.X = \big[\, x_1 \;\; x_2 \;\; \cdots \;\; x_n \,\big] \in \mathbb{R}^{d \times n}, \qquad C = \frac{1}{n}\sum_{i=1}^{n} x_i x_i^\top = \frac{1}{n} X X^\top .

Take an eigenvector ww of CC with a non-zero eigenvalue λ\lambda, so Cw=λwCw = \lambda w. Writing out CC and dividing by λ\lambda:

w=1nλ∑i=1nxi (xi⊤w)=∑i=1nαi xi,αi=xi⊤wnλ.w = \frac{1}{n\lambda}\sum_{i=1}^{n} x_i\,(x_i^\top w) = \sum_{i=1}^{n} \alpha_i\, x_i, \qquad \alpha_i = \frac{x_i^\top w}{n\lambda}.

So every principal component is a weighted sum of the data points, w=Xαw = X\alpha for some weight vector α∈Rn\alpha \in \mathbb{R}^n. That is natural: the directions of variation of a data set can only be built from the data. The formula for α\alpha is useless as it stands (it needs ww, which we are looking for), but it tells us what to search for: nn weights instead of dd coordinates.

An n × n eigenproblem

Substitute w=Xαw = X\alpha into 1nXX⊤w=λw\tfrac{1}{n}XX^\top w = \lambda w:

XX⊤Xα=nλ Xα.X X^\top X \alpha = n\lambda\, X\alpha .

Multiply both sides on the left by X⊤X^\top and write K=X⊤XK = X^\top X, an n×nn \times n matrix:

K2α=nλ Kα.K^2 \alpha = n\lambda\, K\alpha .

Any α\alpha satisfying the simpler equation

Kα=nλ αK\alpha = n\lambda\,\alpha

satisfies this one too. So α\alpha is an eigenvector of KK. A linear algebra fact makes this consistent: XX⊤XX^\top (d×dd \times d) and X⊤XX^\top X (n×nn \times n) have the same non-zero eigenvalues (both come from the singular values of XX). The eigenvalues of KK are therefore exactly nλ1,nλ2,…n\lambda_1, n\lambda_2, \dots, the scaled eigenvalues of CC.

Getting the length right

An eigenvector is only defined up to scale, but we need ∥w∥=1\lVert w \rVert = 1:

1=w⊤w=α⊤X⊤Xα=α⊤Kα.1 = w^\top w = \alpha^\top X^\top X \alpha = \alpha^\top K \alpha .

If β\beta is a unit eigenvector of KK with eigenvalue nλn\lambda, then β⊤Kβ=nλ\beta^\top K \beta = n\lambda, so the right scaling is

α=βnλ.\alpha = \frac{\beta}{\sqrt{n\lambda}} .

The faster algorithm

  1. Compute K=X⊤XK = X^\top X (the n×nn \times n matrix of dot products between centred points).
  2. Eigen-decompose KK: unit eigenvectors β1,β2,…\beta_1, \beta_2, \dots with eigenvalues nλ1≥nλ2≥…n\lambda_1 \ge n\lambda_2 \ge \dots
  3. Set αk=βk/nλk\alpha_k = \beta_k / \sqrt{n\lambda_k}.
  4. The principal components are wk=Xαkw_k = X\alpha_k, and the coefficient of point xjx_j on component kk is xj⊤wk=∑iαk,i (xi⊤xj)x_j^\top w_k = \sum_i \alpha_{k,i}\,(x_i^\top x_j).

The eigen-decomposition now costs about n3n^3 instead of d3d^3. With 2,000 images of 32,000 pixels that is a saving of a factor of roughly 163≈4,00016^3 \approx 4{,}000. When n>dn > d, the ordinary covariance route is the cheaper one: always decompose the smaller matrix.

The observation that changes everything

Look at what the faster algorithm actually needs. Entry (i,j)(i, j) of KK is

Kij=xi⊤xj,K_{ij} = x_i^\top x_j ,

the dot product of two data points, a measure of how similar they are. Step 4 also uses only dot products. The whole of PCA can be computed from the pairwise dot products of the data, without ever looking at the coordinates themselves. Keep that in mind; it is the hinge of the next module.

Limit 2: PCA only sees straight structure

PCA finds the best linear subspace: lines, planes and their higher-dimensional versions through the mean. Many relationships between features are not linear. Suppose three measured features obey f3=f12+f22f_3 = f_1^2 + f_2^2. The data then lies on a curved surface, a bowl, inside three-dimensional space. It is genuinely two-dimensional (two numbers fix a point on the bowl), but no flat plane fits a bowl. PCA will report a large error for every plane and conclude that all three dimensions are needed. The structure is there; PCA simply cannot see its shape.

Two quite different complaints, then: one about computing time, one about the kind of structure PCA can find. The surprising answer, in the next module, is that the trick we just used for the first one (needing only dot products) also solves the second.

Try it yourself
Machine Learning Lab: feature maps →
Two rings that no straight line separates: watch the first principal component mix them up, then add one non-linear feature and see them come apart.
MediumLinear algebraPCA

Why are the non-zero eigenvalues of XXᵀ and XᵀX the same?

EasyPCAComplexity

When would you compute PCA through XᵀX rather than through the covariance matrix?

MediumPCAAnomaly detection

A PCA model trained on photos of faces is shown a photo of a car. What happens to its reconstruction error, and how can that be useful?