ml.lab
Python sleeps until you run code
04 Eigenvectors and eigenvalues

Lesson 3 of 4

Symmetric matrices and PCA

A symmetric matrix has real eigenvalues and perpendicular eigenvectors, so it is a pure stretch along perpendicular axes. The covariance matrix of a dataset is symmetric, and its eigenvectors are the directions in which the data varies most, the principal components.

About 50 minutes
By the end you can
  • Recognize a symmetric matrix and name where symmetric matrices appear in machine learning.

  • State the spectral theorem, A=QΛQ⊤\mathbf{A} = \mathbf{Q}\boldsymbol{\Lambda}\mathbf{Q}^\top, and explain what an orthogonal matrix does to lengths and angles.

  • Prove that eigenvectors of a symmetric matrix for different eigenvalues are perpendicular.

  • Compute the variance of data along a direction as u⊤Cu\mathbf{u}^\top\mathbf{C}\mathbf{u}, and find principal components as eigenvectors of the covariance matrix.

Here are five points in the plane: (3,3)(3,\allowbreak 3), (−3,−3)(-3,\allowbreak -3), (1,−1)(1,\allowbreak -1), (−1,1)(-1,\allowbreak 1) and (0,0)(0,\allowbreak 0). Plot them and one question answers itself: along which direction do they spread out most? Along the diagonal line through (1,1)(1,\allowbreak 1). Two of the points sit on that line, three times as far from the middle as the two on the other diagonal.

Now ask the same question of 10,000 sentence embeddings, each a list of 768 numbers. No picture helps. What you want is a calculation that takes the data and returns the direction of greatest spread, then the next one, and so on. This lesson builds it, and the answer is an eigenvector. Not of any matrix, though: of a symmetric one, and symmetric matrices have unusually clean eigenvectors.

We start with what symmetric means and what it does to eigenvectors, prove it, and then use it on data. The same facts carry the next lesson, on singular values.

What symmetric means

Most matrices from the last two lessons had eigenvectors at odd angles to each other: (1,1)(1,\allowbreak 1) and (1,−2)(1,\allowbreak -2) for [4123]\begin{bmatrix} 4 & 1 \\ 2 & 3 \end{bmatrix}. One family of matrices never does that, and it is the family machine learning meets most.

A matrix is symmetric if it equals its own transpose, A⊤=A\mathbf{A}^\top = \mathbf{A}: the entry in row ii, column jj equals the entry in row jj, column ii, so the matrix is a mirror image across its diagonal. [2112]\begin{bmatrix} 2 & 1 \\ 1 & 2 \end{bmatrix} is symmetric; [4123]\begin{bmatrix} 4 & 1 \\ 2 & 3 \end{bmatrix} is not, because its top-right 1 differs from its bottom-left 2. Symmetric matrices are everywhere in machine learning: covariance matrices (this lesson), the Hessian of a loss (the matrix of second derivatives, in gradient descent), and A⊤A\mathbf{A}^\top\mathbf{A} for any matrix A\mathbf{A} (the next lesson) are all symmetric.

See what symmetry does before we prove anything. The instrument below is the matrix instrument again, starting at the symmetric matrix [2112]\begin{bmatrix} 2 & 1 \\ 1 & 2 \end{bmatrix}, with the lime eigen-lines switched on and the eigenvalues in the readouts. The coral arrow is the second column, (1,2)(1,\allowbreak 2). Dragging its tip sideways changes the top-right entry and leaves the bottom-left one alone, which breaks the symmetry.

In every symmetric case the eigen-lines were perpendicular, and there were always two of them. That is a theorem.

The spectral theorem

The picture suggests a rule. Here it is in full, followed by the two proofs we need for 2x2 matrices.

This is the diagonalization A=PDP−1\mathbf{A} = \mathbf{P}\mathbf{D}\mathbf{P}^{-1} of the previous lesson with the best possible P\mathbf{P}, one whose inverse is just its transpose. A matrix like Q\mathbf{Q}, whose columns have length 1 and are perpendicular to each other, is called orthogonal. Three facts about it:

  • Its inverse is its transpose. Entry (i,j)(i,\allowbreak j) of Q⊤Q\mathbf{Q}^\top\mathbf{Q} is row ii of Q⊤\mathbf{Q}^\top dotted with column jj of Q\mathbf{Q}, which is column ii dotted with column jj. That is 1 when i=ji = j (length 1) and 0 otherwise (perpendicular), so Q⊤Q=I\mathbf{Q}^\top\mathbf{Q} = \mathbf{I}.
  • It keeps every length. Write the squared length as a dot product and use the first fact: ∣Qx∣2=(Qx)⊤(Qx)=x⊤Q⊤Q x=x⊤x=∣x∣2.|\mathbf{Q}\mathbf{x}|^2 = (\mathbf{Q}\mathbf{x})^\top(\mathbf{Q}\mathbf{x}) = \mathbf{x}^\top\mathbf{Q}^\top\mathbf{Q}\,\mathbf{x} = \mathbf{x}^\top\mathbf{x} = |\mathbf{x}|^2.
  • It keeps every angle. The same steps show (Qx)⋅(Qy)=x⊤Q⊤Q y=x⊤y=x⋅y(\mathbf{Q}\mathbf{x})\cdot(\mathbf{Q}\mathbf{y}) = \mathbf{x}^\top\mathbf{Q}^\top\mathbf{Q}\,\mathbf{y} = \mathbf{x}^\top\mathbf{y} = \mathbf{x}\cdot\mathbf{y}, and the angle between two vectors is fixed by their dot product and their lengths. So in the plane an orthogonal matrix is a rotation or a reflection (in more dimensions, a combination of them).

Read A=QΛQ⊤\mathbf{A} = \mathbf{Q}\boldsymbol{\Lambda}\mathbf{Q}^\top right to left, as before. Q⊤\mathbf{Q}^\top rotates (or reflects) the eigen-directions onto the axes, Λ\boldsymbol{\Lambda} stretches each axis by its eigenvalue (a negative one also flips it), and Q\mathbf{Q} rotates back. No shear anywhere: a symmetric matrix is a pure stretch along perpendicular axes.

We will prove the two halves of the theorem for the cases we need. First, why the eigenvalues are real in the 2x2 case.

Go slower: A symmetric 2x2 matrix never has complex eigenvalues

Write A=[abbd]\mathbf{A} = \begin{bmatrix} a & b \\ b & d \end{bmatrix}. Its trace is a+da + d and its determinant is ad−b2ad - b^2. The eigenvalues are complex only when the discriminant (tr⁡A)2−4det⁡A(\operatorname{tr}\mathbf{A})^2 - 4\det\mathbf{A} is negative, so compute it one move at a time:

(a+d)2−4(ad−b2)=a2+2ad+d2−4ad+4b2expand both parts=a2−2ad+d2+4b2combine 2ad−4ad=(a−d)2+4b2a2−2ad+d2=(a−d)2\begin{aligned} (a + d)^2 - 4(ad - b^2) &= a^2 + 2ad + d^2 - 4ad + 4b^2 && \text{expand both parts} \\ &= a^2 - 2ad + d^2 + 4b^2 && \text{combine } 2ad - 4ad \\ &= (a - d)^2 + 4b^2 && a^2 - 2ad + d^2 = (a - d)^2 \end{aligned}

A sum of squares is never negative, so the eigenvalues are real. The discriminant is zero only if a=da = d and b=0b = 0, that is, when A\mathbf{A} is a multiple of I\mathbf{I}, and then every direction is an eigen-direction.

Second, why the eigenvectors are perpendicular. The proof is three lines. It uses only the transpose rule (AB)⊤=B⊤A⊤(\mathbf{A}\mathbf{B})^\top = \mathbf{B}^\top\mathbf{A}^\top from shapes, transposes and batches and the dot product written as a matrix product, a⋅b=a⊤b\mathbf{a}\cdot\mathbf{b} = \mathbf{a}^\top\mathbf{b}.

Go slower: Eigenvectors for different eigenvalues are perpendicular

Let Av1=λ1v1\mathbf{A}\mathbf{v}_1 = \lambda_1\mathbf{v}_1 and Av2=λ2v2\mathbf{A}\mathbf{v}_2 = \lambda_2\mathbf{v}_2 with λ1≠λ2\lambda_1 \ne \lambda_2 and A⊤=A\mathbf{A}^\top = \mathbf{A}. Compute the number (Av1)⋅v2(\mathbf{A}\mathbf{v}_1)\cdot\mathbf{v}_2 in two ways.

Way 1, using Av1=λ1v1\mathbf{A}\mathbf{v}_1 = \lambda_1\mathbf{v}_1:

(Av1)⋅v2=λ1 (v1⋅v2).(\mathbf{A}\mathbf{v}_1)\cdot\mathbf{v}_2 = \lambda_1\,(\mathbf{v}_1\cdot\mathbf{v}_2).

Way 2, moving A\mathbf{A} to the other side, one move per step:

(Av1)⋅v2=(Av1)⊤v2dot product as a matrix product=v1⊤A⊤v2transpose rule=v1⊤A v2symmetry, A⊤=A=v1⊤(λ2v2)Av2=λ2v2=λ2 (v1⋅v2).\begin{aligned} (\mathbf{A}\mathbf{v}_1)\cdot\mathbf{v}_2 &= (\mathbf{A}\mathbf{v}_1)^\top\mathbf{v}_2 && \text{dot product as a matrix product} \\ &= \mathbf{v}_1^\top\mathbf{A}^\top\mathbf{v}_2 && \text{transpose rule} \\ &= \mathbf{v}_1^\top\mathbf{A}\,\mathbf{v}_2 && \text{symmetry, } \mathbf{A}^\top = \mathbf{A} \\ &= \mathbf{v}_1^\top(\lambda_2\mathbf{v}_2) && \mathbf{A}\mathbf{v}_2 = \lambda_2\mathbf{v}_2 \\ &= \lambda_2\,(\mathbf{v}_1\cdot\mathbf{v}_2). \end{aligned}

Compare. Both equal the same number, so λ1(v1⋅v2)=λ2(v1⋅v2)\lambda_1(\mathbf{v}_1\cdot\mathbf{v}_2) = \lambda_2(\mathbf{v}_1\cdot\mathbf{v}_2), which rearranges to

(λ1−λ2) (v1⋅v2)=0.(\lambda_1 - \lambda_2)\,(\mathbf{v}_1\cdot\mathbf{v}_2) = 0.

The first factor is not zero because the eigenvalues differ. So v1⋅v2=0\mathbf{v}_1\cdot\mathbf{v}_2 = 0: the eigenvectors are perpendicular. The step that needed symmetry was replacing A⊤\mathbf{A}^\top by A\mathbf{A}. Without it, the argument breaks, and so does the conclusion.

Worked example. A=[2112]\mathbf{A} = \begin{bmatrix} 2 & 1 \\ 1 & 2 \end{bmatrix} has trace 4 and determinant 4−1=34 - 1 = 3, so λ2−4λ+3=(λ−3)(λ−1)=0\lambda^2 - 4\lambda + 3 = (\lambda - 3)(\lambda - 1) = 0 and the eigenvalues are 3 and 1. For λ=3\lambda = 3, the row (−1,1)(-1,\allowbreak 1) of A−3I\mathbf{A} - 3\mathbf{I} gives the eigenvector (1,1)(1,\allowbreak 1). For λ=1\lambda = 1, the row (1,1)(1,\allowbreak 1) of A−I\mathbf{A} - \mathbf{I} gives (1,−1)(1,\allowbreak -1). Their dot product is 1⋅1+1⋅(−1)=01 \cdot 1 + 1 \cdot (-1) = 0, as promised. Both have length 2\sqrt{2}, so dividing by 2\sqrt{2} gives unit vectors:

Q=12[111−1],Λ=[3001].\mathbf{Q} = \frac{1}{\sqrt{2}}\begin{bmatrix} 1 & 1 \\ 1 & -1 \end{bmatrix}, \qquad \boldsymbol{\Lambda} = \begin{bmatrix} 3 & 0 \\ 0 & 1 \end{bmatrix}.

Multiply back to check. QΛ\mathbf{Q}\boldsymbol{\Lambda} scales the columns of Q\mathbf{Q} by 3 and 1, and this Q\mathbf{Q} happens to equal its own transpose, so

QΛQ⊤=12[313−1]12[111−1]=12[3+13−13−13+1]=[2112].\mathbf{Q}\boldsymbol{\Lambda}\mathbf{Q}^\top = \frac{1}{\sqrt{2}}\begin{bmatrix} 3 & 1 \\ 3 & -1 \end{bmatrix}\frac{1}{\sqrt{2}}\begin{bmatrix} 1 & 1 \\ 1 & -1 \end{bmatrix} = \frac{1}{2}\begin{bmatrix} 3 + 1 & 3 - 1 \\ 3 - 1 & 3 + 1 \end{bmatrix} = \begin{bmatrix} 2 & 1 \\ 1 & 2 \end{bmatrix}.

Compare the non-symmetric [4123]\begin{bmatrix} 4 & 1 \\ 2 & 3 \end{bmatrix} from the first lesson: its eigenvectors (1,1)(1,\allowbreak 1) and (1,−2)(1,\allowbreak -2) have dot product 1−2=−11 - 2 = -1, so they are not perpendicular.

To recap: symmetric means A⊤=A\mathbf{A}^\top = \mathbf{A}; such a matrix has real eigenvalues and perpendicular eigenvectors, so it factors as QΛQ⊤\mathbf{Q}\boldsymbol{\Lambda}\mathbf{Q}^\top with an orthogonal Q\mathbf{Q} that keeps lengths and angles. Take one apart yourself, including the check.

On paperA symmetric matrix, taken apart

Let A=[5222]\mathbf{A} = \begin{bmatrix} 5 & 2 \\ 2 & 2 \end{bmatrix}.

  1. Find its eigenvalues and an eigenvector for each.
  2. Check that the eigenvectors are perpendicular.
  3. Write A=QΛQ⊤\mathbf{A} = \mathbf{Q}\boldsymbol{\Lambda}\mathbf{Q}^\top with unit eigenvectors, and multiply it out to confirm you get A\mathbf{A} back.

Enter the two eigenvalues below as a column, larger first.

Work it on real paper: writing each step is the point. Then check your final answer here and compare your working with the walk-through.

The two eigenvalues as a column, larger first

One entry per box, top to bottom. 0.25, -2, 3/4 and sqrt(2) all work. Enter moves to the next empty box and checks once all are filled.

Principal components

Now the payoff promised at the start: the direction in which data varies most. It takes three steps. Measure how the features vary together (the covariance matrix), turn "the spread along a direction" into a formula, and maximize that formula.

The data and its covariance. You have nn examples, each with dd features, stored as the rows of a data matrix X\mathbf{X} of shape n×dn \times d (the row convention used in code). First center the data: subtract each column's mean, so every feature averages to zero. Call the result X~\tilde{\mathbf{X}}. The covariance matrix is

C=1n−1 X~⊤X~,Cjk=1n−1∑i=1nx~ij x~ik.\mathbf{C} = \frac{1}{n - 1}\,\tilde{\mathbf{X}}^\top\tilde{\mathbf{X}}, \qquad C_{jk} = \frac{1}{n-1}\sum_{i=1}^{n}\tilde{x}_{ij}\,\tilde{x}_{ik}.

It is d×dd \times d. Its diagonal entry CjjC_{jj} is the variance of feature jj, the average squared distance from the mean. The off-diagonal entry CjkC_{jk} is the covariance of features jj and kk, positive when they tend to rise together. It is symmetric because CjkC_{jk} and CkjC_{kj} are the same sum. (Dividing by n−1n - 1 is the usual sample convention, and it is what np.cov does. Module 0 divided by nn, as np.var does; the two choices differ by the same factor for every variance and change no direction.)

For the five points from the opening, the mean is (0,0)(0,\allowbreak 0), so they are already centered. Add up the three kinds of product over the points:

∑x2=9+9+1+1+0=20,∑xy=9+9−1−1+0=16,∑y2=9+9+1+1+0=20.\begin{aligned} \textstyle\sum x^2 &= 9 + 9 + 1 + 1 + 0 = 20, \\ \textstyle\sum xy &= 9 + 9 - 1 - 1 + 0 = 16, \\ \textstyle\sum y^2 &= 9 + 9 + 1 + 1 + 0 = 20. \end{aligned}

Divide by n−1=4n - 1 = 4:

C=[5445].\mathbf{C} = \begin{bmatrix} 5 & 4 \\ 4 & 5 \end{bmatrix}.

Each feature has variance 5, and the covariance 4 is positive: when xx is large, yy tends to be large too.

The spread along a direction. Take a unit vector u\mathbf{u} and project every centered example onto it: zi=u⋅x~iz_i = \mathbf{u}\cdot\tilde{\mathbf{x}}_i, where x~i\tilde{\mathbf{x}}_i is row ii of X~\tilde{\mathbf{X}} written as a column. Each ziz_i is how far example ii lies along u\mathbf{u}. The ziz_i average to zero, and their variance turns out to be a single number built from u\mathbf{u}, C\mathbf{C} and u\mathbf{u} again (an expression of this kind is called a quadratic form):

1n−1∑i=1nzi2=u⊤C u.\frac{1}{n-1}\sum_{i=1}^{n} z_i^2 = \mathbf{u}^\top\mathbf{C}\,\mathbf{u}.

Check it on the five points with u=(1,1)/2\mathbf{u} = (1,\allowbreak 1)/\sqrt{2}. The projections are (3+3)/2=32(3 + 3)/\sqrt{2} = 3\sqrt{2}, then −32-3\sqrt{2}, then (1−1)/2=0(1 - 1)/\sqrt{2} = 0, 00 and 00. Their squares add to 18+18=3618 + 18 = 36, and 36/4=936/4 = 9. The formula gives the same: Cu=(5+4, 4+5)/2=(9,9)/2\mathbf{C}\mathbf{u} = (5 + 4,\allowbreak \ 4 + 5)/\sqrt{2} = (9,\allowbreak 9)/\sqrt{2}, and u⊤Cu=(9+9)/2=9\mathbf{u}^\top\mathbf{C}\mathbf{u} = (9 + 9)/2 = 9. Along the x-axis, u=(1,0)\mathbf{u} = (1,\allowbreak 0), it gives C11=5C_{11} = 5, and along (1,−1)/2(1,\allowbreak -1)/\sqrt{2} it gives (5−4−4+5)/2=1(5 - 4 - 4 + 5)/2 = 1. The diagonal really is the long direction.

Go slower: From projected variance to u transpose C u

Each zi=u⊤x~iz_i = \mathbf{u}^\top\tilde{\mathbf{x}}_i is a number, so it equals its own transpose, x~i⊤u\tilde{\mathbf{x}}_i^\top\mathbf{u}. Then

zi2=zi⋅zi=(u⊤x~i)(x~i⊤u)=u⊤(x~ix~i⊤)u.z_i^2 = z_i \cdot z_i = (\mathbf{u}^\top\tilde{\mathbf{x}}_i)(\tilde{\mathbf{x}}_i^\top\mathbf{u}) = \mathbf{u}^\top\big(\tilde{\mathbf{x}}_i\tilde{\mathbf{x}}_i^\top\big)\mathbf{u}.

Sum over ii and pull the fixed u\mathbf{u} outside the sum:

∑izi2=u⊤(∑ix~ix~i⊤)u.\sum_i z_i^2 = \mathbf{u}^\top\Big(\sum_i\tilde{\mathbf{x}}_i\tilde{\mathbf{x}}_i^\top\Big)\mathbf{u}.

The sum of outer products ∑ix~ix~i⊤\sum_i\tilde{\mathbf{x}}_i\tilde{\mathbf{x}}_i^\top is exactly X~⊤X~\tilde{\mathbf{X}}^\top\tilde{\mathbf{X}}: that is the outer-product view of matrix multiplication, with column ii of X~⊤\tilde{\mathbf{X}}^\top times row ii of X~\tilde{\mathbf{X}}. Divide by n−1n - 1 and you have u⊤Cu\mathbf{u}^\top\mathbf{C}\mathbf{u}. As a bonus, a variance is never negative, so u⊤Cu≥0\mathbf{u}^\top\mathbf{C}\mathbf{u} \ge 0 for every u\mathbf{u}. With u\mathbf{u} a unit eigenvector, u⊤Cu=λ u⊤u=λ\mathbf{u}^\top\mathbf{C}\mathbf{u} = \lambda\,\mathbf{u}^\top\mathbf{u} = \lambda, so every eigenvalue of C\mathbf{C} is at least 0.

The best direction is the top eigenvector. C\mathbf{C} is symmetric, so by the spectral theorem it has perpendicular unit eigenvectors q1,…,qd\mathbf{q}_1,\allowbreak \ldots,\allowbreak \mathbf{q}_d. Number them so the eigenvalues come largest first, λ1≥λ2≥⋯≥λd≥0\lambda_1 \ge \lambda_2 \ge \cdots \ge \lambda_d \ge 0. Any unit u\mathbf{u} can be written as u=c1q1+⋯+cdqd\mathbf{u} = c_1\mathbf{q}_1 + \cdots + c_d\mathbf{q}_d, and then c12+⋯+cd2=1c_1^2 + \cdots + c_d^2 = 1. The reason: ∣u∣2=u⋅u|\mathbf{u}|^2 = \mathbf{u}\cdot\mathbf{u}, and multiplying out that dot product gives a term cicj (qi⋅qj)c_i c_j\,(\mathbf{q}_i\cdot\mathbf{q}_j) for every pair; the pairs with i≠ji \ne j are 0 (perpendicular) and each qi⋅qi\mathbf{q}_i\cdot\mathbf{q}_i is 1, so ∣u∣2=c12+⋯+cd2|\mathbf{u}|^2 = c_1^2 + \cdots + c_d^2, which is 1 for a unit vector. The box below shows that then

u⊤C u=λ1c12+λ2c22+⋯+λdcd2≤λ1 (c12+⋯+cd2)=λ1,\mathbf{u}^\top\mathbf{C}\,\mathbf{u} = \lambda_1 c_1^2 + \lambda_2 c_2^2 + \cdots + \lambda_d c_d^2 \le \lambda_1\,(c_1^2 + \cdots + c_d^2) = \lambda_1,

with equality when u=q1\mathbf{u} = \mathbf{q}_1. The variance along u\mathbf{u} is an average of the eigenvalues, weighted by ci2c_i^2, and an average is never above its largest value.

Go slower: Why u transpose C u is a weighted average of the eigenvalues

Apply C\mathbf{C} to u\mathbf{u}, using linearity and then Cqi=λiqi\mathbf{C}\mathbf{q}_i = \lambda_i\mathbf{q}_i:

Cu=c1Cq1+⋯+cdCqd=c1λ1q1+⋯+cdλdqd.\mathbf{C}\mathbf{u} = c_1\mathbf{C}\mathbf{q}_1 + \cdots + c_d\mathbf{C}\mathbf{q}_d = c_1\lambda_1\mathbf{q}_1 + \cdots + c_d\lambda_d\mathbf{q}_d.

Now dot with u=c1q1+⋯+cdqd\mathbf{u} = c_1\mathbf{q}_1 + \cdots + c_d\mathbf{q}_d. Multiplying out gives one term cj ciλi (qj⋅qi)c_j\,c_i\lambda_i\,(\mathbf{q}_j\cdot\mathbf{q}_i) for every pair i,ji,\allowbreak j. Each qj⋅qi\mathbf{q}_j\cdot\mathbf{q}_i with i≠ji \ne j is 0, because the eigenvectors are perpendicular, and each qi⋅qi\mathbf{q}_i\cdot\mathbf{q}_i is 1. Only the terms with i=ji = j survive:

u⊤Cu=c12λ1+c22λ2+⋯+cd2λd.\mathbf{u}^\top\mathbf{C}\mathbf{u} = c_1^2\lambda_1 + c_2^2\lambda_2 + \cdots + c_d^2\lambda_d.

Every λi\lambda_i is at most λ1\lambda_1, so replacing each by λ1\lambda_1 can only make the sum larger, and c12+⋯+cd2=1c_1^2 + \cdots + c_d^2 = 1 turns it into λ1\lambda_1. Equality needs all the weight on λ1\lambda_1: c1=±1c_1 = \pm 1 and every other ci=0c_i = 0, which is u=±q1\mathbf{u} = \pm\mathbf{q}_1.

Check it on the five points. Their covariance has the unit eigenvectors q1=(1,1)/2\mathbf{q}_1 = (1,\allowbreak 1)/\sqrt{2} and q2=(1,−1)/2\mathbf{q}_2 = (1,\allowbreak -1)/\sqrt{2}, with eigenvalues 9 and 1 (the worked example below confirms this; they are the variances along the two diagonals found above). The x-axis u=(1,0)\mathbf{u} = (1,\allowbreak 0) has c1=u⋅q1=1/2c_1 = \mathbf{u}\cdot\mathbf{q}_1 = 1/\sqrt{2} and c2=u⋅q2=1/2c_2 = \mathbf{u}\cdot\mathbf{q}_2 = 1/\sqrt{2} (dotting u=c1q1+c2q2\mathbf{u} = c_1\mathbf{q}_1 + c_2\mathbf{q}_2 with q1\mathbf{q}_1 leaves only c1c_1, because q1⋅q1=1\mathbf{q}_1\cdot\mathbf{q}_1 = 1 and q1⋅q2=0\mathbf{q}_1\cdot\mathbf{q}_2 = 0), so c12=c22=12c_1^2 = c_2^2 = \tfrac12, and the formula gives 9⋅12+1⋅12=59 \cdot \tfrac12 + 1 \cdot \tfrac12 = 5: the variance along the x-axis, C11C_{11}, halfway between the two eigenvalues.

So the direction of greatest variance is the top eigenvector, and the variance along it is the top eigenvalue. The same argument, restricted to directions perpendicular to q1\mathbf{q}_1, picks out q2\mathbf{q}_2, and so on down the list.

Worked example. For the five points, C=[5445]\mathbf{C} = \begin{bmatrix} 5 & 4 \\ 4 & 5 \end{bmatrix} has the same pattern as [2112]\begin{bmatrix} 2 & 1 \\ 1 & 2 \end{bmatrix} (equal diagonal entries, equal off-diagonal entries), so its eigenvectors are again (1,1)(1,\allowbreak 1) and (1,−1)(1,\allowbreak -1). The eigenvalues are 5+4=95 + 4 = 9 and 5−4=15 - 4 = 1: check that C(1,1)=(9,9)\mathbf{C}(1,\allowbreak 1) = (9,\allowbreak 9) and C(1,−1)=(1,−1)\mathbf{C}(1,\allowbreak -1) = (1,\allowbreak -1), and that 9+1=109 + 1 = 10 is the trace and 9×1=25−169 \times 1 = 25 - 16 the determinant. The first principal component is (1,1)/2(1,\allowbreak 1)/\sqrt{2}, with variance 9, the number we computed from the projections above. It carries 9/(9+1)=90%9/(9 + 1) = 90\% of the total variance.

Every other direction has less spread than the first component. Measure one yourself.

Work it outSpread along another direction

The five points from the lesson have covariance C=[5445]\mathbf{C} = \begin{bmatrix} 5 & 4 \\ 4 & 5 \end{bmatrix}. What is the variance of the data along the unit direction u=(0.6,0.8)\mathbf{u} = (0.6,\allowbreak 0.8)? Enter a decimal to two decimal places.

variance

Type a number: 0.25, -2, 3/4 and sqrt(2) all work. Enter checks.

Now a larger cloud: 200 random points stretched by 2 along one axis and 0.5 along the other, then tilted by 30° and moved away from the origin, so you can watch PCA recover the tilt.

⌘+Enter runs · edit freelyPython sleeps until you run code

The code prints an angle of 27.5°, close to the 30° tilt but not equal to it, because 200 random points only approximate the shape they were drawn from. For the same reason the two variances come out as 3.352 and 0.199 rather than 22=42^2 = 4 and 0.52=0.250.5^2 = 0.25, the spreads the cloud was drawn with. The first component still holds 94.4% of the variance. Use np.linalg.eigh, not eig, for symmetric matrices: it is faster, guarantees real results and perpendicular eigenvectors, and sorts the eigenvalues (in increasing order, which is why the code reverses them).

To recap: center the data, form the symmetric covariance matrix C\mathbf{C}, and its eigenvectors, largest eigenvalue first, are the principal components; each eigenvalue is the variance along its direction. Now implement it, and test it on the five points and on a 3D cloud with a known shape.

Code itPCA from the covariance matrix

Implement principal component analysis with the covariance matrix and np.linalg.eigh.

  • covariance(X): center the columns of the (n,d)(n,\allowbreak d) data, then compute X~⊤X~/(n−1)\tilde{\mathbf{X}}^\top\tilde{\mathbf{X}}/(n - 1).
  • pca(X, k): the top kk unit eigenvectors as the rows of a (k,d)(k,\allowbreak d) array, largest variance first, and their variances.
  • project(X, components): the coordinates of each centered example along each component, shape (n,k)(n,\allowbreak k).
  • explained_variance_ratio(X, k): the fraction of the total variance in the top kk components.

The tests include the five points from the lesson, moved away from the origin so that forgetting to center shows up, and a 3D cloud with a known shape. Do not call np.cov in your code; the tests use it to check you.

⌘+Enter runsPython sleeps until you run code
Write your code where the starter says raise NotImplementedError, then press Run tests. Each check says what it expects.
Next: Singular values and the SVD