Lesson 10: Eigenvalues & Eigenvectors

USAAIO Lesson 10, from Week 4 on linear algebra, fully worked. It reads the eigen-equation Av=λv geometrically, expands the characteristic polynomial det(A−λI)=0 term by term, and solves every eigenvector from (A−λI)v=0 by hand. It states the spectral theorem and verifies A=VΛVᵀ by reconstruction, derives power iteration from the eigenbasis and traces it iteration by iteration, and uses deflation to find the second eigenpair. It then builds PCA from scratch - center, covariance, eigh, sort - and matches it to sklearn. One 2×2 matrix and one 10-point dataset run through the whole deck, and every eigenvalue, trace row, and coefficient was produced by real execution. The lesson runs to 60 slides.

Subject: Machine Learning · 112 slides · code lesson

Open the interactive version of this deck · Homework for this lesson

What this lesson covers

The lesson, slide by slide

1. Eigenvalues & Eigenvectors

Title

USAAIO · Lesson 10 · Week 4 (Linear Algebra)

The directions a matrix only stretches. We derive Av = λv from the geometry, expand det(A − λI) = 0 with no skipped algebra, solve every eigenvector by hand, prove the spectral theorem A = VΛVᵀ by reconstruction, and build power iteration and PCA from scratch — matched to NumPy and sklearn.

2. By the end of this lesson you can

Objectives

  1. Read Av = λv geometrically — eigenvectors are the axes of pure stretch, λ the stretch factor
  2. Find eigenvalues from the characteristic polynomial det(A − λI) = 0, expanded term by term, and each eigenvector from (A − λI)v = 0
  3. State and use the spectral theorem: symmetric matrices have real eigenvalues and orthonormal eigenvectors, A = VΛVᵀ, and verify it by reconstruction
  4. Derive power iteration from the eigenbasis, trace it to the dominant eigenpair, and get the next one by deflation
  5. Build PCA from scratch (center → covariance → eigh → sort) — eigenvalues are variances — and prove it matches sklearn.PCA

3. What survived from The Chain Rule & Backpropagation?

Warm-up

Discussion prompt

Before we open Lesson 10: Eigenvalues & Eigenvectors: without looking back, what was the main idea of The Chain Rule & Backpropagation, and what could you do by the end of it that you could not do before?

Hint: One sentence for the idea, one for the skill. If the second one is blank, that is the part to revisit.

Answer:

the single- and multi-variable chain rule, Jacobians, backprop as reverse-mode autodiff through a 2-layer network, the vanishing-gradient problem for sigmoid vs ReLU, and numerical gradient checking. Build a manual MLP backward pass and verify it against autograd.

4. The eigen-equation

Section

Part 1 of 6 — what Av = λv means

5. Our running matrix

Concept

One 2×2 matrix carries the first half of this lesson. It is symmetric (A = Aᵀ), which will matter enormously.

\[ A = \begin{bmatrix} 2 & 1 \\ 1 & 2 \end{bmatrix} \]

Read A as a transformation: hand it a vector, it hands back a new one. Most inputs come back rotated and rescaled. We are hunting the rare inputs that come back only rescaled.

6. Break it if you can: Our running matrix

Counterexample

Discussion prompt

One 2×2 matrix carries the first half of this lesson. It is symmetric (A = Aᵀ), which will matter enormously.

That is stated as though it always holds. Do one of two things: produce a case where it fails, or say precisely what rules such a case out. "It just does" is not on the menu.

Hint: Hunt at the extremes first — zero, one, negative, empty, equal. If every extreme survives, the reason they survive is the proof.

Answer:

Read A as a transformation: hand it a vector, it hands back a new one. Most inputs come back rotated and rescaled. We are hunting the rare inputs that come back only rescaled.

7. The eigen-equation Av = λv

Concept

An eigenvector v of A is a nonzero vector that A only scales — it keeps its direction. The scale factor λ is the eigenvalue for that vector.

\[ A v = \lambda v, \qquad v \neq 0 \]

eigenvector / eigenvalue — A direction v that A leaves pointing the same way, and the number λ telling how much A stretches it. 'Eigen' is German for 'own' — these are the matrix's OWN natural directions.

8. By analogy: The eigen-equation Av = λv

Analogy

Discussion prompt

Explain The eigen-equation Av = λv by analogy to something with no Machine Learning in it at all — a queue, a recipe, a map, a bank balance, whatever fits. Then say where your analogy breaks.

Hint: An analogy that never breaks is not an analogy, it is the same idea wearing a hat. Find the seam — that is the part that is actually new.

Answer:

An eigenvector v of A is a nonzero vector that A only scales — it keeps its direction. The scale factor λ is the eigenvalue for that vector.

9. Directions of pure stretch

Intuition

Picture A deforming a rubber sheet pinned at the origin. Almost every arrow drawn on the sheet tilts as the sheet stretches. Along an eigenvector the arrow keeps its heading and just grows or shrinks by λ.

λ > 1 stretches, 0 < λ < 1 compresses, λ < 0 flips the arrow around, and λ = 0 collapses that direction to a point — the mark of a singular matrix.

The eigenvectors are the transformation's skeleton: knowing them tells you everything A does, because any vector is a blend of eigen-directions, each stretched independently.

10. Teach it back: Directions of pure stretch

Explain it

Discussion prompt

Explain Directions of pure stretch to a student a year behind you. No notation, no jargon they have not met — and it still has to be true.

Hint: If your explanation needs a symbol they have never seen, you are describing the notation rather than the idea.

Answer:

λ > 1 stretches, 0 < λ < 1 compresses, λ < 0 flips the arrow around, and λ = 0 collapses that direction to a point — the mark of a singular matrix.

11. Why nonzero v forces singularity

Concept

Rewrite Av = λv by moving everything to one side. Since λv = λI v, we can factor:

\[ A v - \lambda v = 0 \;\Longrightarrow\; (A - \lambda I)\,v = 0 \]

We need a nonzero v solving this. A matrix that sends some nonzero vector to 0 cannot be invertible — its determinant must vanish. That single requirement is how we find λ.

12. The characteristic equation

Concept

So the eigenvalues are exactly the numbers λ that make A − λI singular:

\[ \det(A - \lambda I) = 0 \]

Expanding that determinant produces a polynomial in λ — the characteristic polynomial. Its roots are the eigenvalues; then we solve (A − λI)v = 0 for the eigenvector of each root.

13. Guess the shape of the answer: Form A − λI, then its determinant

Estimation

Predict first

Subtract λ from each diagonal entry of A (that is what −λI does) and write the matrix out:

Commit before you compute: what does Form A − λI, then its determinant come out to? A rough magnitude and the right form is enough — the point is to have something concrete to be wrong about.

Correct: Determinant of a 2×2 is (top-left)(bottom-right) − (top-right)(bottom-left)

Why: A prediction you can defend turns the computation into a check rather than a leap of faith — and an answer that contradicts it is caught on the spot. The standard det[[a,b],[c,d]] = ad − bc rule.

14. Form A − λI, then its determinant

Worked example

Subtract λ from each diagonal entry of A (that is what −λI does) and write the matrix out:

Build A − λI by subtracting λ down the diagonal

Why: λI has λ on the diagonal and 0 elsewhere, so only the diagonal entries change.

\[ A - \lambda I = \begin{bmatrix} 2 - \lambda & 1 \\ 1 & 2 - \lambda \end{bmatrix} \]

Determinant of a 2×2 is (top-left)(bottom-right) − (top-right)(bottom-left)

Why: The standard det[[a,b],[c,d]] = ad − bc rule.

\[ \det(A - \lambda I) = (2-\lambda)(2-\lambda) - (1)(1) \]

15. Decode the notation: Form A − λI, then its determinant

Notation

Annotate

From Form A − λI, then its determinant — read this one piece at a time. What is each part doing?

On: \( A - \lambda I = \begin{bmatrix} 2 - \lambda & 1 \\ 1 & 2 - \lambda \end{bmatrix} \)

  • λI has λ on the diagonal and 0 elsewhere, so only the diagonal entries change.
  • The standard det[[a,b],[c,d]] = ad − bc rule.

16. What has to happen first: Expand to the characteristic polynomial

Ranking

Put in order

Put the moves of Expand to the characteristic polynomial into the order they have to happen.

  1. Multiply out (2 − λ)²
  2. Collect constants: 4 − 1 = 3
  3. Factor: two numbers multiplying to 3, adding to 4

Why: These are the moves of the worked example in the order it makes them, and each one is set up by the one before it. (2 − λ)² = 4 − 4λ + λ². FOIL, no shortcut.

17. Expand to the characteristic polynomial

Worked example

Multiply out (2 − λ)²

Why: (2 − λ)² = 4 − 4λ + λ². FOIL, no shortcut.

\[ (2-\lambda)^2 - 1 = \lambda^2 - 4\lambda + 4 - 1 \]

Collect constants: 4 − 1 = 3

Why: Combine the number terms into one.

\[ \lambda^2 - 4\lambda + 3 = 0 \]

Factor: two numbers multiplying to 3, adding to 4

Why: 3 = 1·3 and 1 + 3 = 4, so it factors cleanly.

\[ (\lambda - 1)(\lambda - 3) = 0 \;\Longrightarrow\; \lambda = 1 \;\text{or}\; \lambda = 3 \]

18. Draw the shape of it: Expand to the characteristic polynomial

Blank canvas

Draw it

Draw what Expand to the characteristic polynomial just did — the shape of it, not the line-by-line working. One picture, labels only where you need them. Then check it against the steps: anything you could not draw is a step you followed rather than understood.

19. Two free checks: trace and determinant

Concept

Before finding eigenvectors, sanity-check the eigenvalues. For any square matrix the eigenvalues sum to the trace and multiply to the determinant.

\[ \sum_i \lambda_i = \operatorname{tr}(A), \qquad \prod_i \lambda_i = \det(A) \]

Here 1 + 3 = 4 = tr(A) (the diagonal 2 + 2) and 1 · 3 = 3 = det(A) (2·2 − 1·1). Both agree, so λ = 1, 3 is right. Use this on every exam problem.

20. Plan first: Eigenvector for λ = 3

Step zero

Discussion prompt

Eigenvector for λ = 3 — before any calculation: what is the plan? Name the moves in order, in plain English, without doing the arithmetic.

Hint: It starts with: Substitute λ = 3 into A − λI

Answer:

  1. Substitute λ = 3 into A − λI
  2. Row 1 says −v₁ + v₂ = 0, so v₁ = v₂
  3. Pick v = [1, 1], then normalize to unit length

21. Eigenvector for λ = 3

Worked example

Plug λ = 3 into (A − λI)v = 0 and solve for the direction v = [v₁, v₂]:

Substitute λ = 3 into A − λI

Why: 2 − 3 = −1 on the diagonal.

\[ (A - 3I)v = \begin{bmatrix} -1 & 1 \\ 1 & -1 \end{bmatrix}\begin{bmatrix} v_1 \\ v_2 \end{bmatrix} = \begin{bmatrix} 0 \\ 0 \end{bmatrix} \]

Row 1 says −v₁ + v₂ = 0, so v₁ = v₂

Why: Both rows give the same equation (they must — the matrix is singular). One free parameter remains, which is why an eigenvector is a whole direction, not a single point.

Pick v = [1, 1], then normalize to unit length

Why: Divide by ‖[1,1]‖ = √2 so the eigenvector has length 1, the convention NumPy uses.

\[ v_{(\lambda=3)} = \tfrac{1}{\sqrt{2}}\begin{bmatrix} 1 \\ 1 \end{bmatrix} \approx \begin{bmatrix} 0.707 \\ 0.707 \end{bmatrix} \]

22. Work backwards from the answer: Eigenvector for λ = 3

Reverse engineer

Discussion prompt

Work backwards. The example finished here:

Pick v = [1, 1], then normalize to unit length

What was it asked to do, and what must it have been given? Reconstruct the problem from its answer.

Hint: Every quantity in the result had to enter somewhere. Account for each one.

Answer:

Plug λ = 3 into (A − λI)v = 0 and solve for the direction v = [v₁, v₂]:

23. What has to happen first: Eigenvector for λ = 1

Ranking

Put in order

Put the moves of Eigenvector for λ = 1 into the order they have to happen.

  1. Substitute λ = 1: diagonal becomes 2 − 1 = 1
  2. Row 1 says v₁ + v₂ = 0, so v₁ = −v₂
  3. Pick v = [1, −1], normalize by √2

Why: These are the moves of the worked example in the order it makes them, and each one is set up by the one before it. The two components are opposite.

24. Eigenvector for λ = 1

Worked example

Substitute λ = 1: diagonal becomes 2 − 1 = 1

Why: Same procedure, other root.

\[ (A - 1I)v = \begin{bmatrix} 1 & 1 \\ 1 & 1 \end{bmatrix}\begin{bmatrix} v_1 \\ v_2 \end{bmatrix} = \begin{bmatrix} 0 \\ 0 \end{bmatrix} \]

Row 1 says v₁ + v₂ = 0, so v₁ = −v₂

Why: The two components are opposite. Again one free parameter.

Pick v = [1, −1], normalize by √2

Why: Unit-length convention.

\[ v_{(\lambda=1)} = \tfrac{1}{\sqrt{2}}\begin{bmatrix} 1 \\ -1 \end{bmatrix} \approx \begin{bmatrix} 0.707 \\ -0.707 \end{bmatrix} \]

25. Say it in words: Eigenvector for λ = 1

Translation

\( (A - 1I)v = \begin{bmatrix} 1 & 1 \\ 1 & 1 \end{bmatrix}\begin{bmatrix} v_1 \\ v_2 \end{bmatrix} = \begin{bmatrix} 0 \\ 0 \end{bmatrix} \)

Draw it

Translate both ways. First write the expression above as a sentence with no symbols in it at all. Then cover it, and write your sentence back as notation. If the two versions disagree, the disagreement is the thing to fix.

26. What has to be given first: Verify Av = λv, and check against NumPy

Missing information

Discussion prompt

Never trust an eigenpair you haven't plugged back in. Multiply A by each v and confirm you get λv. This snippet is complete and runnable:

What do you need to know — or decide — before the first line can be written? List everything the problem has to hand you.

Hint: Anything you would have to invent to get started is a thing the problem must supply.

Answer:

Exactly 3v3 — the pair checks out. Likewise A v1 = [0.707, −0.707] = 1·v1.

27. Verify Av = λv, and check against NumPy

Worked example

Never trust an eigenpair you haven't plugged back in. Multiply A by each v and confirm you get λv. This snippet is complete and runnable:

import numpy as np
A = np.array([[2., 1.], [1., 2.]])
v3 = np.array([1., 1.]) / np.sqrt(2)   # claimed eigvec for lambda=3
v1 = np.array([1., -1.]) / np.sqrt(2)  # claimed eigvec for lambda=1
print(A @ v3, 3 * v3)                  # should match
print(A @ v1, 1 * v1)                  # should match
vals, vecs = np.linalg.eigh(A)         # symmetric solver
print(vals)
print(vecs)

A v3 = [2.121, 2.121] = 3 · [0.707, 0.707]

Why: Exactly 3v3 — the pair checks out. Likewise A v1 = [0.707, −0.707] = 1·v1.

quantityvalue (verified)
A @ v3[2.121, 2.121]
3 * v3[2.121, 2.121]
np.linalg.eigh vals[1.0, 3.0]
eigh vecs (columns)[[−0.707, 0.707], [0.707, 0.707]]

28. Which is which, by value (verified)

Discrimination

Sort into buckets

Sort these by value (verified), from memory, without looking back at Verify Av = λv, and check against NumPy. Telling them apart on the spot is the skill; the table is only where the answer happens to be written down.

[2.121, 2.121]
A @ v3; 3 * v3
[1.0, 3.0]
np.linalg.eigh vals
[[−0.707, 0.707], [0.707, 0.707]]
eigh vecs (columns)
g1
value (verified) is "[2.121, 2.121]" for A @ v3, 3 * v3 — that is what the table on "Verify Av = λv, and check against NumPy" records, and it is the single property separating this group from the rest.
g2
value (verified) is "[1.0, 3.0]" for np.linalg.eigh vals — that is what the table on "Verify Av = λv, and check against NumPy" records, and it is the single property separating this group from the rest.
g3
value (verified) is "[[−0.707, 0.707], [0.707, 0.707]]" for eigh vecs (columns) — that is what the table on "Verify Av = λv, and check against NumPy" records, and it is the single property separating this group from the rest.

29. A sign is not a new answer

Concept

NumPy returned the λ = 3 vector as [0.707, 0.707] and the λ = 1 vector as [−0.707, 0.707] — the second flipped from our [0.707, −0.707].

That's fine: if v is an eigenvector, so is −v (same line, opposite arrow), because A(−v) = −Av = −λv = λ(−v). An eigenvector names a direction, and its sign is arbitrary.

So when you compare your eigenvectors to a library's, compare directions (up to sign), never raw components. This bites everyone in the PCA section — remember it now.

30. Something is wrong here: are the diagonal entries the eigenvalues?

Anomaly

Predict first

A student writes this, and it looks reasonable:

The eigenvalues of [[3,1],[0,2]] turn out to be 3 and 2 — its diagonal. So just read eigenvalues off the diagonal of any matrix.

It is wrong. Say what breaks — and say it before you turn the page.

Correct: Generalizes a rule that only holds for TRIANGULAR matrices.

Diagonal = eigenvalues only for triangular (or diagonal) matrices, where the determinant is the product of diagonal entries. Otherwise solve det(A − λI) = 0.

Why: Generalizes a rule that only holds for TRIANGULAR matrices. A is not triangular, and we just proved its eigenvalues are 1 and 3 — nowhere near 2 and 2.

31. Trap: are the diagonal entries the eigenvalues?

Trap

The trap

The eigenvalues of [[3,1],[0,2]] turn out to be 3 and 2 — its diagonal. So just read eigenvalues off the diagonal of any matrix.

Read eigenvalues of A = [[2,1],[1,2]] off the diagonal → 2 and 2

Why: Generalizes a rule that only holds for TRIANGULAR matrices. A is not triangular, and we just proved its eigenvalues are 1 and 3 — nowhere near 2 and 2.

The fix

Diagonal = eigenvalues only for triangular (or diagonal) matrices, where the determinant is the product of diagonal entries. Otherwise solve det(A − λI) = 0.

det([[2−λ,1],[1,2−λ]]) = (2−λ)² − 1 = 0 → λ = 1, 3

Why: The off-diagonal 1s shift the eigenvalues off the diagonal. Verified: np.linalg.eigh returns 1 and 3, not 2 and 2.

32. The spectral theorem

Section

Part 2 of 6 — the symmetric case

33. Why symmetric matrices are the good case

Intuition

Almost every matrix you meet in ML is symmetric: covariance matrices, Gram matrices XᵀX, Hessians of a loss, kernel matrices. So the symmetric case isn't a special corner — it's the main event.

General matrices can misbehave: complex eigenvalues, eigenvectors that aren't perpendicular, sometimes too few eigenvectors to span the space. Symmetric matrices never do any of that.

34. The spectral theorem

Concept

Spectral theorem. If A = Aᵀ (real symmetric), then A has real eigenvalues and a full set of orthonormal eigenvectors — perpendicular and unit length.

Stack those eigenvectors as the columns of V and the eigenvalues on the diagonal of Λ. Then A factors as:

\[ A = V \Lambda V^\top, \qquad V^\top V = I \]

VᵀV = I says the eigenvectors are orthonormal, so V⁻¹ = Vᵀ — the inverse is free. This eigen-decomposition is the engine under PCA, SVD, and spectral clustering.

35. Reading A = VΛVᵀ for our matrix

Worked example

For A = [[2,1],[1,2]], put the two orthonormal eigenvectors in V and the eigenvalues in Λ:

\[ V = \tfrac{1}{\sqrt2}\begin{bmatrix} 1 & 1 \\ -1 & 1 \end{bmatrix}, \qquad \Lambda = \begin{bmatrix} 1 & 0 \\ 0 & 3 \end{bmatrix} \]

Column order of V matches diagonal order of Λ

Why: Column 1 of V is the λ=1 eigenvector, column 2 is the λ=3 eigenvector — the pairing must line up or the reconstruction fails.

Check orthonormality: v₁·v₃ = 0

Why: (1·1 + (−1)·1)/2 = 0. Perpendicular, as the spectral theorem promised for a symmetric matrix.

36. Predict the next row: Reconstruct A from its eigen-decomposition

Pattern

Predict first

The table runs: V @ diag(vals) @ V.T | [[2., 1.], [1., 2.]] · np.allclose(recon, A) | True

In Reconstruct A from its eigen-decomposition, given the rows so far: what is the next one — the row where quantity is V.T @ V?

Correct: V.T @ V | [[1., 0.], [0., 1.]] (identity)

quantityvalue (verified)
V @ diag(vals) @ V.T[[2., 1.], [1., 2.]]
np.allclose(recon, A)True
V.T @ V[[1., 0.], [0., 1.]] (identity)

Why: The relationship between the columns, not the individual numbers, is what generates the next row. np.allclose prints True. The decomposition is faithful: A really is 'rotate into eigen-axes (Vᵀ), stretch by Λ, rotate back (V)'.

37. Reconstruct A from its eigen-decomposition

Worked example

If the theorem is real, multiplying V Λ Vᵀ back together must return A exactly. Verify it — runnable as written:

import numpy as np
A = np.array([[2., 1.], [1., 2.]])
vals, V = np.linalg.eigh(A)          # vals=[1,3], V orthonormal
Lam = np.diag(vals)
recon = V @ Lam @ V.T                 # V Lambda V^T
print(recon)
print(np.allclose(recon, A))          # exact match?
print(V.T @ V)                        # should be the identity

V Λ Vᵀ returns [[2,1],[1,2]] — exactly A

Why: np.allclose prints True. The decomposition is faithful: A really is 'rotate into eigen-axes (Vᵀ), stretch by Λ, rotate back (V)'.

quantityvalue (verified)
V @ diag(vals) @ V.T[[2., 1.], [1., 2.]]
np.allclose(recon, A)True
V.T @ V[[1., 0.], [0., 1.]] (identity)

38. Fill in: value (verified) for Reconstruct A from its eigen-decomposition

Comparison

Comparison matrix

From Reconstruct A from its eigen-decomposition: refill the value (verified) column from what you know. The rest of the table is as it appeared.

quantityvalue (verified)
V @ diag(vals) @ V.T[[2., 1.], [1., 2.]]
np.allclose(recon, A)True
V.T @ V[[1., 0.], [0., 1.]] (identity)

39. A = VΛVᵀ is rotate–stretch–rotate

Intuition

The decomposition reads right-to-left as three moves applied to any input vector: Vᵀ rotates it into the eigen-axes, Λ stretches each axis by its eigenvalue, then V rotates back to the original frame.

So a symmetric matrix is never a complicated tangle — it's just stretch along perpendicular axes. The eigenvectors name those axes; the eigenvalues are the stretch amounts. That's the whole picture.

It also explains det(A) = ∏λᵢ: the rotations preserve area, so the only area-scaling is the product of the diagonal stretches in Λ.

40. Eigenvalues classify a symmetric matrix

Concept

The signs of a symmetric matrix's eigenvalues tell you its type — which is exactly how we test whether a loss surface is a bowl (a minimum), a dome, or a saddle.

all eigenvaluesmatrix isquadratic zᵀAz
> 0positive definite> 0 for every z ≠ 0 (a bowl)
≥ 0positive semidefinite≥ 0 (a bowl with a flat floor)
mixed signsindefinitepositive some ways, negative others (a saddle)

Our A = [[2,1],[1,2]] has eigenvalues 1 and 3 — both positive, so it's positive definite. Covariance matrices are always at least PSD, which is why PCA's variances (the eigenvalues) can never be negative.

41. What each one costs: Eigenvalues classify a symmetric matrix

Trade off

Comparison matrix

From Eigenvalues classify a symmetric matrix: every row here is a choice with a cost. Fill the quadratic zᵀAz column, then say which row you would actually pick and what you give up for it.

all eigenvaluesmatrix isquadratic zᵀAz
> 0positive definite> 0 for every z ≠ 0 (a bowl)
≥ 0positive semidefinite≥ 0 (a bowl with a flat floor)
mixed signsindefinitepositive some ways, negative others (a saddle)

42. eig vs eigh — pick the right tool

Concept

NumPy has two solvers. np.linalg.eig works on any square matrix but can return complex numbers and non-orthogonal, unsorted eigenvectors. np.linalg.eigh assumes the matrix is symmetric (Hermitian).

For symmetric A, always use eigh: it's faster, guarantees real eigenvalues returned in ascending order, and gives genuinely orthonormal eigenvectors. Using eig on a covariance matrix invites tiny imaginary parts and messy vectors.

43. Restore the missing line: A non-symmetric matrix behaves differently

Fill the middle

Fill in the blanks

From A non-symmetric matrix behaves differently — one line has had its right-hand side removed. Put it back.

import numpy as np
B = np.array([[3., 1.], [0., 2.]])
vals, vecs = np.linalg.eig(B) # general solver
print(vals) # [3., 2.]
print(vecs)
v_a = vecs[:, 0]; v_b = vecs[:, 1]
print(v_a @ v_b) # dot product != 0

Why: v_a is what everything below it consumes, so the wrong expression here fails later and somewhere else. Non-symmetric ⇒ the spectral theorem does NOT apply ⇒ no orthogonality guarantee.

44. A non-symmetric matrix behaves differently

Worked example

Contrast with the triangular B = [[3,1],[0,2]]. Its eigenvalues sit on the diagonal (it's triangular), but its eigenvectors are not perpendicular:

import numpy as np
B = np.array([[3., 1.], [0., 2.]])
vals, vecs = np.linalg.eig(B)          # general solver
print(vals)                            # [3., 2.]
print(vecs)
v_a = vecs[:, 0]; v_b = vecs[:, 1]
print(v_a @ v_b)                       # dot product != 0

Eigenvectors [1,0] and [−0.707, 0.707] have dot product 0.707, not 0

Why: Non-symmetric ⇒ the spectral theorem does NOT apply ⇒ no orthogonality guarantee. The columns still span the plane, just not at right angles.

quantityvalue (verified)
eig vals[3., 2.]
eigvec for λ=3[1., 0.]
eigvec for λ=2[−0.707, 0.707]
dot of the two eigvecs0.707 (NOT orthogonal)

45. Something is wrong here: are eigenvectors always orthogonal?

Anomaly

Predict first

A student writes this, and it looks reasonable:

Eigenvectors form the natural axes of a transform, so they must be perpendicular — orthogonalize or dot them freely.

It is wrong. Say what breaks — and say it before you turn the page.

Correct: We just measured it fail: B = [[3,1],[0,2]] has eigenvectors [1,0] and [−0.707,0.707] with dot product 0.707.

Orthonormal eigenvectors are guaranteed only by the spectral theorem — i.e. for symmetric A.

Why: We just measured it fail: B = [[3,1],[0,2]] has eigenvectors [1,0] and [−0.707,0.707] with dot product 0.707. Orthogonality is not automatic.

46. Trap: are eigenvectors always orthogonal?

Trap

The trap

Eigenvectors form the natural axes of a transform, so they must be perpendicular — orthogonalize or dot them freely.

Assume ANY matrix's eigenvectors are orthogonal

Why: We just measured it fail: B = [[3,1],[0,2]] has eigenvectors [1,0] and [−0.707,0.707] with dot product 0.707. Orthogonality is not automatic.

The fix

Orthonormal eigenvectors are guaranteed only by the spectral theorem — i.e. for symmetric A.

Symmetric ⇒ orthonormal eigenvectors; general matrix ⇒ not necessarily

Why: This is exactly why PCA (covariance is symmetric) yields perpendicular components, while a generic linear map need not. Check A = Aᵀ before you assume perpendicular axes.

47. Break it on purpose: are eigenvectors always orthogonal?

Break the constraint

Discussion prompt

The rule this trap just fixed:

Orthonormal eigenvectors are guaranteed only by the spectral theorem — i.e. for symmetric A.

Now break it on purpose. Build a case that violates it and follow the consequences until something visibly fails. Where does the failure first show up — and would you have noticed it if you had not been looking?

Hint: The dangerous rules are the ones whose violation still produces an answer. If yours fails loudly, try to find one that fails quietly.

Answer:

We just measured it fail: B = [[3,1],[0,2]] has eigenvectors [1,0] and [−0.707,0.707] with dot product 0.707. Orthogonality is not automatic.

48. Power iteration

Section

Part 3 of 6 — the dominant eigenpair

49. You often want just the top one

Intuition

Full eigen-decomposition costs a lot on a big matrix, and often you only need the dominant eigenvector — the direction of largest stretch (largest |λ|). PageRank, PCA's first component, and spectral embeddings all want exactly that top vector.

Power iteration finds it with nothing but repeated matrix–vector multiplies: start anywhere, keep applying A, renormalize, and the dominant direction takes over.

50. The power-iteration update

Concept

Pick any starting vector b₀. Repeat: multiply by A, then divide by the length to keep it unit-sized.

\[ b_{k+1} = \frac{A\,b_k}{\lVert A\,b_k \rVert} \]

The renormalize step is not optional — without it, entries either blow up to infinity or shrink to zero. We care about the direction, so we rescale to length 1 every step.

Once b settles, recover the eigenvalue from the Rayleigh quotient bᵀAb (with ‖b‖ = 1).

51. Guess the shape of the answer: Why it converges: work in the eigenbasis

Estimation

Predict first

Write the start b₀ as a blend of eigenvectors: b₀ = c₃v₃ + c₁v₁ (dominant v₃ with λ=3, other v₁ with λ=1). Applying A scales each piece by its own eigenvalue:

Commit before you compute: what does Why it converges: work in the eigenbasis come out to? A rough magnitude and the right form is enough — the point is to have something concrete to be wrong about.

Correct: For b₀ = [1,0]: ratio small/big = 1/3, 1/9, 1/27, …

Why: A prediction you can defend turns the computation into a check rather than a leap of faith — and an answer that contradicts it is caught on the spot. Verified: 0.333, 0.111, 0.037, 0.0041 at k = 1,2,3,5.

52. Why it converges: work in the eigenbasis

Worked example

Write the start b₀ as a blend of eigenvectors: b₀ = c₃v₃ + c₁v₁ (dominant v₃ with λ=3, other v₁ with λ=1). Applying A scales each piece by its own eigenvalue:

\[ A^k b_0 = c_3\,3^k\, v_3 \;+\; c_1\,1^k\, v_1 \]

The dominant term grows like 3ᵏ; the other stays flat at 1ᵏ

Why: The ratio of the small piece to the big piece is (1/3)ᵏ — it shrinks fast. After k steps the vector is almost pure v₃.

For b₀ = [1,0]: ratio small/big = 1/3, 1/9, 1/27, …

Why: Verified: 0.333, 0.111, 0.037, 0.0041 at k = 1,2,3,5. Convergence speed is set by |λ₂/λ₁| — the closer that ratio to 1, the slower.

k3ᵏ (dominant)1ᵏ (other)ratio other/dominant
1310.3333
2910.1111
32710.0370
524310.0041

53. What stays fixed: Why it converges: work in the eigenbasis

Invariant

Step through it

Step through Why it converges: work in the eigenbasis one row at a time. One of these columns never changes — find it, and say why it cannot.

  1. Step 1: k is 1
  2. Step 2: k is 2
  3. Step 3: k is 3
  4. Step 4: k is 5

54. Restore the missing line: Trace power iteration on A, step by step

Fill the middle

Fill in the blanks

From Trace power iteration on A, step by step — one line has had its right-hand side removed. Put it back.

import numpy as np
A = np.array([[2., 1.], [1., 2.]])
b = np.array([1., 0.])
for i in range(6):
Ab = A @ b
b = Ab / np.linalg.norm(Ab)
print(i + 1, b.round(4), round(b @ A @ b, 5))

Why: Ab is what everything below it consumes, so the wrong expression here fails later and somewhere else. Divide [2,1] by 2.236. Rayleigh bᵀAb = 2.8, already climbing toward 3.

55. Trace power iteration on A, step by step

Worked example

Start from b₀ = [1, 0]. Each row: apply A, renormalize, and read the Rayleigh quotient. Complete, runnable snippet:

import numpy as np
A = np.array([[2., 1.], [1., 2.]])
b = np.array([1., 0.])
for i in range(6):
    Ab = A @ b
    b = Ab / np.linalg.norm(Ab)
    print(i + 1, b.round(4), round(b @ A @ b, 5))

Step 1: A[1,0] = [2,1], length √5 = 2.236 → b = [0.8944, 0.4472]

Why: Divide [2,1] by 2.236. Rayleigh bᵀAb = 2.8, already climbing toward 3.

iterb (normalized)Rayleigh bᵀAb
1[0.8944, 0.4472]2.80000
2[0.7809, 0.6247]2.97561
3[0.7328, 0.6805]2.99726
4[0.7158, 0.6983]2.99970
5[0.7100, 0.7042]2.99997
6[0.7081, 0.7061]3.00000

Six steps reach [0.707, 0.707] and λ = 3.0

Why: Exactly the dominant eigenpair we solved by hand. The Rayleigh quotient converges even faster than the vector — it's accurate to 5 decimals by step 6.

56. Inspect it line by line: Trace power iteration on A, step by step

Error analysis

Annotate

Walk the callouts on Trace power iteration on A, step by step. Each one is a place this is easy to get subtly wrong.

  • Divide [2,1] by 2.236. Rayleigh bᵀAb = 2.8, already climbing toward 3.
  • Exactly the dominant eigenpair we solved by hand. The Rayleigh quotient converges even faster than the vector — it's accurate to 5 decimals by step 6.

57. Deflation: getting the next eigenvector

Concept

Power iteration only finds the top eigenvector. To get the second, deflate: subtract the dominant piece from A so its eigenvalue drops to 0, leaving the next one on top.

\[ A' = A - \lambda_1\, v_1 v_1^\top \]

For symmetric A, A' has the same eigenvectors but with λ₁ replaced by 0. Power-iterate A' and you land on the second eigenvector. Repeat to peel off eigenpairs one at a time.

58. Restore the missing line: Deflate A and recover the second eigenpair

Fill the middle

Fill in the blanks

From Deflate A and recover the second eigenpair — one line has had its right-hand side removed. Put it back.

import numpy as np
A = np.array([[2., 1.], [1., 2.]])
v3 = np.array([1., 1.]) / np.sqrt(2)
A_def = A - 3.0 * np.outer(v3, v3) # remove the lambda=3 piece
b = np.array([1., 0.])
for _ in range(30):
b = A_def @ b
b = b / np.linalg.norm(b)
print(A_def)
print(b.round(4), round(b @ A_def @ b, 4))

Why: b is what everything below it consumes, so the wrong expression here fails later and somewhere else. The λ=3 direction is now dead (eigenvalue 0), so the λ=1 direction dominates A'.

59. Deflate A and recover the second eigenpair

Worked example

Subtract 3·v₃v₃ᵀ from A, then power-iterate the result. It should converge to the λ = 1 eigenvector. Runnable:

import numpy as np
A = np.array([[2., 1.], [1., 2.]])
v3 = np.array([1., 1.]) / np.sqrt(2)
A_def = A - 3.0 * np.outer(v3, v3)     # remove the lambda=3 piece
b = np.array([1., 0.])
for _ in range(30):
    b = A_def @ b
    b = b / np.linalg.norm(b)
print(A_def)
print(b.round(4), round(b @ A_def @ b, 4))

A' = [[0.5, −0.5], [−0.5, 0.5]] and power iteration → [0.707, −0.707], λ = 1.0

Why: The λ=3 direction is now dead (eigenvalue 0), so the λ=1 direction dominates A'. We recovered the exact second eigenpair without eig.

quantityvalue (verified)
A − 3·v₃v₃ᵀ[[0.5, −0.5], [−0.5, 0.5]]
converged b[0.707, −0.707]
eigenvalue bᵀA'b1.0

60. Something is wrong here: forgetting to renormalize

Anomaly

Predict first

A student writes this, and it looks reasonable:

Power iteration is just 'multiply by A a lot', so loop b = A @ b and read off the direction at the end — skip the divide.

It is wrong. Say what breaks — and say it before you turn the page.

Correct: Each multiply scales the dominant part by ~3, so after 30 steps entries are ~3³⁰ ≈ 2e14 and keep growing — eventually overflow to inf, and the eigenvalue read-out bᵀAb explodes instead of settling.

Divide by the length every iteration so the vector stays unit-sized — we only care about its direction.

Why: Each multiply scales the dominant part by ~3, so after 30 steps entries are ~3³⁰ ≈ 2e14 and keep growing — eventually overflow to inf, and the eigenvalue read-out bᵀAb explodes instead of settling.

61. Trap: forgetting to renormalize

Trap

The trap

Power iteration is just 'multiply by A a lot', so loop b = A @ b and read off the direction at the end — skip the divide.

b = A @ b (no renormalize), 30 times

Why: Each multiply scales the dominant part by ~3, so after 30 steps entries are ~3³⁰ ≈ 2e14 and keep growing — eventually overflow to inf, and the eigenvalue read-out bᵀAb explodes instead of settling.

The fix

Divide by the length every iteration so the vector stays unit-sized — we only care about its direction.

b = A @ b; b = b / np.linalg.norm(b)

Why: Renormalizing keeps magnitudes bounded while the DIRECTION still converges to the dominant eigenvector. The eigenvalue then comes cleanly from the Rayleigh quotient bᵀAb.

62. Eigenvectors are PCA

Section

Part 4 of 6 — the payoff

63. The idea behind PCA

Intuition

Given a cloud of data points, PCA finds the directions of greatest spread. The first principal component is the single line along which the data varies most; the next is the most-varying direction perpendicular to it, and so on.

Those directions turn out to be eigenvectors of the covariance matrix, and the variance captured along each is its eigenvalue. All the machinery we just built — symmetric matrices, eigh, sorting by eigenvalue — is exactly what PCA runs.

64. Our running dataset

Concept

Ten 2-D points, strongly correlated (as x grows, so does y). This one dataset carries the rest of the deck.

pointxy
12.52.4
20.50.7
32.22.9
………
101.10.9

Mean of the columns is [1.81, 1.91]. Because the two features rise together, the cloud is a tilted cigar — PCA should find that tilt as PC1.

65. Watch it run: Our running dataset

Pattern

Step through it

Step through Our running dataset one row at a time. What is driving the change, and what would the row after the last one be?

  1. Step 1: point is 1
  2. Step 2: point is 2
  3. Step 3: point is 3
  4. Step 4: point is …
  5. Step 5: point is 10

66. The covariance matrix

Concept

First center the data (subtract the mean), then form the covariance. With centered Xᶜ and n rows:

\[ C = \frac{X_c^\top X_c}{n - 1} \]

C is 2×2, symmetric (Xᶜᵀ Xᶜ always is), with variances on the diagonal and the covariance off it. Symmetric ⇒ the spectral theorem applies ⇒ real eigenvalues, orthonormal eigenvectors. That's why eigh is the right solver.

67. Teach it back: The covariance matrix

Explain it

Discussion prompt

Explain The covariance matrix to a student a year behind you. No notation, no jargon they have not met — and it still has to be true.

Hint: If your explanation needs a symbol they have never seen, you are describing the notation rather than the idea.

Answer:

First center the data (subtract the mean), then form the covariance. With centered Xᶜ and n rows:

68. Picture it first: What the covariance eigenvectors point at

Picture it

Figure (svg): A tilted elliptical cloud of dots with a long arrow along its major axis labeled PC1 and a short perpendicular arrow labeled PC2.

PC1 follows the cloud's long axis; PC2 is perpendicular and short. The eigenvalues are how far the data spreads along each arrow.

Discussion prompt

Read the picture before the words. What is this showing, and what is the one thing it is built to make obvious? Commit to an answer, then read on.

Hint: Name the parts, then say what changes between them — and if nothing changes, say what is being held still.

Answer:

The covariance matrix encodes the shape of the data cloud: the diagonal says how spread the cloud is along each raw axis, the off-diagonal says how tilted it is.

69. What the covariance eigenvectors point at

Intuition

The covariance matrix encodes the shape of the data cloud: the diagonal says how spread the cloud is along each raw axis, the off-diagonal says how tilted it is.

Its top eigenvector points along the cloud's longest axis — the direction the cigar-shaped cloud stretches. The second eigenvector is perpendicular (spectral theorem: covariance is symmetric) and points across its narrow width.

Figure (svg): A tilted elliptical cloud of dots with a long arrow along its major axis labeled PC1 and a short perpendicular arrow labeled PC2.

PC1 follows the cloud's long axis; PC2 is perpendicular and short. The eigenvalues are how far the data spreads along each arrow.

70. By analogy: What the covariance eigenvectors point at

Analogy

Discussion prompt

Explain What the covariance eigenvectors point at by analogy to something with no Machine Learning in it at all — a queue, a recipe, a map, a bank balance, whatever fits. Then say where your analogy breaks.

Hint: An analogy that never breaks is not an analogy, it is the same idea wearing a hat. Find the seam — that is the part that is actually new.

Answer:

The covariance matrix encodes the shape of the data cloud: the diagonal says how spread the cloud is along each raw axis, the off-diagonal says how tilted it is.

71. Plan first: Build the covariance entry by entry

Step zero

Discussion prompt

Build the covariance entry by entry — before any calculation: what is the plan? Name the moves in order, in plain English, without doing the arithmetic.

Hint: It starts with: Top-left = Σ(xᶜ)² / 9 = 5.549 / 9 = 0.6166

Answer:

  1. Top-left = Σ(xᶜ)² / 9 = 5.549 / 9 = 0.6166
  2. Bottom-right = Σ(yᶜ)² / 9 = 6.449 / 9 = 0.7166
  3. Off-diagonal = Σ(xᶜ·yᶜ) / 9 = 5.539 / 9 = 0.6154

72. Build the covariance entry by entry

Worked example

Center each column, then each covariance entry is a sum of products over the 10 points divided by n − 1 = 9. The three distinct entries (it's symmetric):

Top-left = Σ(xᶜ)² / 9 = 5.549 / 9 = 0.6166

Why: Variance of the centered x column.

Bottom-right = Σ(yᶜ)² / 9 = 6.449 / 9 = 0.7166

Why: Variance of the centered y column.

Off-diagonal = Σ(xᶜ·yᶜ) / 9 = 5.539 / 9 = 0.6154

Why: Covariance of x and y — large and positive, confirming the features move together.

\[ C = \begin{bmatrix} 0.6166 & 0.6154 \\ 0.6154 & 0.7166 \end{bmatrix} \]

73. Draw the shape of it: Build the covariance entry by entry

Blank canvas

Draw it

Draw what Build the covariance entry by entry just did — the shape of it, not the line-by-line working. One picture, labels only where you need them. Then check it against the steps: anything you could not draw is a step you followed rather than understood.

74. What has to happen first: Eigenvalues of C by the characteristic polynomial

Ranking

Put in order

Put the moves of Eigenvalues of C by the characteristic polynomial into the order they have to happen.

  1. Characteristic polynomial: λ² − tr·λ + det = 0
  2. Quadratic formula, discriminant = 1.3331² − 4·0.06302 = 1.5251
  3. λ₁ = 1.2840 (PC1 variance), λ₂ = 0.0491 (PC2 variance)

Why: These are the moves of the worked example in the order it makes them, and each one is set up by the one before it. For a 2×2, det(C − λI) = λ² − tr(C)λ + det(C).

75. Eigenvalues of C by the characteristic polynomial

Worked example

Use trace and determinant to write the quadratic, then the quadratic formula. tr(C) = 0.6166 + 0.7166 = 1.3331, det(C) = 0.6166·0.7166 − 0.6154² = 0.06302:

Characteristic polynomial: λ² − tr·λ + det = 0

Why: For a 2×2, det(C − λI) = λ² − tr(C)λ + det(C). We derived this exact shape in Part 1.

\[ \lambda^2 - 1.3331\,\lambda + 0.06302 = 0 \]

Quadratic formula, discriminant = 1.3331² − 4·0.06302 = 1.5251

Why: √1.5251 = 1.2349.

\[ \lambda = \frac{1.3331 \pm 1.2349}{2} = 1.2840 \;\text{or}\; 0.0491 \]

λ₁ = 1.2840 (PC1 variance), λ₂ = 0.0491 (PC2 variance)

Why: Matches np.linalg.eigh exactly. PC1 holds 1.2840/(1.2840+0.0491) = 96.3% of the total variance.

76. Decode the notation: Eigenvalues of C by the characteristic polynomial

Notation

Annotate

From Eigenvalues of C by the characteristic polynomial — read this one piece at a time. What is each part doing?

On: \( \lambda = \frac{1.3331 \pm 1.2349}{2} = 1.2840 \;\text{or}\; 0.0491 \)

  • For a 2×2, det(C − λI) = λ² − tr(C)λ + det(C). We derived this exact shape in Part 1.
  • Matches np.linalg.eigh exactly. PC1 holds 1.2840/(1.2840+0.0491) = 96.3% of the total variance.

77. Predict the next row: PCA from scratch, top to bottom

Pattern

Predict first

The table runs: cov | [[0.6166, 0.6154], [0.6154, 0.7166]] · eigenvalues (desc) | [1.2840, 0.0491] · PC1 direction | [0.6779, 0.7352]

In PCA from scratch, top to bottom, given the rows so far: what is the next one — the row where quantity is PC1 share of variance?

Correct: PC1 share of variance | 1.2840 / 1.3331 = 96.3%

quantityvalue (verified)
cov[[0.6166, 0.6154], [0.6154, 0.7166]]
eigenvalues (desc)[1.2840, 0.0491]
PC1 direction[0.6779, 0.7352]
PC1 share of variance1.2840 / 1.3331 = 96.3%

Why: The relationship between the columns, not the individual numbers, is what generates the next row. eigh returns ascending, so we reverse the order to put the biggest-variance direction first.

78. PCA from scratch, top to bottom

Worked example

Now the whole pipeline in code: center, covariance, eigh, sort descending. X is the 10×2 array from before. Runnable:

import numpy as np
X = np.array([[2.5,2.4],[0.5,0.7],[2.2,2.9],[1.9,2.2],[3.1,3.0],
              [2.3,2.7],[2.0,1.6],[1.0,1.1],[1.5,1.6],[1.1,0.9]])
Xc = X - X.mean(axis=0)                 # 1. CENTER
cov = (Xc.T @ Xc) / (len(Xc) - 1)       # 2. covariance
evals, evecs = np.linalg.eigh(cov)      # 3. eigen-decompose (ascending)
order = np.argsort(evals)[::-1]         # 4. sort DESCENDING
evals, evecs = evals[order], evecs[:, order]
print(evals.round(4))
print(evecs[:, 0].round(4))             # PC1 direction

Sorted eigenvalues [1.2840, 0.0491]; PC1 = [0.6779, 0.7352]

Why: eigh returns ascending, so we reverse the order to put the biggest-variance direction first. PC1 points up-and-to-the-right — the cigar's long axis.

quantityvalue (verified)
cov[[0.6166, 0.6154], [0.6154, 0.7166]]
eigenvalues (desc)[1.2840, 0.0491]
PC1 direction[0.6779, 0.7352]
PC1 share of variance1.2840 / 1.3331 = 96.3%

79. What has to be given first: Match it against sklearn

Missing information

Discussion prompt

sklearn's PCA centers internally and reports explained_variance_ (the eigenvalues) and components_ (the eigenvectors as rows). Confirm they agree with our from-scratch numbers:

What do you need to know — or decide — before the first line can be written? List everything the problem has to hand you.

Hint: Anything you would have to invent to get started is a thing the problem must supply.

Answer:

Identical to our hand-built PCA. sklearn uses an SVD internally rather than eigh on the covariance, but the answer is the same — that's the eigen-decomposition of the covariance either way.

80. Match it against sklearn

Worked example

sklearn's PCA centers internally and reports explained_variance_ (the eigenvalues) and components_ (the eigenvectors as rows). Confirm they agree with our from-scratch numbers:

import numpy as np
from sklearn.decomposition import PCA
X = np.array([[2.5,2.4],[0.5,0.7],[2.2,2.9],[1.9,2.2],[3.1,3.0],
              [2.3,2.7],[2.0,1.6],[1.0,1.1],[1.5,1.6],[1.1,0.9]])
p = PCA(n_components=2).fit(X)
print(p.explained_variance_.round(4))   # eigenvalues
print(p.components_[0].round(4))        # PC1 direction

sklearn variances [1.2840, 0.0491]; PC1 [0.6779, 0.7352]

Why: Identical to our hand-built PCA. sklearn uses an SVD internally rather than eigh on the covariance, but the answer is the same — that's the eigen-decomposition of the covariance either way.

quantityfrom scratchsklearn PCA
explained variance[1.2840, 0.0491][1.2840, 0.0491]
PC1 direction[0.6779, 0.7352][0.6779, 0.7352]
PC1 signup-rightup-right (may flip)

81. Fill in: sklearn PCA for Match it against sklearn

Comparison

Comparison matrix

From Match it against sklearn: refill the sklearn PCA column from what you know. The rest of the table is as it appeared.

quantityfrom scratchsklearn PCA
explained variance[1.2840, 0.0491][1.2840, 0.0491]
PC1 direction[0.6779, 0.7352][0.6779, 0.7352]
PC1 signup-rightup-right (may flip)

82. Guess the shape of the answer: Projecting onto PC1 recovers the variance

Estimation

Predict first

The eigenvalue is a promise: project the centered data onto PC1 and the projected scores should have variance equal to λ₁ = 1.2840. Check it:

Commit before you compute: what does Projecting onto PC1 recovers the variance come out to? A rough magnitude and the right form is enough — the point is to have something concrete to be wrong about.

Correct: Variance of the PC1 scores = 1.2840 = λ₁

Why: A prediction you can defend turns the computation into a check rather than a leap of faith — and an answer that contradicts it is caught on the spot. The scores spread out with exactly the eigenvalue's worth of variance — the concrete meaning of 'eigenvalue = variance along that component.'

83. Projecting onto PC1 recovers the variance

Worked example

The eigenvalue is a promise: project the centered data onto PC1 and the projected scores should have variance equal to λ₁ = 1.2840. Check it:

import numpy as np
X = np.array([[2.5,2.4],[0.5,0.7],[2.2,2.9],[1.9,2.2],[3.1,3.0],
              [2.3,2.7],[2.0,1.6],[1.0,1.1],[1.5,1.6],[1.1,0.9]])
Xc = X - X.mean(axis=0)
cov = (Xc.T @ Xc) / (len(Xc) - 1)
evals, evecs = np.linalg.eigh(cov)
pc1 = evecs[:, np.argmax(evals)]        # dominant eigenvector
scores = Xc @ pc1                       # project each point onto PC1
print(scores.round(4))
print(round(scores.var(ddof=1), 4))     # variance of the scores

Variance of the PC1 scores = 1.2840 = λ₁

Why: The scores spread out with exactly the eigenvalue's worth of variance — the concrete meaning of 'eigenvalue = variance along that component.'

quantityvalue (verified)
first 3 PC1 scores[0.828, −1.7776, 0.9922]
var(scores, ddof=1)1.2840
λ₁ from eigh1.2840

84. Work backwards from the answer: Projecting onto PC1 recovers the variance

Reverse engineer

Discussion prompt

Work backwards. The example finished here:

Variance of the PC1 scores = 1.2840 = λ₁

What was it asked to do, and what must it have been given? Reconstruct the problem from its answer.

Hint: Every quantity in the result had to enter somewhere. Account for each one.

Answer:

The eigenvalue is a promise: project the centered data onto PC1 and the projected scores should have variance equal to λ₁ = 1.2840. Check it:

85. Something is wrong here: PCA without centering

Anomaly

Predict first

A student writes this, and it looks reasonable:

Just eigen-decompose XᵀX/(n−1) on the raw data — skip the mean subtraction, it's an extra step.

It is wrong. Say what breaks — and say it before you turn the page.

Correct: That top eigenvector comes out [0.686, 0.727] — which is essentially the data's MEAN direction [0.688, 0.726], not its direction of spread.

Variance is defined around the mean, so center first — always.

Why: That top eigenvector comes out [0.686, 0.727] — which is essentially the data's MEAN direction [0.688, 0.726], not its direction of spread. The 'variance' 8.977 is inflated garbage; the real PC1 variance is 1.284.

86. Trap: PCA without centering

Trap

The trap

Just eigen-decompose XᵀX/(n−1) on the raw data — skip the mean subtraction, it's an extra step.

cov = XᵀX / (n−1) on un-centered data → top eigenvalue 8.977

Why: That top eigenvector comes out [0.686, 0.727] — which is essentially the data's MEAN direction [0.688, 0.726], not its direction of spread. The 'variance' 8.977 is inflated garbage; the real PC1 variance is 1.284.

The fix

Variance is defined around the mean, so center first — always.

Xc = X − X.mean(0), then cov = XcᵀXc/(n−1) → eigenvalue 1.284

Why: Only the centered covariance has eigenvectors that capture spread. sklearn centers internally, so your from-scratch version must do it explicitly or you'll silently measure the offset from the origin instead of the shape of the cloud.

87. Which of these survive contact with Lesson 10: Eigenvalues & Eigenvectors?

Two truths and a lie

Sort into buckets

Some of these hold up and some are the exact mistakes this lesson is built to prevent. Sort them.

Holds up
One 2×2 matrix carries the first half of this lesson. It is symmetric (A = Aᵀ), which will matter enormously.; An eigenvector v of A is a nonzero vector that A only scales — it keeps its direction. The scale factor λ is the eigenvalue for that vector.; λ > 1 stretches, 0 < λ < 1 compresses, λ < 0 flips the arrow around, and λ = 0 collapses that direction to a point — the mark of a singular matrix.
Breaks
The eigenvalues of [[3,1],[0,2]] turn out to be 3 and 2 — its diagonal. So just read eigenvalues off the diagonal of any matrix.; Eigenvectors form the natural axes of a transform, so they must be perpendicular — orthogonalize or dot them freely.
sound
These are stated as this lesson states them — each one survives the edge cases Lesson 10: Eigenvalues & Eigenvectors puts it through.
flawed
Each of these is lifted from a trap in this deck: reasonable-sounding, and wrong in a way that only shows up once you rely on it.

88. The eigen-toolkit

Section

Part 5 of 6 — pattern & checks

89. Without one step: The eigen-toolkit

Constraint

Discussion prompt

Run The eigen-toolkit with this step confiscated:

Symmetric A: use np.linalg.eigh → real eigenvalues, orthonormal vectors, A = VΛVᵀ (verify by reconstruction)

Is it still possible? If it is, say what takes its place and what it costs you. If it is not, say exactly what that step was providing that nothing else does.

Hint: A step you can drop for free was never load-bearing. If you cannot drop it, name the thing that goes wrong the moment it is gone.

Answer:

  1. Eigenvalues: roots of det(A − λI) = 0 — sanity-check with sum = trace, product = det
  2. Eigenvectors: for each λ, solve (A − λI)v = 0; normalize to unit length (sign is arbitrary)
  3. Symmetric A: use np.linalg.eigh → real eigenvalues, orthonormal vectors, A = VΛVᵀ (verify by reconstruction)
  4. Dominant only: power-iterate b ← Ab/‖Ab‖; eigenvalue from the Rayleigh quotient bᵀAb; deflate A − λ₁v₁v₁ᵀ for the next one
  5. PCA: center → covariance XᶜᵀXᶜ/(n−1) → eigh → sort by eigenvalue (= variance) → match sklearn

90. The eigen-toolkit

Pattern

  1. Eigenvalues: roots of det(A − λI) = 0 — sanity-check with sum = trace, product = det
  2. Eigenvectors: for each λ, solve (A − λI)v = 0; normalize to unit length (sign is arbitrary)
  3. Symmetric A: use np.linalg.eigh → real eigenvalues, orthonormal vectors, A = VΛVᵀ (verify by reconstruction)
  4. Dominant only: power-iterate b ← Ab/‖Ab‖; eigenvalue from the Rayleigh quotient bᵀAb; deflate A − λ₁v₁v₁ᵀ for the next one
  5. PCA: center → covariance XᶜᵀXᶜ/(n−1) → eigh → sort by eigenvalue (= variance) → match sklearn

91. Where does it stop working: The eigen-toolkit

Edge cases

Discussion prompt

The eigen-toolkit works on the cases you have just seen. Push it to the edge: what is the most degenerate input it still handles — empty, zero, one item, everything equal — and what is the first case where it stops being true? Name the case, not just "it breaks".

Hint: Try the smallest legal input, then the largest, then the one where two things collide. Methods are specified at their edges; the middle takes care of itself.

Answer:

  1. Eigenvalues: roots of det(A − λI) = 0 — sanity-check with sum = trace, product = det
  2. Eigenvectors: for each λ, solve (A − λI)v = 0; normalize to unit length (sign is arbitrary)
  3. Symmetric A: use np.linalg.eigh → real eigenvalues, orthonormal vectors, A = VΛVᵀ (verify by reconstruction)
  4. Dominant only: power-iterate b ← Ab/‖Ab‖; eigenvalue from the Rayleigh quotient bᵀAb; deflate A − λ₁v₁v₁ᵀ for the next one
  5. PCA: center → covariance XᶜᵀXᶜ/(n−1) → eigh → sort by eigenvalue (= variance) → match sklearn

92. Rule out three: Check yourself — finding eigenvalues

Elimination

Eliminate the wrong options

The eigenvalues of A = [[4,2],[1,3]] are the roots of which equation?

3 of these 4 are wrong. Strike them one at a time, and say what rules each one out before you strike the next. The survivor is the answer.

  • A. (4−λ)(3−λ) − 2·1 = 0
  • B. (4−λ)(3−λ) = 0
  • C. (4−λ) + (3−λ) = 0
  • D. 4·3 − 2·1 − λ = 0

Survives elimination: A

Why: det(A − λI) = (4−λ)(3−λ) − (2)(1) = λ² − 7λ + 10 = 0, giving λ = 2 and 5. The off-diagonal product 2·1 must be subtracted, and the trace 7 / det 10 checks confirm it.

93. Check yourself — finding eigenvalues

Check

Set up the characteristic equation before you answer.

Check your understanding

The eigenvalues of A = [[4,2],[1,3]] are the roots of which equation?

  • A. (4−λ)(3−λ) − 2·1 = 0 (correct)
  • B. (4−λ)(3−λ) = 0
  • C. (4−λ) + (3−λ) = 0
  • D. 4·3 − 2·1 − λ = 0

Answer: A

Why: det(A − λI) = (4−λ)(3−λ) − (2)(1) = λ² − 7λ + 10 = 0, giving λ = 2 and 5. The off-diagonal product 2·1 must be subtracted, and the trace 7 / det 10 checks confirm it.

Why B tempts people
Forgets the off-diagonal term. (4−λ)(3−λ) = 0 would be correct only if the off-diagonal entries were zero — i.e. a triangular matrix. Here they aren't.
Why C tempts people
That's the trace condition (λ₁ + λ₂ = 7), a single check on the eigenvalues, not the equation that produces them. It gives one linear equation, not the required quadratic.
Why D tempts people
Confuses determinant with the characteristic polynomial. det(A) = 10 is the PRODUCT of the eigenvalues, a check — not an equation you solve for λ this way.

94. Answer it before you see the options: Check yourself — the spectral theorem

Prediction

Predict first

Which property is guaranteed for a real SYMMETRIC matrix but NOT for a general square matrix?

Answer it in your own words, now, with nothing to choose from. The options are on the next slide — and picking the right one off a list is an easier skill than producing it.

Correct: Real eigenvalues and orthonormal eigenvectors

Why: The spectral theorem guarantees real eigenvalues and a full orthonormal eigenbasis for symmetric matrices. A general matrix can have complex eigenvalues and non-orthogonal (or too few) eigenvectors.

95. Check yourself — the spectral theorem

Check

Which guarantee actually needs symmetry?

Check your understanding

Which property is guaranteed for a real SYMMETRIC matrix but NOT for a general square matrix?

  • A. Real eigenvalues and orthonormal eigenvectors (correct)
  • B. All eigenvalues are strictly positive
  • C. The eigenvalues equal the diagonal entries
  • D. It has exactly one eigenvector

Answer: A

Why: The spectral theorem guarantees real eigenvalues and a full orthonormal eigenbasis for symmetric matrices. A general matrix can have complex eigenvalues and non-orthogonal (or too few) eigenvectors.

Why B tempts people
Positive eigenvalues is positive-DEFINITENESS, a strictly stronger condition. Symmetric matrices can have negative eigenvalues — e.g. [[0,1],[1,0]] is symmetric with eigenvalues −1 and 1.
Why C tempts people
Diagonal = eigenvalues holds for TRIANGULAR matrices, not symmetric ones. Our symmetric [[2,1],[1,2]] has eigenvalues 1 and 3, not 2 and 2.
Why D tempts people
The opposite is true: a symmetric n×n matrix has a FULL set of n orthonormal eigenvectors, not just one.

96. Answer it before you see the options: Check yourself — power iteration

Prediction

Predict first

Power iteration bₖ₊₁ = Abₖ/‖Abₖ‖ converges to the eigenvector with…

Answer it in your own words, now, with nothing to choose from. The options are on the next slide — and picking the right one off a list is an easier skill than producing it.

Correct: the largest eigenvalue in absolute value (the dominant one)

Why: Writing b₀ in the eigenbasis, each multiply by A scales the component along λᵢ by λᵢ. The largest-|λ| component grows fastest and dominates, so b converges to that dominant eigenvector; the eigenvalue follows from bᵀAb.

97. Check yourself — power iteration

Check

Think about which component grows fastest.

Check your understanding

Power iteration bₖ₊₁ = Abₖ/‖Abₖ‖ converges to the eigenvector with…

  • A. the largest eigenvalue in absolute value (the dominant one) (correct)
  • B. the smallest eigenvalue
  • C. the eigenvalue closest to zero
  • D. whichever eigenvector you started nearest to

Answer: A

Why: Writing b₀ in the eigenbasis, each multiply by A scales the component along λᵢ by λᵢ. The largest-|λ| component grows fastest and dominates, so b converges to that dominant eigenvector; the eigenvalue follows from bᵀAb.

Why B tempts people
The smallest eigenvalue's component shrinks relative to the others every step, so it's the first to vanish — not what power iteration lands on. (To target the smallest, you'd iterate with A⁻¹ — inverse iteration.)
Why C tempts people
Same misconception as B: the near-zero-eigenvalue direction decays fastest under repeated multiplication by A, so iteration moves away from it.
Why D tempts people
The start only affects the coefficients c_i (and how many steps you need). As long as the dominant component isn't exactly zero, iteration converges to the dominant eigenvector regardless of where you began.

98. Rule out three: Check yourself — PCA eigenvalues

Elimination

Eliminate the wrong options

In PCA, the eigenvalues of the (centered) covariance matrix represent…

3 of these 4 are wrong. Strike them one at a time, and say what rules each one out before you strike the next. The survivor is the answer.

  • A. The variance captured along each principal component
  • B. The mean of the data along each axis
  • C. The number of samples in each cluster
  • D. The reconstruction error of the model

Survives elimination: A

Why: Each eigenvalue is the variance of the data projected onto its eigenvector (principal component) — we verified it: projecting onto PC1 gave scores with variance 1.2840, exactly λ₁. The largest eigenvalue marks the direction of maximum spread.

99. Check yourself — PCA eigenvalues

Check

What does each eigenvalue of the covariance mean?

Check your understanding

In PCA, the eigenvalues of the (centered) covariance matrix represent…

  • A. The variance captured along each principal component (correct)
  • B. The mean of the data along each axis
  • C. The number of samples in each cluster
  • D. The reconstruction error of the model

Answer: A

Why: Each eigenvalue is the variance of the data projected onto its eigenvector (principal component) — we verified it: projecting onto PC1 gave scores with variance 1.2840, exactly λ₁. The largest eigenvalue marks the direction of maximum spread.

Why B tempts people
The mean is removed by centering BEFORE the covariance is formed, so it can't be an eigenvalue. Eigenvalues describe spread, not location. (Skipping centering is the exact trap that made the top 'eigenvalue' point at the mean.)
Why C tempts people
PCA is not clustering and knows nothing about cluster membership; eigenvalues are variances (real numbers), not integer counts.
Why D tempts people
Reconstruction error is the sum of the DISCARDED eigenvalues (variance you throw away), not the eigenvalues you keep.

100. Your turn: build it

Section

Part 6 of 6 — the project

101. Project: power iteration & PCA

Concept

Build the dominant-eigenvector finder, then PCA from scratch, and prove both against NumPy/sklearn. You've derived every piece — now assemble them yourself.

#requirementtool
1Confirm eigen-pairs of the 2×2 by hand + NumPynp.linalg.eigh
2Power iteration → dominant eigenvector + eigenvalueloop: b ← Ab/‖Ab‖
3PCA: center → covariance → eigh → sort, vs sklearnPCA(n_components=2)

Build rules: type every line yourself, run after each, renormalize inside the loop (or values explode), and compare eigenvector directions, not raw components — the sign is arbitrary.

102. Break it if you can: Project: power iteration & PCA

Counterexample

Discussion prompt

Build the dominant-eigenvector finder, then PCA from scratch, and prove both against NumPy/sklearn. You've derived every piece — now assemble them yourself.

That is stated as though it always holds. Do one of two things: produce a case where it fails, or say precisely what rules such a case out. "It just does" is not on the menu.

Hint: Hunt at the extremes first — zero, one, negative, empty, equal. If every extreme survives, the reason they survive is the proof.

Answer:

Build rules: type every line yourself, run after each, renormalize inside the loop (or values explode), and compare eigenvector directions, not raw components — the sign is arbitrary.

103. Milestone 1 — confirm the eigen-pairs

Worked example

Your turn: get the eigenvalues of [[2,1],[1,2]]. Predict them from det(A − λI) = 0 first, then run eigh to confirm.

Hint: use np.linalg.eigh because the matrix is symmetric; it returns eigenvalues in ascending order, so the dominant one is last.

import numpy as np
A = np.array([[2., 1.], [1., 2.]])
vals, vecs = np.linalg.eigh(A)
print(vals)
print(vecs)
outputvalue
eigenvalues (ascending)[1.0, 3.0]
dominant eigenvector (λ=3)[0.707, 0.707]
other eigenvector (λ=1)[−0.707, 0.707]

104. Milestone 2 — power iteration

Worked example

Your turn: loop b ← Ab, renormalize, repeat ~6 times from b = [1, 0]. Predict which eigenvector it converges to before you print.

Hint: inside the loop do b = A @ b then b = b/np.linalg.norm(b); read the eigenvalue from b @ A @ b.

import numpy as np
A = np.array([[2., 1.], [1., 2.]])
b = np.array([1., 0.])
for i in range(6):
    b = A @ b
    b = b / np.linalg.norm(b)
print(b.round(4), round(b @ A @ b, 4))
resultvalue
converged b[0.7081, 0.7061]
Rayleigh bᵀAb3.0
true dominant eigvec[0.7071, 0.7071]

105. Milestone 3 — PCA, verified

Worked example

Your turn: center the 10×2 X, build the covariance, eigen-decompose, sort descending, and compare the variances to sklearn. Will the PC1 sign match?

Hint: Xc = X - X.mean(0); cov = Xc.T @ Xc / (len(X)-1); eigh; reverse with [::-1]. Compare evals to PCA().fit(X).explained_variance_.

import numpy as np
from sklearn.decomposition import PCA
X = np.array([[2.5,2.4],[0.5,0.7],[2.2,2.9],[1.9,2.2],[3.1,3.0],
              [2.3,2.7],[2.0,1.6],[1.0,1.1],[1.5,1.6],[1.1,0.9]])
Xc = X - X.mean(0)
cov = Xc.T @ Xc / (len(X) - 1)
evals, evecs = np.linalg.eigh(cov)
evals = evals[::-1]                     # descending
print(evals.round(4))
print(PCA(n_components=2).fit(X).explained_variance_.round(4))
sourceexplained variance
from scratch[1.2840, 0.0491]
sklearn[1.2840, 0.0491]

106. Milestone 4 — deflate for PC2

Worked example

Your turn: peel off the dominant direction of the covariance and power-iterate the remainder to recover the second principal component. Predict which eigenvalue you'll land on.

Hint: Cdef = cov - λ₁ · outer(pc1, pc1), then power-iterate Cdef. The Rayleigh quotient should converge to λ₂ = 0.0491.

import numpy as np
X = np.array([[2.5,2.4],[0.5,0.7],[2.2,2.9],[1.9,2.2],[3.1,3.0],
              [2.3,2.7],[2.0,1.6],[1.0,1.1],[1.5,1.6],[1.1,0.9]])
Xc = X - X.mean(0)
cov = Xc.T @ Xc / (len(X) - 1)
evals2, evecs2 = np.linalg.eigh(cov)
lam1 = evals2[-1]; pc1 = evecs2[:, -1]      # dominant pair
Cdef = cov - lam1 * np.outer(pc1, pc1)      # deflate it away
b = np.array([1., 0.])
for _ in range(50):
    b = Cdef @ b
    b = b / np.linalg.norm(b)
print(b.round(4), round(b @ cov @ b, 4))
resultvalue
PC2 direction[−0.7352, 0.6779] (⟂ to PC1)
variance along PC20.0491 (= λ₂)
PC1 · PC2≈ 0 (orthogonal)

107. What each one costs: Milestone 4 — deflate for PC2

Trade off

Comparison matrix

From Milestone 4 — deflate for PC2: every row here is a choice with a cost. Fill the value column, then say which row you would actually pick and what you give up for it.

resultvalue
PC2 direction[−0.7352, 0.6779] (⟂ to PC1)
variance along PC20.0491 (= λ₂)
PC1 · PC2≈ 0 (orthogonal)

108. The full program

Concept

import numpy as np
from sklearn.decomposition import PCA

def power_iteration(M, iters=50):
    b = np.ones(M.shape[0])
    for _ in range(iters):
        b = M @ b
        b = b / np.linalg.norm(b)   # renormalize EVERY step
    return b, b @ M @ b             # eigenvector, eigenvalue

def pca(X, k):
    Xc = X - X.mean(0)              # center first, always
    cov = Xc.T @ Xc / (len(X) - 1)
    vals, vecs = np.linalg.eigh(cov)
    idx = np.argsort(vals)[::-1][:k]
    return vals[idx], vecs[:, idx]

A = np.array([[2., 1.], [1., 2.]])
v, lam = power_iteration(A)
print('power iter:', np.abs(v).round(3), round(lam, 3))
outputvalue (verified)
power_iteration(A) vector[0.707, 0.707]
power_iteration(A) eigenvalue3.0
pca(X, 2) variances[1.2840, 0.0491]

If power_iteration returns [0.707, 0.707] with eigenvalue 3.0, and your pca matches sklearn's variances [1.2840, 0.0491] — you built the eigen-toolkit from the math up.

109. Fill in: value (verified) for The full program

Comparison

Comparison matrix

From The full program: refill the value (verified) column from what you know. The rest of the table is as it appeared.

outputvalue (verified)
power_iteration(A) vector[0.707, 0.707]
power_iteration(A) eigenvalue3.0
pca(X, 2) variances[1.2840, 0.0491]

110. Show it off

Concept

Slides closed, out loud: explain (1) why det(A − λI) = 0 finds eigenvalues, (2) why power iteration converges to the dominant one and what sets its speed, and (3) why PCA needs centering and uses eigh not eig.

Stretch (homework): prove that eigenvectors for distinct eigenvalues of a symmetric matrix are orthogonal. This eigen-thread runs straight into SVD (Lessons 16–18), kernels (Week 10), and the VAE covariance (Week 44).

111. Connect it up: Lesson 10: Eigenvalues & Eigenvectors

Connect it up

Draw it

One page, no notation unless you need it: draw how these connect — The eigen-equation · The spectral theorem · Power iteration · Eigenvectors are PCA · The eigen-toolkit · Your turn: build it. Put an arrow wherever one of them is what makes another possible, and label the arrow with why.

112. What you can do now

Recap

ideathe one thing to remember
eigenvaluesroots of det(A − λI) = 0; sum = trace, product = det
diagonal = eigenvaluesonly for triangular matrices
orthonormal eigenvectorsonly guaranteed if A is symmetric
power iterationrenormalize every step; converges to largest |λ|
PCAcenter first; eigenvalue = variance; use eigh

Sources

  1. USAAIO Year-Long Master Lesson Plan, Lesson 10 (Week 4 — Eigenvalues) — Barron · USAAIO Round 2 Preparation, 2026
  2. Gilbert Strang, Introduction to Linear Algebra, Ch. 6 (Eigenvalues & Eigenvectors) — Wellesley-Cambridge Press, 5th ed.
  3. NumPy linalg.eig / eigh
  4. scikit-learn PCA
  5. Every eigenvalue, power-iteration row, and PCA number produced by real execution — numpy 2.2.6 + scikit-learn 1.9, verification run July 2026

Want this taught 1-on-1? Alexander tutors Machine Learning — $55/session, free consultation.

Book on Wyzant · Text (657) 465-8108