Type at least 2 letters. Enter opens the first result, Esc closes.

    Linear Algebra · Lesson 9 · The SVD and PCA

    PCA as SVD of centered data, and randomized SVD

    Intermediate 70 min 4 interactive figures 4 videos Colab notebook

    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 ww and project every point onto the line through the origin in direction ww. The projections are numbers ("shadows" on the line).

    • If ww points along the long axis, the shadows are spread out: large variance.
    • If ww points along the short axis, the shadows are bunched together: small variance.

    PC1 (the first principal direction) is the ww 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 kk-dimensional subspace) in this sense.

    Interactive figure: loading…

    Drag the orange handle to turn ww. 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 w⊤Sww^\top S w and the squared distances, summed and divided by N−1N - 1 like the variance. The two curves always add up to tr⁡S\operatorname{tr} S. Find the angle where the orange curve is highest, then press Show principal axes: it is PC1, and its height is λ1\lambda_1.

    Quick check

    A centered cloud of points lies close to the line y=xy = x. What is PC1?

    The randomized SVD rests on one picture too. With A=∑jσjujvj⊤A = \sum_j \sigma_j u_j v_j^\top, a random vector ω\omega gives

    Aω=∑jσj (vj⊤ω) uj.A\omega = \sum_j \sigma_j \,(v_j^\top \omega)\, u_j .

    The numbers vj⊤ωv_j^\top \omega are random and of size about 1, so the large σj\sigma_j dominate: a random sample of the range of AA points mostly along the top singular directions. A few such samples span (almost) the top-kk subspace. "Mostly" is the weak point: if v1⊤ωv_1^\top\omega happens to be small, the sample misses u1u_1. Two cheap fixes help. Oversampling takes a few extra random vectors, so one bad draw does not matter. Power iterations multiply by AA⊤AA^\top again, which turns the weights σj\sigma_j into σj3,σj5,…\sigma_j^3, \sigma_j^5, \dots, so the top direction wins by much more.

    Interactive figure: loading…

    Change one setting at a time. Here A=diag⁡(3,1,0.1)A = \operatorname{diag}(3, 1, 0.1), so the singular vectors are the axes. With p=0p = 0 and q=0q = 0, the single sample y1=Aω1y_1 = A\omega_1 misses the top direction u1u_1 by about 49°49° for this unlucky ω1\omega_1 (grey). Set p=1p = 1: two samples span a blue plane that almost contains u1u_1, and the estimate u^1\hat u_1 is about 6°6° from it. Set p=0p = 0 and q=1q = 1: the weights 3,1,0.13, 1, 0.1 become 27,1,0.00127, 1, 0.001, and the single sample turns toward u1u_1. Press Run 1000 draws: the median angle is about 20°20° with p=q=0p = q = 0, and about 2°2° with p=1p = 1 or q=1q = 1.

    3. Definitions and main results #

    Setup. X∈RN×dX \in \mathbb{R}^{N \times d} holds NN samples as rows (the convention of scikit-learn), with dd features. The mean is μ=1NX⊤1\mu = \frac{1}{N}X^\top \mathbf{1}. Centering subtracts it from every row: Xc=X−1μ⊤X_c = X - \mathbf{1}\mu^\top. The sample covariance matrix is

    S=1N−1Xc⊤Xc∈Rd×d.S = \frac{1}{N-1} X_c^\top X_c \in \mathbb{R}^{d\times d}.

    SS is symmetric PSD, so S=QΛQ⊤S = Q\Lambda Q^\top with λ1≥⋯≥λd≥0\lambda_1 \ge \dots \ge \lambda_d \ge 0 (lesson 06).

    Why N−1N - 1 and not NN? The deviations are measured from the sample mean μ\mu, which is fitted to the same data, so they are a little too small on average. Dividing by N−1N - 1 instead of NN corrects this exactly: SS 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 N/(N−1)N/(N-1).

    Theorem 1 (PCA as an eigenproblem) #

    The unit vector ww that maximizes the sample variance of the projections XcwX_c w is w=q1w = q_1, and the maximum variance is λ1\lambda_1. Under the extra constraint w⊥q1,…,qk−1w \perp q_1, \dots, q_{k-1}, the maximizer is qkq_k, with variance λk\lambda_k.

    Proof.

    1. The projections are zi=w⊤x~iz_i = w^\top \tilde x_i, where x~i\tilde x_i is row ii of XcX_c. Their mean is w⊤1N∑ix~i=0w^\top \frac1N \sum_i \tilde x_i = 0, because the data are centered.
    2. So their sample variance is 1N−1∑i(w⊤x~i)2=1N−1∥Xcw∥2=w⊤Sw\frac{1}{N-1}\sum_i (w^\top \tilde x_i)^2 = \frac{1}{N-1}\|X_c w\|^2 = w^\top S w.
    3. Write w=Qcw = Qc. Then ∥c∥=∥w∥=1\|c\| = \|w\| = 1 and w⊤Sw=∑jλjcj2≤λ1∑jcj2=λ1w^\top S w = \sum_j \lambda_j c_j^2 \le \lambda_1 \sum_j c_j^2 = \lambda_1, with equality for c=e1c = e_1, that is w=q1w = q_1.
    4. The constraint w⊥q1,…,qk−1w \perp q_1, \dots, q_{k-1} means c1=⋯=ck−1=0c_1 = \dots = c_{k-1} = 0. The same bound gives w⊤Sw≤λkw^\top S w \le \lambda_k, with equality at w=qkw = q_k. ■\blacksquare

    The Lagrange route gives the same result: the gradient of w⊤Sw−λ(w⊤w−1)w^\top S w - \lambda(w^\top w - 1) is 2Sw−2λw2Sw - 2\lambda w, so a maximizer satisfies Sw=λwSw = \lambda w, and then the objective equals λ\lambda. If λ1=λ2\lambda_1 = \lambda_2, PC1 is not unique: every unit vector in that eigenspace is a maximizer.

    Theorem 2 (PCA from the SVD of centered data) #

    Let Xc=UΣV⊤X_c = U\Sigma V^\top (full SVD: VV is d×dd\times d, Σ\Sigma is N×dN\times d). Then:

    • the principal directions are the columns of VV (the right singular vectors);
    • the variance along direction ii is λi=σi2/(N−1)\lambda_i = \sigma_i^2/(N-1) (zero beyond the rank);
    • the scores (coordinates of the samples on the principal directions) are XcV=UΣX_c V = U\Sigma.

    Proof.

    1. Xc⊤Xc=VΣ⊤U⊤UΣV⊤=V(Σ⊤Σ)V⊤X_c^\top X_c = V\Sigma^\top U^\top U \Sigma V^\top = V (\Sigma^\top\Sigma) V^\top, because U⊤U=IU^\top U = I; Σ⊤Σ=diag⁡(σ12,σ22,… )\Sigma^\top\Sigma = \operatorname{diag}(\sigma_1^2, \sigma_2^2, \dots) is d×dd\times d.
    2. Divide by N−1N-1: S=V Σ⊤ΣN−1 V⊤S = V \,\frac{\Sigma^\top\Sigma}{N-1}\, V^\top. This is a spectral decomposition of SS (orthogonal VV, diagonal non-negative middle factor).
    3. The eigenvalues of SS are unique, so λi=σi2/(N−1)\lambda_i = \sigma_i^2/(N-1), and the columns of VV are eigenvectors of SS.
    4. XcV=UΣV⊤V=UΣX_c V = U\Sigma V^\top V = U\Sigma. In practice keep only the top kk columns (thin SVD). ■\blacksquare

    The explained variance ratio of PC ii is λi/∑jλj=σi2/∥Xc∥F2\lambda_i / \sum_j \lambda_j = \sigma_i^2/\|X_c\|_F^2. If the samples are columns instead (A=Xc⊤A = X_c^\top, size d×Nd \times N, common in science), the principal directions are the left singular vectors of AA, and S=AA⊤/(N−1)S = AA^\top/(N-1).

    At most N−1N - 1 components have nonzero variance #

    This surprises many people when dd is much larger than NN. Here is why, step by step.

    1. Centering makes the rows add up to zero. Each column of XcX_c has mean 0, so 1⊤Xc=0\mathbf{1}^\top X_c = 0: the sum of the NN rows is the zero vector.
    2. So the rows are dependent. The last row equals minus the sum of the others. The row space is spanned by N−1N - 1 rows, so rank⁡(Xc)≤N−1\operatorname{rank}(X_c) \le N - 1 (and of course ≤d\le d).
    3. Variance needs the row space. The variance along ww is ∥Xcw∥2/(N−1)\|X_c w\|^2/(N-1). If ww is orthogonal to every row, then Xcw=0X_c w = 0 and the variance is 0.
    4. Count. By Theorem 2, the number of nonzero variances is the number of nonzero σi\sigma_i, which is rank⁡(Xc)≤N−1\operatorname{rank}(X_c) \le N - 1. (Equivalently, rank⁡(S)=rank⁡(Xc⊤Xc)=rank⁡(Xc)\operatorname{rank}(S) = \operatorname{rank}(X_c^\top X_c) = \operatorname{rank}(X_c), lesson 02.)

    Small cases make it concrete. Two points, after centering, are x~\tilde x and −x~-\tilde x: 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 R1000\mathbb{R}^{1000}. A numerical check: a centered random 50×100050 \times 1000 matrix has rank 49.

    Quick check

    You have N=20N = 20 simulation snapshots, each with d=105d = 10^5 values. After centering, how many principal components can have nonzero variance?

    Theorem 3 (maximum variance = minimum reconstruction error) #

    For W∈Rd×kW \in \mathbb{R}^{d\times k} with orthonormal columns, the projection of x~i\tilde x_i onto the span of WW is WW⊤x~iWW^\top \tilde x_i, and

    ∑i∥x~i−WW⊤x~i∥2=∥Xc∥F2−(N−1)tr⁡(W⊤SW).\sum_i \|\tilde x_i - WW^\top \tilde x_i\|^2 = \|X_c\|_F^2 - (N-1)\operatorname{tr}(W^\top S W).

    Proof.

    1. WW⊤WW^\top is an orthogonal projector, so x~i−WW⊤x~i⊥WW⊤x~i\tilde x_i - WW^\top \tilde x_i \perp WW^\top \tilde x_i.
    2. Pythagoras, with ∥WW⊤x~i∥=∥W⊤x~i∥\|WW^\top \tilde x_i\| = \|W^\top \tilde x_i\| (orthonormal columns): ∥x~i∥2=∥W⊤x~i∥2+∥x~i−WW⊤x~i∥2\|\tilde x_i\|^2 = \|W^\top \tilde x_i\|^2 + \|\tilde x_i - WW^\top \tilde x_i\|^2.
    3. Sum over ii: ∑i∥W⊤x~i∥2=∥XcW∥F2=(N−1)tr⁡(W⊤SW)\sum_i \|W^\top \tilde x_i\|^2 = \|X_c W\|_F^2 = (N-1)\operatorname{tr}(W^\top S W). ■\blacksquare

    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 W=VkW = V_k (top kk right singular vectors), with error ∑j>kσj2=(N−1)∑j>kλj\sum_{j>k}\sigma_j^2 = (N-1)\sum_{j>k}\lambda_j. Eckart–Young compares with every matrix of rank at most kk, so no other kk-dimensional subspace does better.

    Why center? #

    Without centering you analyze the second-moment matrix. Expanding xi=x~i+μx_i = \tilde x_i + \mu and using ∑ix~i=0\sum_i \tilde x_i = 0:

    1N−1X⊤X=S+NN−1 μμ⊤.\frac{1}{N-1}X^\top X = S + \frac{N}{N-1}\,\mu\mu^\top .

    The extra rank-one term pulls the top eigenvector toward the mean μ\mu. PC1 then describes where the data are, not how they spread.

    Interactive figure: loading…

    Drag the cloud by its mean xˉ\bar x, and change the spreads and the correlation. The orange and blue arrows are the principal axes ±λi qi\pm\sqrt{\lambda_i}\,q_i; the violet ellipses are one and two standard deviations. The dashed magenta line is the top eigenvector of the uncentered matrix X⊤X/(N−1)X^\top X/(N-1): 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: σi2/(N−1)=λi\sigma_i^2/(N-1) = \lambda_i.

    Units matter too. PCA is not scale invariant. If one feature is a pressure in pascals (spread about 10310^3) and another a temperature in kelvin (spread about 5), the pressure variance is about 4×1044 \times 10^4 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.

    Quick check

    Feature 1 is a pressure in pascals, feature 2 a temperature in kelvin. What should you do before PCA?

    Covariance or SVD? #

    Forming Xc⊤XcX_c^\top X_c squares the singular values, so it squares the condition number. In float64 (machine epsilon ε=2−52≈2.2×10−16\varepsilon = 2^{-52} \approx 2.2 \times 10^{-16}), directions with σj/σ1\sigma_j/\sigma_1 below about ε≈1.5×10−8\sqrt{\varepsilon} \approx 1.5 \times 10^{-8} are lost in rounding. The SVD works on XcX_c directly and keeps them. Cost decides the rest:

    • N≫dN \gg d, small dd: the d×dd \times d covariance is cheap, and the lost directions are usually noise. scikit-learn (checked with version 1.9) uses its covariance_eigh solver by default when d≤1000d \le 1000 and N≥10dN \ge 10d.
    • d≫Nd \gg N (10610^6 grid points, N=50N = 50 members): never form the d×dd\times d matrix. Use the thin SVD of XcX_c (O(N2d)O(N^2 d) work), or the N×NN\times N Gram matrix XcXc⊤=UΣ2U⊤X_c X_c^\top = U\Sigma^2U^\top and then V=Xc⊤UΣ−1V = X_c^\top U\Sigma^{-1} (the "method of snapshots" of POD).
    • Both large: randomized SVD.

    The randomized SVD (Halko, Martinsson, Tropp 2011; "HMT") #

    Input: A∈Rm×nA \in \mathbb{R}^{m\times n}, target rank kk, oversampling pp (5 or 10 is typical), power iterations qq (1 or 2 is typical). Let ℓ=k+p\ell = k + p.

    1. Draw a Gaussian test matrix Ω∈Rn×ℓ\Omega \in \mathbb{R}^{n\times \ell} (independent standard normal entries).
    2. Y=AΩY = A\Omega (m×ℓm\times\ell); orthonormalize, Q=orth⁡(Y)Q = \operatorname{orth}(Y) (thin QR). This is the range finder: QQ is an orthonormal basis for (almost) the top-ℓ\ell part of the range of AA.
    3. Repeat qq times: Q~=orth⁡(A⊤Q)\tilde Q = \operatorname{orth}(A^\top Q) (n×ℓn\times\ell), then Q=orth⁡(AQ~)Q = \operatorname{orth}(A\tilde Q) (m×ℓm\times\ell). In exact arithmetic the final QQ spans the range of (AA⊤)qAΩ(AA^\top)^q A\Omega.
    4. B=Q⊤AB = Q^\top A (ℓ×n\ell\times n). Then A≈QB=QQ⊤AA \approx QB = QQ^\top A.
    5. Exact SVD of the small matrix: B=U~ΣV⊤B = \tilde U \Sigma V^\top (U~\tilde U is ℓ×ℓ\ell\times\ell).
    6. U=QU~U = Q\tilde U (m×ℓm\times\ell). Keep the top kk triplets.

    The shapes, for AA of size m×nm \times n:

    Matrix Shape Made from
    Ω\Omega n×ℓn \times \ell random numbers
    Y=AΩY = A\Omega, QQ m×ℓm \times \ell one pass over AA
    A⊤QA^\top Q, Q~\tilde Q (each power iteration) n×ℓn \times \ell one pass over AA
    AQ~A\tilde Q, new QQ (each power iteration) m×ℓm \times \ell one pass over AA
    B=Q⊤AB = Q^\top A ℓ×n\ell \times n one pass over AA
    U~\tilde U, Σ\Sigma ℓ×ℓ\ell \times \ell small SVD, no pass
    V⊤V^\top ℓ×n\ell \times n small SVD, no pass
    U=QU~U = Q\tilde U m×ℓm \times \ell, keep m×km \times k no pass

    So the algorithm touches AA in 2q+22q + 2 passes. The cost is O(mnℓ)O(mn\ell) per pass plus O((m+n)ℓ2)O((m+n)\ell^2) for the QR and the small SVD, instead of O(mnmin⁡(m,n))O(mn\min(m,n)) for a full SVD.

    Quick check

    A randomized SVD with q=1q = 1 power iteration. How many times does it read the whole matrix AA?

    Why oversampling. The error depends on how well the samples "see" each of the top kk directions. Split every random vector ω\omega into its parts along v1,…,vkv_1, \dots, v_k and along the other right singular vectors. The top parts form a k×ℓk \times \ell matrix Ω1=Vk⊤Ω\Omega_1 = V_k^\top\Omega. A Gaussian matrix stays Gaussian under rotation, so Ω1\Omega_1 is again a Gaussian matrix.

    • With p=0p = 0 it is square (k×kk \times k), 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 ω\omega.
    • With a few extra columns (p=5p = 5 or 1010), Ω1\Omega_1 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 V⊥V_\perp for the other right singular vectors, Ω2=V⊥⊤Ω\Omega_2 = V_\perp^\top\Omega, and let Σ2\Sigma_2 hold σk+1,σk+2,…\sigma_{k+1}, \sigma_{k+2}, \dots. If Ω1\Omega_1 has full row rank, the deterministic bound of HMT (Theorem 9.1) is

    ∥A−QQ⊤A∥2≤∥Σ2∥2+∥Σ2Ω2Ω1+∥2(spectral or Frobenius norm).\|A - QQ^\top A\|^2 \le \|\Sigma_2\|^2 + \|\Sigma_2\Omega_2\Omega_1^{+}\|^2 \quad(\text{spectral or Frobenius norm}).

    So the error is small when Ω1\Omega_1 is well conditioned. For a k×(k+p)k\times(k+p) Gaussian matrix, E∥Ω1+∥F2=k/(p−1)\mathbb{E}\|\Omega_1^{+}\|_F^2 = k/(p-1) for p≥2p \ge 2. This gives (HMT Theorem 10.5, k,p≥2k, p \ge 2, k+p≤min⁡(m,n)k + p \le \min(m, n))

    E ∥A−QQ⊤A∥F≤(1+kp−1)1/2(∑j>kσj2)1/2.\mathbb{E}\,\|A - QQ^\top A\|_F \le \Big(1 + \frac{k}{p-1}\Big)^{1/2}\Big(\sum_{j>k}\sigma_j^2\Big)^{1/2}.

    The right factor is the optimal rank-kk error (Eckart–Young). The error is also small with high probability: a spectral-norm tail bound (HMT Corollary 10.9, p≥4p \ge 4) fails with probability at most 6p−p6p^{-p} (about 0.0020.002 for p=5p = 5).

    For power iterations, (AA⊤)qA=UΣ2q+1V⊤(AA^\top)^q A = U\Sigma^{2q+1}V^\top. In the spectral-norm bound (HMT Corollary 10.10) the factor in front of σk+1\sigma_{k+1} is raised to the power 1/(2q+1)1/(2q+1), so it goes to 1 quickly as qq grows.

    Why power iterations. (AA⊤)qA=UΣ2q+1V⊤(AA^\top)^q A = U\Sigma^{2q+1}V^\top: same singular vectors, singular values σj2q+1\sigma_j^{2q+1}. If the spectrum decays slowly (noisy data), the tail σk+1,σk+2,…\sigma_{k+1}, \sigma_{k+2}, \dots is large in total and pollutes the samples. Raising to the power 2q+12q+1 makes it decay fast. For example, σj=1/j\sigma_j = 1/\sqrt j becomes j−3/2j^{-3/2} with q=1q = 1.

    Interactive figure: loading…

    Each dot is one randomized SVD; the lines are means. The chart shows the spectral error of the rank-kk result divided by the best possible error σk+1\sigma_{k+1} (Eckart–Young), against the oversampling pp, for q=0,1,2q = 0, 1, 2 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 q=0q = 0. Here AA is diag⁡(σ1,…,σ200)\operatorname{diag}(\sigma_1, \dots, \sigma_{200}): the algorithm only multiplies by AA and A⊤A^\top, and a rotated Gaussian matrix is still Gaussian, so the errors have the same distribution for Udiag⁡(σ)V⊤U\operatorname{diag}(\sigma)V^\top with any orthogonal UU and VV.

    Why re-orthonormalize. Without the QR in step 3, all columns of (AA⊤)qAΩ(AA^\top)^qA\Omega turn toward u1u_1, as in power iteration. Information about σj\sigma_j below about ε1/(2q+1)σ1\varepsilon^{1/(2q+1)}\sigma_1 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: 1⊤Xc=0\mathbf{1}^\top X_c = 0, so the 50 rows of XcX_c are dependent and rank⁡(Xc)≤N−1\operatorname{rank}(X_c) \le N - 1. (2) With exactly kk samples the k×kk\times k block Ω1\Omega_1 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 R2\mathbb{R}^2 (rows), so N=5N = 5 and d=2d = 2:

    X=(1021344352).X = \begin{pmatrix} 1 & 0 \\ 2 & 1 \\ 3 & 4 \\ 4 & 3 \\ 5 & 2 \end{pmatrix}.

    Step 1. Center. The column means are μ=(15/5, 10/5)=(3,2)\mu = (15/5,\ 10/5) = (3, 2). Subtract μ\mu from every row:

    Xc=(−2−2−1−1021120).X_c = \begin{pmatrix} -2 & -2 \\ -1 & -1 \\ 0 & 2 \\ 1 & 1 \\ 2 & 0 \end{pmatrix}.

    Check: each column of XcX_c adds up to 0.

    Step 2. Covariance (or SVD). Multiply column by column: (Xc⊤Xc)11=4+1+0+1+4=10(X_c^\top X_c)_{11} = 4 + 1 + 0 + 1 + 4 = 10, (Xc⊤Xc)12=4+1+0+1+0=6(X_c^\top X_c)_{12} = 4 + 1 + 0 + 1 + 0 = 6, (Xc⊤Xc)22=4+1+4+1+0=10(X_c^\top X_c)_{22} = 4 + 1 + 4 + 1 + 0 = 10. Divide by N−1=4N - 1 = 4:

    S=14(106610)=(2.51.51.52.5).S = \frac14\begin{pmatrix} 10 & 6 \\ 6 & 10 \end{pmatrix} = \begin{pmatrix} 2.5 & 1.5 \\ 1.5 & 2.5 \end{pmatrix}.

    Step 3. Directions. A matrix (abba)\begin{pmatrix} a & b \\ b & a \end{pmatrix} has eigenvalues a±ba \pm b with eigenvectors (1,1)/2(1, 1)/\sqrt2 and (1,−1)/2(1, -1)/\sqrt2. So λ1=4\lambda_1 = 4 with q1=(1,1)/2q_1 = (1, 1)/\sqrt2, and λ2=1\lambda_2 = 1 with q2=(1,−1)/2q_2 = (1, -1)/\sqrt2. The SVD route gives the same: the singular values of XcX_c are 16=4\sqrt{16} = 4 and 4=2\sqrt4 = 2, and 42/4=44^2/4 = 4, 22/4=12^2/4 = 1. ✓

    Step 4. Scores. Project the centered rows on the directions:

    • on PC1: Xcq1=(−4,−2,2,2,2)/2=(−22,−2,2,2,2)X_c q_1 = (-4, -2, 2, 2, 2)/\sqrt2 = (-2\sqrt2, -\sqrt2, \sqrt2, \sqrt2, \sqrt2);
    • on PC2: Xcq2=(0,0,−2,0,2)/2=(0,0,−2,0,2)X_c q_2 = (0, 0, -2, 0, 2)/\sqrt2 = (0, 0, -\sqrt2, 0, \sqrt2).

    Check: the PC1 scores have mean 0 and variance (8+2+2+2+2)/4=4=λ1(8 + 2 + 2 + 2 + 2)/4 = 4 = \lambda_1. ✓

    Step 5. Explained variance. PC1 explains λ1/(λ1+λ2)=4/5=80%\lambda_1/(\lambda_1 + \lambda_2) = 4/5 = 80\% of the variance, PC2 the other 20%20\%. If you keep only PC1, the reconstruction error is the sum of the squared PC2 scores: 2+2=4=σ22=(N−1)λ22 + 2 = 4 = \sigma_2^2 = (N - 1)\lambda_2, as Theorem 3 says. ✓

    Quick check

    In this example, XcX_c has singular values 44 and 22 and N=5N = 5. What is the variance along PC2?

    Without centering: X⊤X=(55363630)=Xc⊤Xc+5μμ⊤X^\top X = \begin{pmatrix} 55 & 36 \\ 36 & 30\end{pmatrix} = X_c^\top X_c + 5\mu\mu^\top. Its top eigenvector is about (0.815,0.580)(0.815, 0.580): only 1.7°1.7° from the mean direction (3,2)/13(3, 2)/\sqrt{13}, and 9.6°9.6° from the true PC1.

    Randomized SVD by hand. A=diag⁡(3,1)A = \operatorname{diag}(3, 1), k=1k = 1, p=0p = 0, and the "random" vector Ω=(1,1)⊤\Omega = (1, 1)^\top. The optimal rank-1 error is σ2=1\sigma_2 = 1.

    qq Y=(AA⊤)qAΩY = (AA^\top)^q A\Omega estimate ∥Q⊤A∥\lVert Q^\top A\rVert of σ1=3\sigma_1 = 3 error ∥A−QQ⊤A∥2\lVert A - QQ^\top A\rVert_2
    0 (3,1)(3, 1) 8.2≈2.864\sqrt{8.2} \approx 2.864 1.8≈1.342\sqrt{1.8} \approx 1.342
    1 (27,1)(27, 1) ≈2.998\approx 2.998 ≈1.005\approx 1.005

    The weight ratio of u1u_1 to u2u_2 in YY grows from 3:13:1 to 27:1=33:127:1 = 3^3:1. That is the σ2q+1\sigma^{2q+1} 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 pp from 10 to 40 with q=0q = 0 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 cos⁡(latitude)\sqrt{\cos(\text{latitude})} 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_lowrank and torch.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_lowrank does not center; torch.pca_lowrank does by default.)
    • Mixing conventions. Samples as rows: directions = right singular vectors VV. Samples as columns: directions = left singular vectors UU.
    • 1/N1/N vs 1/(N−1)1/(N-1). The directions are the same; the variances differ by the factor N/(N−1)N/(N-1). scikit-learn uses 1/(N−1)1/(N-1).
    • 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 N−1N - 1 components. With NN samples, at most N−1N - 1 components have nonzero variance, however large dd is.
    • Randomized SVD with p=0p = 0, or power iterations without re-orthonormalization.

    8. Check yourself #

    1. XcX_c (N=10N = 10) has singular values 6,3,06, 3, 0. Give the variances along the PCs and the explained variance ratio of PC1.
      Answerλ=36/9=4\lambda = 36/9 = 4, 9/9=19/9 = 1, 00. Ratio 4/5=80%4/5 = 80\%.
    2. Data with mean μ=(10,0)\mu = (10, 0) and a small spread. What does "PCA" without centering give as PC1?
      AnswerAbout e1e_1, the mean direction: X⊤X/(N−1)=S+NN−1μμ⊤X^\top X/(N-1) = S + \frac{N}{N-1}\mu\mu^\top is dominated by μμ⊤\mu\mu^\top (largest eigenvalue about 100N/(N−1)100N/(N-1)).
    3. Randomized SVD of a 106×10410^6 \times 10^4 matrix with k=20k = 20, p=10p = 10, q=2q = 2: shapes of Ω\Omega, QQ, BB, and the number of passes over AA?
      AnswerΩ\Omega: 104×3010^4\times 30; QQ: 106×3010^6 \times 30; B=Q⊤AB = Q^\top A: 30×10430\times 10^4. Passes: 2q+2=62q+2 = 6.
    4. The singular values decay like σj=1/j\sigma_j = 1/\sqrt j and the error is twice the optimum. Increase pp or qq? Why?
      AnswerMainly qq. The tail is flat, so many tail directions leak into the samples. Power iterations turn σj\sigma_j into σj2q+1\sigma_j^{2q+1} (here j−5/2j^{-5/2} for q=2q = 2), which suppresses the tail. Oversampling alone helps more slowly.
    5. With q=3q = 3 power iterations and no re-orthonormalization in float64, roughly which singular values are lost?
      AnswerThose below about ε1/(2q+1)σ1=(2−52)1/7σ1≈6×10−3 σ1\varepsilon^{1/(2q+1)}\sigma_1 = (2^{-52})^{1/7}\sigma_1 \approx 6\times10^{-3}\,\sigma_1.
    Recall cardsAnswer in your head first, then reveal. Add the cards to your review deck to see them again just before you would forget.
    1. What does the first principal direction maximize, and which eigenproblem gives it?

    2. How do you get the principal directions and variances from the SVD of the centered data XcX_c (samples as rows)?

    3. Why is "maximum variance" the same as "minimum reconstruction error" in PCA?

    4. Why must you center the data before PCA?

    5. NN samples in Rd\mathbb{R}^d with d>Nd > N. At most how many principal components have nonzero variance, and why?

    6. Why does the sample covariance divide by N−1N - 1 and not by NN?

    7. Randomized SVD: what are the first two steps (the range finder)?

    8. Randomized SVD: what happens after the range finder?

    9. Why does the randomized SVD oversample (ℓ=k+p\ell = k + p with p≈5p \approx 5–1010)?

    10. Why do power iterations help the randomized SVD, and what must be done after each product?

    Open the review →

    9. Interview angle #

    • "Derive PCA." — Variance of projections =w⊤Sw= w^\top S w; maximize on the unit sphere; get Sw=λwSw = \lambda w; then link to the SVD: λi=σi2/(N−1)\lambda_i = \sigma_i^2/(N-1).
    • "Eigendecomposition of the covariance or SVD of the data?" — SVD for accuracy (no squared condition number) and when dd is large; covariance when N≫dN \gg d and dd is small.
    • "How do you run PCA on a 107×10510^7 \times 10^5 matrix?" — Randomized SVD (or a Krylov method), with k+pk + p samples and 1–2 power iterations: 2q+22q+2 passes over the data.
    • "Why does a random projection find the top singular subspace?" — AωA\omega weights uju_j by σj\sigma_j; oversampling makes Ω1\Omega_1 well conditioned; the error is close to σk+1\sigma_{k+1}.

    10. Practice #

    The notebook for this lesson runs in Colab. It has four exercises, each with a check cell and a folded solution:

    1. pca: principal directions, explained variances and scores from the SVD of the centered data; compare with scikit-learn on the digits data set.
    2. reconstruction_error: project the digits onto the top kk components, check Theorem 3 (error =∑j>kσj2= \sum_{j>k}\sigma_j^2), and find how many components keep 90% of the variance.
    3. uncentered_pc1: see how far the top direction of X⊤XX^\top X moves when you shift the data.
    4. randomized_svd: the HMT algorithm with oversampling, power iterations and QR after every product; compare its error with σk+1\sigma_{k+1} and with a full SVD on a 1000×4001000 \times 400 matrix.

    11. Watch and read #

    Open on YouTube · the player loads from youtube-nocookie.com when you press play
    Open on YouTube · the player loads from youtube-nocookie.com when you press play
    Open on YouTube · the player loads from youtube-nocookie.com when you press play
    Open on YouTube · the player loads from youtube-nocookie.com when you press play