PCA as SVD of centered data, and randomized SVD
Before this lesson: lesson 08 (the SVD, Eckart–Young–Mirsky, polar decomposition and the pseudoinverse) and lesson 06 (the spectral theorem and the Rayleigh quotient). Time: about 70 minutes, plus the notebook.
Why this matters #
PCA is the first thing to try on any high-dimensional data set: it finds the few directions in which the data varies most. In climate science the same computation is called EOF analysis; in fluid dynamics it is called POD (proper orthogonal decomposition). It is also an interview classic, because it connects statistics (variance), optimization (a constrained maximum) and linear algebra (eigenvectors and singular vectors).
When the data matrix is huge (millions of grid points, many snapshots), an exact SVD is too expensive. The randomized SVD finds the top singular directions with a few passes over the matrix. Both ideas rest on the SVD of lesson 08.
1. Predict first #
2. The picture #
Start with a cloud of points in the plane, centered at the origin and shaped like a long thin ellipse. Pick a unit vector and project every point onto the line through the origin in direction . The projections are numbers ("shadows" on the line).
- If points along the long axis, the shadows are spread out: large variance.
- If points along the short axis, the shadows are bunched together: small variance.
PC1 (the first principal direction) is the with the largest spread of shadows. There is a second, equivalent view. For each point, its squared length splits into the squared shadow plus the squared perpendicular distance to the line (Pythagoras). The total squared length is fixed. So maximizing the shadows = minimizing the perpendicular distances. PCA finds the best-fitting line (or -dimensional subspace) in this sense.
Drag the orange handle to turn . Each grey point casts an orange shadow on the line; the blue segments are the distances to the line. The chart shows, for every angle, the shadow variance and the squared distances, summed and divided by like the variance. The two curves always add up to . Find the angle where the orange curve is highest, then press Show principal axes: it is PC1, and its height is .
A centered cloud of points lies close to the line . What is PC1?
The shadows on the line are the widest, so PC1 points along it: , or its negative (a principal direction has no fixed sign). is perpendicular to the cloud: it is PC2, with the smallest variance. The mean is after centering; PCA describes the spread, not the location.
The randomized SVD rests on one picture too. With , a random vector gives
The numbers are random and of size about 1, so the large dominate: a random sample of the range of points mostly along the top singular directions. A few such samples span (almost) the top- subspace. "Mostly" is the weak point: if happens to be small, the sample misses . Two cheap fixes help. Oversampling takes a few extra random vectors, so one bad draw does not matter. Power iterations multiply by again, which turns the weights into , so the top direction wins by much more.
Change one setting at a time. Here , so the singular vectors are the axes. With and , the single sample misses the top direction by about for this unlucky (grey). Set : two samples span a blue plane that almost contains , and the estimate is about from it. Set and : the weights become , and the single sample turns toward . Press Run 1000 draws: the median angle is about with , and about with or .
3. Definitions and main results #
Setup. holds samples as rows (the convention of scikit-learn), with features. The mean is . Centering subtracts it from every row: . The sample covariance matrix is
is symmetric PSD, so with (lesson 06).
Why and not ? The deviations are measured from the sample mean , which is fitted to the same data, so they are a little too small on average. Dividing by instead of corrects this exactly: is then an unbiased estimate of the population covariance (Bessel's correction). The principal directions are the same with either choice; only the variances change, by the factor .
Theorem 1 (PCA as an eigenproblem) #
The unit vector that maximizes the sample variance of the projections is , and the maximum variance is . Under the extra constraint , the maximizer is , with variance .
Proof.
- The projections are , where is row of . Their mean is , because the data are centered.
- So their sample variance is .
- Write . Then and , with equality for , that is .
- The constraint means . The same bound gives , with equality at .
The Lagrange route gives the same result: the gradient of is , so a maximizer satisfies , and then the objective equals . If , PC1 is not unique: every unit vector in that eigenspace is a maximizer.
Theorem 2 (PCA from the SVD of centered data) #
Let (full SVD: is , is ). Then:
- the principal directions are the columns of (the right singular vectors);
- the variance along direction is (zero beyond the rank);
- the scores (coordinates of the samples on the principal directions) are .
Proof.
- , because ; is .
- Divide by : . This is a spectral decomposition of (orthogonal , diagonal non-negative middle factor).
- The eigenvalues of are unique, so , and the columns of are eigenvectors of .
- . In practice keep only the top columns (thin SVD).
The explained variance ratio of PC is . If the samples are columns instead (, size , common in science), the principal directions are the left singular vectors of , and .
At most components have nonzero variance #
This surprises many people when is much larger than . Here is why, step by step.
- Centering makes the rows add up to zero. Each column of has mean 0, so : the sum of the rows is the zero vector.
- So the rows are dependent. The last row equals minus the sum of the others. The row space is spanned by rows, so (and of course ).
- Variance needs the row space. The variance along is . If is orthogonal to every row, then and the variance is 0.
- Count. By Theorem 2, the number of nonzero variances is the number of nonzero , which is . (Equivalently, , lesson 02.)
Small cases make it concrete. Two points, after centering, are and : they lie on one line through 0, so only one component has variance. Three points, after centering, lie in a plane through 0 (the plane of their triangle, moved to the origin), so at most two components have variance, even in . A numerical check: a centered random matrix has rank 49.
You have simulation snapshots, each with values. After centering, how many principal components can have nonzero variance?
The 20 centered rows add up to the zero vector, so . The number of features does not help: the data span at most a 19-dimensional subspace of . Without centering the bound would be , but then PC1 describes the mean, not the spread.
Theorem 3 (maximum variance = minimum reconstruction error) #
For with orthonormal columns, the projection of onto the span of is , and
Proof.
- is an orthogonal projector, so .
- Pythagoras, with (orthonormal columns): .
- Sum over : .
So the subspace that captures the most variance is the one with the smallest reconstruction error. By Eckart–Young (lesson 08), the best choice is (top right singular vectors), with error . Eckart–Young compares with every matrix of rank at most , so no other -dimensional subspace does better.
Why center? #
Without centering you analyze the second-moment matrix. Expanding and using :
The extra rank-one term pulls the top eigenvector toward the mean . PC1 then describes where the data are, not how they spread.
Drag the cloud by its mean , and change the spreads and the correlation. The orange and blue arrows are the principal axes ; the violet ellipses are one and two standard deviations. The dashed magenta line is the top eigenvector of the uncentered matrix : move the mean away from 0 and it turns toward the mean. Press Mean to 0 and it agrees with PC1 again. The readout checks Theorem 2: .
Units matter too. PCA is not scale invariant. If one feature is a pressure in pascals (spread about ) and another a temperature in kelvin (spread about 5), the pressure variance is about times larger, and PC1 is almost the pressure axis only because of the units. Then standardize first: divide each centered feature by its standard deviation. This is PCA of the correlation matrix.
Feature 1 is a pressure in pascals, feature 2 a temperature in kelvin. What should you do before PCA?
Centering fixes the location but not the scale. Variances change with the square of the unit, so the feature with the large numbers takes PC1 for no physical reason. After standardizing, every feature has variance 1, and PCA compares correlations. Removing a feature throws away information.
Covariance or SVD? #
Forming squares the singular values, so it squares the condition number. In float64 (machine epsilon ), directions with below about are lost in rounding. The SVD works on directly and keeps them. Cost decides the rest:
- , small : the covariance is cheap, and the lost directions are
usually noise. scikit-learn (checked with version 1.9) uses its
covariance_eighsolver by default when and . - ( grid points, members): never form the matrix. Use the thin SVD of ( work), or the Gram matrix and then (the "method of snapshots" of POD).
- Both large: randomized SVD.
The randomized SVD (Halko, Martinsson, Tropp 2011; "HMT") #
Input: , target rank , oversampling (5 or 10 is typical), power iterations (1 or 2 is typical). Let .
- Draw a Gaussian test matrix (independent standard normal entries).
- (); orthonormalize, (thin QR). This is the range finder: is an orthonormal basis for (almost) the top- part of the range of .
- Repeat times: (), then (). In exact arithmetic the final spans the range of .
- (). Then .
- Exact SVD of the small matrix: ( is ).
- (). Keep the top triplets.
The shapes, for of size :
| Matrix | Shape | Made from |
|---|---|---|
| random numbers | ||
| , | one pass over | |
| , (each power iteration) | one pass over | |
| , new (each power iteration) | one pass over | |
| one pass over | ||
| , | small SVD, no pass | |
| small SVD, no pass | ||
| , keep | no pass |
So the algorithm touches in passes. The cost is per pass plus for the QR and the small SVD, instead of for a full SVD.
A randomized SVD with power iteration. How many times does it read the whole matrix ?
is one pass, the power iteration needs two ( and ), and is one more: . Answers 2 and 3 forget either the power iteration (it costs two passes, not one) or the final projection .
Why oversampling. The error depends on how well the samples "see" each of the top directions. Split every random vector into its parts along and along the other right singular vectors. The top parts form a matrix . A Gaussian matrix stays Gaussian under rotation, so is again a Gaussian matrix.
- With it is square (), and a random square matrix is sometimes close to singular. Then some top direction gets almost no weight in every sample: the figure in section 2 shows this with one bad .
- With a few extra columns ( or ), is wide, and a wide Gaussian matrix is very rarely close to rank-deficient. The error is then close to the best possible one.
The error bounds of HMT
Write for the other right singular vectors, , and let hold . If has full row rank, the deterministic bound of HMT (Theorem 9.1) is
So the error is small when is well conditioned. For a Gaussian matrix, for . This gives (HMT Theorem 10.5, , )
The right factor is the optimal rank- error (Eckart–Young). The error is also small with high probability: a spectral-norm tail bound (HMT Corollary 10.9, ) fails with probability at most (about for ).
For power iterations, . In the spectral-norm bound (HMT Corollary 10.10) the factor in front of is raised to the power , so it goes to 1 quickly as grows.
Why power iterations. : same singular vectors, singular values . If the spectrum decays slowly (noisy data), the tail is large in total and pollutes the samples. Raising to the power makes it decay fast. For example, becomes with .
Each dot is one randomized SVD; the lines are means. The chart shows the spectral error of the rank- result divided by the best possible error (Eckart–Young), against the oversampling , for power iterations. With the slow spectrum, oversampling alone stays far from 1, while one power iteration almost reaches it. With the fast spectrum, about ten extra columns are enough. The noise floor case is the worst for . Here is : the algorithm only multiplies by and , and a rotated Gaussian matrix is still Gaussian, so the errors have the same distribution for with any orthogonal and .
Why re-orthonormalize. Without the QR in step 3, all columns of turn toward , as in power iteration. Information about below about is lost to rounding (HMT Remark 4.3). Orthonormalizing after every product (subspace iteration) keeps the basis well conditioned.
Answers to section 1. (1) At most 49: , so the 50 rows of are dependent and . (2) With exactly samples the block can be nearly singular, so one top direction can be badly missed. A few extra columns make that very unlikely.
4. Worked example #
PCA by hand in five steps. Five points in (rows), so and :
Step 1. Center. The column means are . Subtract from every row:
Check: each column of adds up to 0.
Step 2. Covariance (or SVD). Multiply column by column: , , . Divide by :
Step 3. Directions. A matrix has eigenvalues with eigenvectors and . So with , and with . The SVD route gives the same: the singular values of are and , and , . ✓
Step 4. Scores. Project the centered rows on the directions:
- on PC1: ;
- on PC2: .
Check: the PC1 scores have mean 0 and variance . ✓
Step 5. Explained variance. PC1 explains of the variance, PC2 the other . If you keep only PC1, the reconstruction error is the sum of the squared PC2 scores: , as Theorem 3 says. ✓
In this example, has singular values and and . What is the variance along PC2?
. forgets to divide by ; uses instead of (the scikit-learn convention is ); forgets to square.
Without centering: . Its top eigenvector is about : only from the mean direction , and from the true PC1.
Randomized SVD by hand. , , , and the "random" vector . The optimal rank-1 error is .
| estimate of | error | ||
|---|---|---|---|
| 0 | |||
| 1 |
The weight ratio of to in grows from to . That is the effect.
5. In code #
Libraries check the identities of section 3. The notebook asks you to write pca and
randomized_svd yourself.
import numpy as np
from sklearn.decomposition import PCA
from sklearn.utils.extmath import randomized_svd
# 1) The worked example: PCA variances are sigma_i^2 / (N - 1).
X = np.array([[1, 0], [2, 1], [3, 4], [4, 3], [5, 2]], dtype=float)
pca = PCA(n_components=2).fit(X)
s = np.linalg.svd(X - X.mean(axis=0), compute_uv=False)
print(s) # [4. 2.]
print(pca.explained_variance_) # [4. 1.]
print(s**2 / (len(X) - 1)) # [4. 1.]
print(pca.explained_variance_ratio_) # [0.8 0.2]
print(np.abs(pca.components_)) # rows: (1,1)/√2 and (1,-1)/√2, up to sign
# 2) Forming Z^T Z squares the condition number: a singular value 1e-9 is lost.
rng = np.random.default_rng(0)
P, _ = np.linalg.qr(rng.standard_normal((1000, 2)))
R = np.array([[1.0, -1.0], [1.0, 1.0]]) / np.sqrt(2) # rotate the input axes by 45°
Z = P @ np.diag([1.0, 1e-9]) @ R.T # singular values 1 and 1e-9
print(np.linalg.svd(Z, compute_uv=False)) # [1.e+00 1.e-09]: correct
print(np.linalg.eigvalsh(Z.T @ Z)) # small one: rounding noise (about -3e-17), not 1e-18
# 3) Randomized SVD on a slowly decaying spectrum sigma_j = 1/sqrt(j).
m = n = 500
U, _ = np.linalg.qr(rng.standard_normal((m, m)))
V, _ = np.linalg.qr(rng.standard_normal((n, n)))
sig = 1 / np.sqrt(np.arange(1, n + 1))
A = (U * sig) @ V.T
k = 10
for q in [0, 1, 2]:
Uk, sk, Vtk = randomized_svd(A, k, n_oversamples=10, n_iter=q,
power_iteration_normalizer="QR", random_state=0)
err = np.linalg.norm(A - (Uk * sk) @ Vtk, 2)
print(q, round(err / sig[k], 3)) # ratio to the optimum sigma_{k+1}: about 1.9, 1.02, 1.00
In part 2 the small eigenvalue comes out negative: pure rounding noise. In part 3, without power iterations the error is almost twice the optimum; two power iterations reach it. (For this matrix, raising from 10 to 40 with helps less than one power iteration.)
6. Where it shows up #
- Climate and weather (EOF analysis). Rows are times or ensemble members, columns are grid points. The principal directions are spatial patterns (EOFs), the scores are their time series (PCs). On a latitude–longitude grid, multiply each column by first, so that each grid point counts with its area.
- Ensemble forecasts. The leading PCs of the ensemble anomalies give a low-rank model of the forecast uncertainty. Without localization, the ensemble Kalman filter update lies in the span of these anomalies.
- Reduced-order models (POD). The leading modes of simulation snapshots give a small basis for a fast surrogate model.
- ML. Embedding visualization, whitening, feature compression. A linear autoencoder trained with squared error learns the PCA subspace (not necessarily the individual directions).
- Libraries.
sklearn.decomposition.PCA(svd_solver="randomized"),torch.svd_lowrankandtorch.pca_lowrank(based on HMT Algorithm 5.1). For small dense matrices a full SVD is faster.
7. Common mistakes #
- Not centering. PC1 then points toward the mean. (
torch.svd_lowrankdoes not center;torch.pca_lowrankdoes by default.) - Mixing conventions. Samples as rows: directions = right singular vectors . Samples as columns: directions = left singular vectors .
- vs . The directions are the same; the variances differ by the factor . scikit-learn uses .
- Comparing signs. Each principal direction is defined only up to sign.
- Not scaling features with different units. PCA is not scale invariant. If one variable is in pascals and another in kelvin, standardize first (PCA of the correlation matrix).
- Expecting more than components. With samples, at most components have nonzero variance, however large is.
- Randomized SVD with , or power iterations without re-orthonormalization.
8. Check yourself #
- () has singular values . Give the variances along the PCs and the
explained variance ratio of PC1.
Answer
, , . Ratio . - Data with mean and a small spread. What does "PCA" without centering give
as PC1?
Answer
About , the mean direction: is dominated by (largest eigenvalue about ). - Randomized SVD of a matrix with , , : shapes of
, , , and the number of passes over ?
Answer
: ; : ; : . Passes: . - The singular values decay like and the error is twice the optimum.
Increase or ? Why?
Answer
Mainly . The tail is flat, so many tail directions leak into the samples. Power iterations turn into (here for ), which suppresses the tail. Oversampling alone helps more slowly. - With power iterations and no re-orthonormalization in float64, roughly which
singular values are lost?
Answer
Those below about .
What does the first principal direction maximize, and which eigenproblem gives it?
The variance of the centered data projected on a unit vector . The maximizer is the top eigenvector of (), and the maximum is .
How do you get the principal directions and variances from the SVD of the centered data (samples as rows)?
: the directions are the columns of , and the variance along direction is .
Why is "maximum variance" the same as "minimum reconstruction error" in PCA?
By Pythagoras, . The total is fixed, so a larger captured part means a smaller error.
Why must you center the data before PCA?
Without centering, , and the top direction turns toward the mean instead of the spread.
samples in with . At most how many principal components have nonzero variance, and why?
. The centered rows add up to zero, so .
Why does the sample covariance divide by and not by ?
Deviations from the sample mean are slightly too small on average; makes unbiased (Bessel's correction). The directions do not change.
Randomized SVD: what are the first two steps (the range finder)?
Draw a Gaussian of size ; form and orthonormalize it: .
Randomized SVD: what happens after the range finder?
Form (), take its exact SVD , and set ; keep the top triplets.
Why does the randomized SVD oversample ( with –)?
With exactly samples, the Gaussian block can be nearly singular, so a top direction is missed. A few extra columns make this very unlikely.
Why do power iterations help the randomized SVD, and what must be done after each product?
has singular values , so a slowly decaying tail is suppressed. Re-orthonormalize (QR) after each product, or small singular values are lost to rounding.
9. Interview angle #
- "Derive PCA." — Variance of projections ; maximize on the unit sphere; get ; then link to the SVD: .
- "Eigendecomposition of the covariance or SVD of the data?" — SVD for accuracy (no squared condition number) and when is large; covariance when and is small.
- "How do you run PCA on a matrix?" — Randomized SVD (or a Krylov method), with samples and 1–2 power iterations: passes over the data.
- "Why does a random projection find the top singular subspace?" — weights by ; oversampling makes well conditioned; the error is close to .
10. Practice #
The notebook for this lesson runs in Colab. It has four exercises, each with a check cell and a folded solution:
pca: principal directions, explained variances and scores from the SVD of the centered data; compare with scikit-learn on the digits data set.reconstruction_error: project the digits onto the top components, check Theorem 3 (error ), and find how many components keep 90% of the variance.uncentered_pc1: see how far the top direction of moves when you shift the data.randomized_svd: the HMT algorithm with oversampling, power iterations and QR after every product; compare its error with and with a full SVD on a matrix.
11. Watch and read #
- Halko, Martinsson, Tropp, Finding structure with randomness (SIAM Review 2011): §1.6 (prototype randomized SVD), §4.1–4.5 (Algorithms 4.1, 4.3, 4.4 and Remark 4.3), §9.2 (Theorem 9.1), §10.2–10.4 (Theorem 10.5, Corollaries 10.9 and 10.10).
- Brunton and Kutz, Data-Driven Science and Engineering, 2nd edition (free PDF), chapter 1: §1.5 (PCA), §1.6 (eigenfaces), §1.8 (randomized SVD).
- scikit-learn user guide, Principal component analysis:
the solvers (
full,covariance_eigh,randomized) and when each is used.
Runs in your browser with nothing to install. The notebook repeats the key demos and has exercises with checks; solutions are inside, folded.
No Google account needed: Python runs inside your browser. The first start downloads about 40 MB; your changes are saved in this browser only.