USAAIO Lesson 25, from Week 9, fully worked. It derives orthogonal projection matrices from P²=P and Pᵀ=P, then builds the hat matrix H=X(XᵀX)⁻¹Xᵀ from the normal equations one step at a time and proves that ŷ=Hy equals the OLS fit. It checks idempotence and symmetry algebraically, covers the eigenvalues of 0 and 1 and the fact that tr(H)=p, and introduces the residual projector I−H. It then derives leverage hᵢᵢ both from diag(H) and from the closed form 1/n+(xᵢ−x̄)²/Sxx, builds Cook's distance entry by entry, and runs a leave-one-out demo proving that influence is leverage times residual. Every snippet runs standalone, and every number came from real numpy execution. The lesson runs to 62 slides.
Subject: Machine Learning · 118 slides · code lesson
Open the interactive version of this deck · Homework for this lesson
Title
USAAIO · Lesson 25 · Week 9 (Linear Algebra)
Least squares was a projection. Today we make the projection into a single matrix H — build it step by step, prove it puts the hat on ŷ, and read leverage and influence straight off its diagonal.
Objectives
P² = P and Pᵀ = P, and show its eigenvalues are only 0 and 1H = X(XᵀX)⁻¹Xᵀ from the normal equations and prove ŷ = Hy equals the OLS fitH² = H, Hᵀ = H, and rank(H) = tr(H) = p — the model's degrees of freedomI − H, and prove residuals are perpendicular to fitted valueshᵢᵢ two ways (from diag(H) and the closed form) and flag influence with Cook's distanceWarm-up
Discussion prompt
Before we open Lesson 25: Projections & the Hat Matrix: without looking back, what was the main idea of Constrained Optimization & KKT, 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:
constrained optimization with Lagrange multipliers, the KKT conditions and complementary slackness, the SVM dual via Lagrangian duality, and strong duality / Slater's condition. Solve equality- and inequality-constrained problems by hand and with scipy.
Section
Part 1 of 7
Concept
Least squares found the weights w★ that make Xw★ the closest point in the column space of X to the target y. The residual came out perpendicular to that space.
\[ X^\top X\, w^\star = X^\top y \quad\Longrightarrow\quad w^\star = (X^\top X)^{-1} X^\top y \]
That was a picture about w. Today we ask a sharper question: what single matrix turns y directly into the fitted ŷ? That matrix is the whole lesson.
Counterexample
Discussion prompt
Least squares found the weights w★ that make Xw★ the closest point in the column space of X to the target y. The residual came out perpendicular to that space.
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.
Concept
We reuse Lesson 7's data so every number connects: five students, hours x and score y, fit by ŷ = w₀ + w₁·x.
| student | hours x | score y |
|---|---|---|
| 1 | 1 | 2 |
| 2 | 2 | 4 |
| 3 | 3 | 5 |
| 4 | 4 | 4 |
| 5 | 5 | 5 |
From Lesson 7 we already know the answer: w★ = [2.2, 0.6], so ŷ = 2.2 + 0.6x, total squared error 2.4. Today we recover the same ŷ without ever solving for w — straight from a matrix.
Comparison
Comparison matrix
From The 5-student running example: refill the hours x column from what you know. The rest of the table is as it appeared.
| student | hours x | score y |
|---|---|---|
| 1 | 1 | 2 |
| 2 | 2 | 4 |
| 3 | 3 | 5 |
| 4 | 4 | 4 |
| 5 | 5 | 5 |
Concept
The hat matrix is built from X alone — the feature positions. It does not depend on the targets y at all.
That's powerful: with the same X, you can predict how the fit will respond to any y (leverage, degrees of freedom, influence) before collecting a single outcome. H is a property of the experimental design, not the data you measure.
Analogy
Discussion prompt
Explain H is fixed before you ever see y 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 hat matrix is built from X alone — the feature positions. It does not depend on the targets y at all.
Intuition
Hold a pencil above a table under a light straight overhead. Its shadow on the table is a projection: a 3-D point flattened onto a 2-D surface.
Do it twice — project the shadow again — and nothing moves. The shadow is already on the floor. That 'projecting twice does nothing' is the defining property we formalize next.
In least squares, y is the pencil floating above, the column space of X is the floor, and ŷ is the shadow. The leftover height is the residual.
Explain it
Discussion prompt
Explain A shadow on the floor 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:
Do it twice — project the shadow again — and nothing moves. The shadow is already on the floor. That 'projecting twice does nothing' is the defining property we formalize next.
Section
Part 2 of 7 — the defining laws
Concept
A matrix P is a projector if applying it twice is the same as applying it once. Formally:
\[ P^2 = P \qquad (\text{idempotent}) \]
Once Pv lands in the target subspace, it is already there, so P leaves it alone: P(Pv) = Pv. This one equation is what 'the shadow of a shadow is the shadow' means in algebra.
Concept
A projector can be slanted. An orthogonal projector — the shadow drops straight down, perpendicular to the subspace — additionally satisfies:
\[ P^\top = P \qquad (\text{symmetric}) \]
orthogonal projection matrix — A matrix P with BOTH P² = P and Pᵀ = P. Idempotence makes it a projection; symmetry makes the leftover (v − Pv) perpendicular to the target subspace. Least squares uses exactly this kind.
Ranking
Put in order
Put the moves of Eigenvalues of a projector are only 0 and 1 into the order they have to happen.
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. P(Pv) = P(λv) = λ(Pv) = λ·λv = λ²v.
Worked example
This single fact explains rank, trace, and non-invertibility all at once. Let Pv = λv for an eigenvector v ≠ 0. Apply P again:
Apply P to both sides of Pv = λv
Why: P(Pv) = P(λv) = λ(Pv) = λ·λv = λ²v. The left side is P²v.
\[ P^2 v = \lambda^2 v \]
But P² = P, so P²v = Pv = λv
Why: Idempotence lets us replace P²v with λv on the left.
\[ \lambda v = \lambda^2 v \;\Longrightarrow\; (\lambda^2 - \lambda)\,v = 0 \]
Since v ≠ 0, λ² − λ = 0, so λ ∈ {0, 1}
Why: λ(λ − 1) = 0. A projector's eigenvalues can ONLY be 0 (directions it kills) or 1 (directions it keeps). Nothing in between.
\[ \lambda \in \{0, 1\} \]
Notation
Annotate
From Eigenvalues of a projector are only 0 and 1 — read this one piece at a time. What is each part doing?
On: \( P^2 v = \lambda^2 v \)
Estimation
Predict first
Before the hat matrix, meet a projector you can see. P = [[1,0],[0,0]] flattens any 2-D point onto the x-axis: it keeps the first coordinate, zeroes the second.
Commit before you compute: what does The simplest projector: drop onto the x-axis come out to? A rough magnitude and the right form is enough — the point is to have something concrete to be wrong about.
Correct: P²=P, Pᵀ=P, eig = [0, 1], trace = 1 = rank
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. Every projector law shows up in this 2×2 toy: idempotent, symmetric, eigenvalues 0/1, and trace 1 counting the one kept dimension (the x-axis).
Worked example
Before the hat matrix, meet a projector you can see. P = [[1,0],[0,0]] flattens any 2-D point onto the x-axis: it keeps the first coordinate, zeroes the second.
P·[3, 7] = [3, 0]
Why: First row [1,0] picks out the 3; second row [0,0] kills the 7. The point's shadow on the x-axis.
\[ \begin{bmatrix} 1 & 0 \\ 0 & 0 \end{bmatrix}\begin{bmatrix} 3 \\ 7 \end{bmatrix} = \begin{bmatrix} 3 \\ 0 \end{bmatrix} \]
import numpy as np
P = np.array([[1., 0.], [0., 0.]]) # project onto the x-axis
print("P@[3,7] =", P @ np.array([3., 7.]))
print("P^2==P:", np.allclose(P @ P, P), " P.T==P:", np.allclose(P, P.T))
print("eig:", np.linalg.eigvalsh(P), " trace:", np.trace(P))P²=P, Pᵀ=P, eig = [0, 1], trace = 1 = rank
Why: Every projector law shows up in this 2×2 toy: idempotent, symmetric, eigenvalues 0/1, and trace 1 counting the one kept dimension (the x-axis). The hat matrix is the same idea in n dimensions.
| property | value (verified) |
|---|---|
| P·[3,7] | [3, 0] |
| P²=P, Pᵀ=P | True, True |
| eigenvalues | [0, 1] |
| trace = rank | 1 |
Trade off
Comparison matrix
From The simplest projector: drop onto the x-axis: every row here is a choice with a cost. Fill the value (verified) column, then say which row you would actually pick and what you give up for it.
| property | value (verified) |
|---|---|
| P·[3,7] | [3, 0] |
| P²=P, Pᵀ=P | True, True |
| eigenvalues | [0, 1] |
| trace = rank | 1 |
Concept
A symmetric matrix's trace is the sum of its eigenvalues, and for a projector those are just a pile of 1s and 0s. So the trace literally counts the 1s:
\[ \operatorname{tr}(P) = \#\{\text{eigenvalues equal to }1\} = \operatorname{rank}(P) \]
Any direction with eigenvalue 0 is sent to the zero vector, so unless P = I the matrix has a nontrivial null space — it is not invertible. Remember that; it trips people up.
Intuition
Split any vector v into two parts: the piece inside the target subspace and the piece sticking out of it. A projector keeps the inside piece and deletes the outside piece.
So if v is already inside the subspace, Pv = v (eigenvalue 1). If v sticks straight out, Pv = 0 (eigenvalue 0). Every other vector is a blend of the two — which is why 0 and 1 are the only eigenvalues.
For least squares, the 'inside' subspace is the column space of X, the kept piece is ŷ, and the deleted piece is the residual r.
Anomaly
Predict first
A student writes this, and it looks reasonable:
A projector 'undoes' cleanly, so surely P² = I — apply it twice and you're back where you started.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: P² = I describes an INVOLUTION — a reflection (eigenvalues ±1), which is invertible (it's its own inverse).
A projector flattens — the second application has nothing left to do, so P² = P, not I.
Why: P² = I describes an INVOLUTION — a reflection (eigenvalues ±1), which is invertible (it's its own inverse). That is a totally different animal from a projection.
Trap
A projector 'undoes' cleanly, so surely P² = I — apply it twice and you're back where you started.
Assume P² = I
Why: P² = I describes an INVOLUTION — a reflection (eigenvalues ±1), which is invertible (it's its own inverse). That is a totally different animal from a projection.
A projector flattens — the second application has nothing left to do, so P² = P, not I.
P² = P, eigenvalues 0/1, singular
Why: Projecting a shadow onto the floor again leaves it put: P(Pv) = Pv. Its eigenvalues are 0 and 1 (not ±1), and it is singular. Reflection ≠ projection.
Section
Part 3 of 7 — step by step
Concept
We want the matrix that eats the raw target y and hands back the fitted values ŷ directly — the entire least-squares fit packaged as one linear operator.
\[ \hat y = H y \quad\text{for some fixed matrix } H \text{ built only from } X \]
Because H puts the little hat on y, it's called the hat matrix. Let's derive its formula from the pieces we already have.
Step zero
Discussion prompt
Derive H from the normal equations — before any calculation: what is the plan? Name the moves in order, in plain English, without doing the arithmetic.
Hint: It starts with: Start from the fitted values
Answer:
Worked example
Two facts from Lesson 7: the fit is ŷ = Xw★, and w★ = (XᵀX)⁻¹Xᵀy. Substitute the second into the first — no new ideas, just plug in.
Start from the fitted values
Why: The predictions are the design matrix times the optimal weights.
\[ \hat y = X w^\star \]
Substitute w★ = (XᵀX)⁻¹Xᵀy
Why: Replace w★ with the closed-form solution of the normal equations.
\[ \hat y = X\,(X^\top X)^{-1} X^\top\, y \]
Group everything that touches y
Why: Everything to the LEFT of y depends only on X. Name that block H — it is the hat matrix.
\[ \hat y = \underbrace{X (X^\top X)^{-1} X^\top}_{H}\, y \;\Longrightarrow\; \boxed{\,H = X (X^\top X)^{-1} X^\top\,} \]
Reverse engineer
Discussion prompt
Work backwards. The example finished here:
Group everything that touches y
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:
Two facts from Lesson 7: the fit is ŷ = Xw★, and w★ = (XᵀX)⁻¹Xᵀy. Substitute the second into the first — no new ideas, just plug in.
Concept
X is n×p (here 5×2). Track the dimensions through the product so you trust the result is n×n:
\[ \underset{n\times p}{X}\;\underset{p\times p}{(X^\top X)^{-1}}\;\underset{p\times n}{X^\top} \;=\; \underset{n\times n}{H} \]
So H is 5×5 — it acts on the 5-vector y and returns a 5-vector ŷ. It lives in data space, not weight space. That is the key mental shift from Lesson 7.
Sorting
Sort into buckets
These are the pieces of Lesson 25: Projections & the Hat Matrix, out of order. Put each one back under the part of the lesson it belongs to.
Intuition
y is what the students actually scored — noisy, off the line. ŷ = Hy is what the fitted line predicts at each x — the smoothed, on-the-line version.
H is the machine that does the smoothing: it takes the jagged observed vector and returns the closest vector that a straight line can produce. The difference between them is the residual, the part H throws away.
Ranking
Put in order
Put the moves of One entry of H, by hand into the order they have to happen.
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. From Lesson 7: det(XᵀX) = 50, and the 2×2 inverse is (1/50)[[55,−15],[−15,5]] = [[1.1,−0.3],[−0.3,0.1]].
Worked example
Entry Hᵢⱼ is rowᵢ(X)·(XᵀX)⁻¹·rowⱼ(X)ᵀ. We already know (XᵀX)⁻¹ from Lesson 7. Compute H₁₁ (the leverage of student 1) to see where 0.6 comes from.
Recall (XᵀX)⁻¹ = [[1.1, −0.3], [−0.3, 0.1]]
Why: From Lesson 7: det(XᵀX) = 50, and the 2×2 inverse is (1/50)[[55,−15],[−15,5]] = [[1.1,−0.3],[−0.3,0.1]].
\[ (X^\top X)^{-1} = \begin{bmatrix} 1.1 & -0.3 \\ -0.3 & 0.1 \end{bmatrix} \]
Row 1 of X is [1, 1]; multiply it by (XᵀX)⁻¹
Why: Student 1 has x=1, so its row is [1, 1]. [1,1]·[[1.1,−0.3],[−0.3,0.1]] = [1.1−0.3, −0.3+0.1] = [0.8, −0.2].
\[ \begin{bmatrix} 1 & 1 \end{bmatrix}\begin{bmatrix} 1.1 & -0.3 \\ -0.3 & 0.1 \end{bmatrix} = \begin{bmatrix} 0.8 & -0.2 \end{bmatrix} \]
Dot that with row 1 again → H₁₁ = 0.6
Why: [0.8, −0.2]·[1, 1]ᵀ = 0.8 − 0.2 = 0.6. That is exactly the top-left of H and the leverage of student 1.
\[ \begin{bmatrix} 0.8 & -0.2 \end{bmatrix}\begin{bmatrix} 1 \\ 1 \end{bmatrix} = 0.6 = H_{11} \]
import numpy as np
x = np.array([1., 2., 3., 4., 5.])
X = np.c_[np.ones(5), x]
XtXinv = np.linalg.inv(X.T @ X)
H11 = X[0] @ XtXinv @ X[0] # row1 . (XtX)^-1 . row1
print("(XtX)^-1 =\n", XtXinv)
print("H[1,1] =", round(H11, 4))| step | value (verified) |
|---|---|
| (XᵀX)⁻¹ | [[1.1, −0.3], [−0.3, 0.1]] |
| [1,1]·(XᵀX)⁻¹ | [0.8, −0.2] |
| ·[1,1]ᵀ = H₁₁ | 0.6 |
Error analysis
Annotate
Walk the callouts on One entry of H, by hand. Each one is a place this is easy to get subtly wrong.
Missing information
Discussion prompt
Assemble H for our 5-student data and print it. Note the code uses inv only to expose the structure — in production you'd use solve; more on that in the trap.
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:
Read row 1 and column 1 — identical. The matrix is manifestly symmetric, our first sign it's an orthogonal projector. Verified by real execution.
Worked example
Assemble H for our 5-student data and print it. Note the code uses inv only to expose the structure — in production you'd use solve; more on that in the trap.
import numpy as np
x = np.array([1., 2., 3., 4., 5.])
y = np.array([2., 4., 5., 4., 5.])
X = np.c_[np.ones(5), x] # bias column + feature
H = X @ np.linalg.inv(X.T @ X) @ X.T
print(np.round(H, 2))
print("H@H==H:", np.allclose(H @ H, H), " H.T==H:", np.allclose(H, H.T))H is 5×5, symmetric across the diagonal
Why: Read row 1 and column 1 — identical. The matrix is manifestly symmetric, our first sign it's an orthogonal projector. Verified by real execution.
| col1 | col2 | col3 | col4 | col5 | |
|---|---|---|---|---|---|
| row1 | 0.6 | 0.4 | 0.2 | 0.0 | −0.2 |
| row2 | 0.4 | 0.3 | 0.2 | 0.1 | 0.0 |
| row3 | 0.2 | 0.2 | 0.2 | 0.2 | 0.2 |
| row4 | 0.0 | 0.1 | 0.2 | 0.3 | 0.4 |
| row5 | −0.2 | 0.0 | 0.2 | 0.4 | 0.6 |
Invariant
Step through it
Step through Build H in code — and see it one row at a time. One of these columns never changes — find it, and say why it cannot.
Pattern
Predict first
The table runs: 1 | 2 | 2.8 | 2.8 · 2 | 4 | 3.4 | 3.4 · 3 | 5 | 4.0 | 4.0 · 4 | 4 | 4.6 | 4.6
In H really produces the OLS fit, given the rows so far: what is the next one — the row where x is 5?
Correct: 5 | 5 | 5.2 | 5.2
| x | true y | ŷ = Hy | X@w |
|---|---|---|---|
| 1 | 2 | 2.8 | 2.8 |
| 2 | 4 | 3.4 | 3.4 |
| 3 | 5 | 4.0 | 4.0 |
| 4 | 4 | 4.6 | 4.6 |
| 5 | 5 | 5.2 | 5.2 |
Why: The relationship between the columns, not the individual numbers, is what generates the next row. The hat matrix reproduces the regression line's predictions to machine precision.
Worked example
The payoff: Hy should equal the Lesson-7 fit [2.8, 3.4, 4.0, 4.6, 5.2] — computed without ever solving for w. Then confirm it matches the long way X@w.
import numpy as np
x = np.array([1., 2., 3., 4., 5.])
y = np.array([2., 4., 5., 4., 5.])
X = np.c_[np.ones(5), x]
H = X @ np.linalg.inv(X.T @ X) @ X.T
yhat = H @ y # fitted values, no solve for w needed
print("yhat =", yhat.round(4))
w = np.linalg.solve(X.T @ X, X.T @ y)
print("X@w =", (X @ w).round(4)) # same thing the long way
print("match:", np.allclose(H @ y, X @ w))Hy = [2.8, 3.4, 4.0, 4.6, 5.2] = X@w exactly
Why: The hat matrix reproduces the regression line's predictions to machine precision. The whole OLS fit is now one matrix-vector multiply.
| x | true y | ŷ = Hy | X@w |
|---|---|---|---|
| 1 | 2 | 2.8 | 2.8 |
| 2 | 4 | 3.4 | 3.4 |
| 3 | 5 | 4.0 | 4.0 |
| 4 | 4 | 4.6 | 4.6 |
| 5 | 5 | 5.2 | 5.2 |
Pattern
Step through it
Step through H really produces the OLS fit one row at a time. What is driving the change, and what would the row after the last one be?
Ranking
Put in order
Put the moves of Prove H² = H algebraically into the order they have to happen.
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. Substitute H = X(XᵀX)⁻¹Xᵀ into both factors.
Worked example
Numbers agreed; now the proof. Multiply H by itself and watch a matched (XᵀX)⁻¹(XᵀX) collapse to the identity.
Write H·H with the full formula
Why: Substitute H = X(XᵀX)⁻¹Xᵀ into both factors.
\[ H^2 = \big[X(X^\top X)^{-1}X^\top\big]\big[X(X^\top X)^{-1}X^\top\big] \]
The inner XᵀX meets its own inverse
Why: The middle Xᵀ·X = (XᵀX), sitting next to (XᵀX)⁻¹, cancels to the identity I.
\[ H^2 = X(X^\top X)^{-1}\,\underbrace{(X^\top X)(X^\top X)^{-1}}_{I}\,X^\top \]
What's left is H again
Why: Dropping the identity leaves exactly X(XᵀX)⁻¹Xᵀ = H. Idempotence proven — H is a projection matrix.
\[ H^2 = X(X^\top X)^{-1}X^\top = H \]
import numpy as np
x = np.array([1., 2., 3., 4., 5.])
X = np.c_[np.ones(5), x]
H = X @ np.linalg.inv(X.T @ X) @ X.T
print("H@H == H:", np.allclose(H @ H, H))| check | value (verified) |
|---|---|
| H @ H == H | True |
| reason | (XᵀX)⁻¹(XᵀX) = I cancels |
Blank canvas
Draw it
Draw what Prove H² = H algebraically 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.
Fill the middle
Fill in the blanks
From Prove Hᵀ = H algebraically — one line has had its right-hand side removed. Put it back.
import numpy as np
x = np.array([1., 2., 3., 4., 5.])
X = np.c_[np.ones(5), x]
H = X @ np.linalg.inv(X.T @ X) @ X.T
print("H.T == H:", np.allclose(H, H.T))
Why: X is what everything below it consumes, so the wrong expression here fails later and somewhere else. (ABC)ᵀ = CᵀBᵀAᵀ. Here A = X, B = (XᵀX)⁻¹, C = Xᵀ.
Worked example
Symmetry needs two rules: (ABC)ᵀ = CᵀBᵀAᵀ, and XᵀX is symmetric so its inverse is too. Transpose H piece by piece.
Transpose the product, reversing order
Why: (ABC)ᵀ = CᵀBᵀAᵀ. Here A = X, B = (XᵀX)⁻¹, C = Xᵀ.
\[ H^\top = \big(X^\top\big)^\top\,\big[(X^\top X)^{-1}\big]^\top\,X^\top = X\,\big[(X^\top X)^{-1}\big]^\top X^\top \]
The inverse of a symmetric matrix is symmetric
Why: XᵀX is symmetric, so [(XᵀX)⁻¹]ᵀ = (XᵀX)⁻¹ — the transpose does nothing to it.
\[ H^\top = X\,(X^\top X)^{-1} X^\top = H \]
import numpy as np
x = np.array([1., 2., 3., 4., 5.])
X = np.c_[np.ones(5), x]
H = X @ np.linalg.inv(X.T @ X) @ X.T
print("H.T == H:", np.allclose(H, H.T))| check | value (verified) |
|---|---|
| H.T == H | True |
| key fact | (XᵀX) symmetric ⇒ inverse symmetric |
Translation
\( H^\top = \big(X^\top\big)^\top\,\big[(X^\top X)^{-1}\big]^\top\,X^\top = X\,\big[(X^\top X)^{-1}\big]^\top X^\top \)
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.
Faded example
Fill in the blanks
Eigenvalues and rank of H, numerically, with the scaffolding fading: two lines are gone now — fill both.
import numpy as np
x = np.array([1., 2., 3., 4., 5.])
X = np.c_[np.ones(5), x]
H = X @ np.linalg.inv(X.T @ X) @ X.T
print("eigenvalues:", np.linalg.eigvalsh(H).round(6))
print("rank(H) =", np.linalg.matrix_rank(H))
print("trace(H) =", round(np.trace(H), 4))
Why: Reproducing these unaided, rather than reading them, is what tells you the method has transferred. Exactly two nonzero (unit) eigenvalues — one per parameter (intercept + slope).
Worked example
The general projector theory said eigenvalues are 0/1 and rank = tr. Confirm it on our H: two 1s (the two model parameters) and three 0s.
import numpy as np
x = np.array([1., 2., 3., 4., 5.])
X = np.c_[np.ones(5), x]
H = X @ np.linalg.inv(X.T @ X) @ X.T
print("eigenvalues:", np.linalg.eigvalsh(H).round(6))
print("rank(H) =", np.linalg.matrix_rank(H))
print("trace(H) =", round(np.trace(H), 4))eig(H) = [0, 0, 0, 1, 1] → rank 2 = trace 2 = p
Why: Exactly two nonzero (unit) eigenvalues — one per parameter (intercept + slope). The three zeros are the residual directions H annihilates. rank = trace = p, as the theory demanded.
| quantity | value (verified) |
|---|---|
| eigenvalues of H | [0, 0, 0, 1, 1] |
| rank(H) | 2 |
| trace(H) | 2 ( = p ) |
Anomaly
Predict first
A student writes this, and it looks reasonable:
H is 5×5 and packed with nonzero entries, so it's an invertible matrix like any other — just call inv(H).
It is wrong. Say what breaks — and say it before you turn the page.
Correct: H has eigenvalues 0 (three of them).
H is a projector, so it is singular by design — its rank is only p, not n.
Why: H has eigenvalues 0 (three of them). Any matrix with a zero eigenvalue has det = 0 and no inverse. inv(H) raises 'Singular matrix'.
Trap
H is 5×5 and packed with nonzero entries, so it's an invertible matrix like any other — just call inv(H).
np.linalg.inv(H) → LinAlgError (Singular)
Why: H has eigenvalues 0 (three of them). Any matrix with a zero eigenvalue has det = 0 and no inverse. inv(H) raises 'Singular matrix'.
H is a projector, so it is singular by design — its rank is only p, not n.
H is n×n but rank p; it collapses n−p directions to 0
Why: H maps the whole 5-D data space into the 2-D column space, so 3 directions die. There is nothing to invert — that information is gone. Its eigenvalues are 0 and 1, never all nonzero.
Break the constraint
Discussion prompt
The rule this trap just fixed:
H maps the whole 5-D data space into the 2-D column space, so 3 directions die. There is nothing to invert — that information is gone. Its eigenvalues are 0 and 1, never all nonzero.
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:
H has eigenvalues 0 (three of them). Any matrix with a zero eigenvalue has det = 0 and no inverse. inv(H) raises 'Singular matrix'.
Worked example
The column space of X is exactly what H projects onto, so H must leave every column of X unchanged: HX = X. Any vector already in the target space is its own shadow.
HX = X(XᵀX)⁻¹XᵀX
Why: Write H = X(XᵀX)⁻¹Xᵀ and multiply by X on the right. The trailing XᵀX meets its inverse.
\[ HX = X(X^\top X)^{-1}\underbrace{(X^\top X)}_{}= X\,I = X \]
import numpy as np
x = np.array([1., 2., 3., 4., 5.])
X = np.c_[np.ones(5), x]
H = X @ np.linalg.inv(X.T @ X) @ X.T
print("H@X == X:", np.allclose(H @ X, X))
print("H@(I-H) all zero:", np.allclose(H @ (np.eye(5) - H), 0))HX = X, and H(I−H) = 0
Why: H keeps the column space untouched, and it completely annihilates the residual projector — H − H² = 0. The two projectors have zero overlap, which is why the fit and residual are perpendicular.
| identity | value (verified) |
|---|---|
| H X == X | True |
| H (I − H) == 0 | True |
| meaning | H fixes col(X), kills the rest |
Section
Part 4 of 7
Concept
If H grabs the part of y inside the column space, then whatever is left over is y − Hy = (I − H)y. That leftover is the residual.
\[ r = y - \hat y = (I - H)\,y \]
I − H is itself an orthogonal projector — onto the space perpendicular to the column space. Two complementary shadows: H onto the fit, I − H onto the error.
Picture it
Figure (svg): A point y above a horizontal plane. A vertical dashed line drops from y to its foot yhat on the plane, labeled Hy. The horizontal segment from the origin to yhat is the fit; the vertical segment from yhat up to y is the residual, labeled (I-H)y, meeting the plane at a right angle.
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:
H and I − H split every vector into two perpendicular pieces that add back to the original: Hy + (I − H)y = y. One shadow on the fit, one shadow on the error.
Intuition
H and I − H split every vector into two perpendicular pieces that add back to the original: Hy + (I − H)y = y. One shadow on the fit, one shadow on the error.
Figure (svg): A point y above a horizontal plane. A vertical dashed line drops from y to its foot yhat on the plane, labeled Hy. The horizontal segment from the origin to yhat is the fit; the vertical segment from yhat up to y is the residual, labeled (I-H)y, meeting the plane at a right angle.
Because the two pieces meet at a right angle, Pythagoras gives ‖y‖² = ‖Hy‖² + ‖(I−H)y‖² — the identity behind R² and the ANOVA sum-of-squares split.
Estimation
Predict first
Prove (I − H)² = I − H using only H² = H. Expand the square like ordinary binomials (matrices commute with I).
Commit before you compute: what does I − H is a projector too come out to? A rough magnitude and the right form is enough — the point is to have something concrete to be wrong about.
Correct: Replace H² with H
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. Idempotence of H: H² = H. So −2H + H² = −2H + H = −H.
Worked example
Prove (I − H)² = I − H using only H² = H. Expand the square like ordinary binomials (matrices commute with I).
Expand (I − H)²
Why: (I − H)(I − H) = I·I − I·H − H·I + H·H = I − H − H + H².
\[ (I - H)^2 = I - 2H + H^2 \]
Replace H² with H
Why: Idempotence of H: H² = H. So −2H + H² = −2H + H = −H.
\[ (I - H)^2 = I - 2H + H = I - H \]
import numpy as np
x = np.array([1., 2., 3., 4., 5.])
X = np.c_[np.ones(5), x]
H = X @ np.linalg.inv(X.T @ X) @ X.T
M = np.eye(5) - H
print("(I-H)^2 == (I-H):", np.allclose(M @ M, M))
print("(I-H).T == (I-H):", np.allclose(M, M.T))| check | value (verified) |
|---|---|
| (I−H)² == I−H | True |
| (I−H)ᵀ == I−H | True |
| so I−H is | an orthogonal projector |
Notation
Annotate
From I − H is a projector too — read this one piece at a time. What is each part doing?
On: \( (I - H)^2 = I - 2H + H = I - H \)
Fill the middle
Fill in the blanks
From Residuals ⊥ fitted values — one line has had its right-hand side removed. Put it back.
import numpy as np
x = np.array([1., 2., 3., 4., 5.])
y = np.array([2., 4., 5., 4., 5.])
X = np.c_[np.ones(5), x]
H = X @ np.linalg.inv(X.T @ X) @ X.T
M = np.eye(5) - H # residual projector
r = M @ y
yhat = H @ y
print("r =", r.round(4))
print("r . yhat =", round(float(r @ yhat), 10))
print("trace(I-H) =", round(np.trace(M), 4)) # n - p = 5 - 2
Why: H is what everything below it consumes, so the wrong expression here fails later and somewhere else. The residuals are exactly Lesson 7's, and they have zero overlap with the fit — H·(I−H) = 0 because HᵀM = H(I−H) = H − H² = 0.
Worked example
The geometric heart of Lesson 7, now in H-language: the residual r is orthogonal to the fitted ŷ, so their dot product is zero. Compute r, then r·ŷ.
import numpy as np
x = np.array([1., 2., 3., 4., 5.])
y = np.array([2., 4., 5., 4., 5.])
X = np.c_[np.ones(5), x]
H = X @ np.linalg.inv(X.T @ X) @ X.T
M = np.eye(5) - H # residual projector
r = M @ y
yhat = H @ y
print("r =", r.round(4))
print("r . yhat =", round(float(r @ yhat), 10))
print("trace(I-H) =", round(np.trace(M), 4)) # n - p = 5 - 2r = [−0.8, 0.6, 1.0, −0.6, −0.2]; r·ŷ = 0
Why: The residuals are exactly Lesson 7's, and they have zero overlap with the fit — H·(I−H) = 0 because HᵀM = H(I−H) = H − H² = 0. Perpendicularity, restated.
trace(I − H) = 3 = n − p
Why: The residual space has dimension n − p = 5 − 2 = 3 — the 'residual degrees of freedom' used to estimate the noise variance in statistics.
| quantity | value (verified) |
|---|---|
| r = (I−H)y | [−0.8, 0.6, 1.0, −0.6, −0.2] |
| r · ŷ | 0.0 |
| trace(I − H) | 3 ( = n − p ) |
Blank canvas
Draw it
Draw what Residuals ⊥ fitted values 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.
Faded example
Fill in the blanks
The Pythagorean sum-of-squares split, with the scaffolding fading: two lines are gone now — fill both.
import numpy as np
x = np.array([1., 2., 3., 4., 5.])
y = np.array([2., 4., 5., 4., 5.])
X = np.c_[np.ones(5), x]
H = X @ np.linalg.inv(X.T @ X) @ X.T
yhat = H @ y
r = y - yhat
print("||y||^2 =", round(float(y @ y), 4))
print("||yhat||^2 =", round(float(yhat @ yhat), 4))
print("||r||^2 (RSS) =", round(float(r @ r), 4))
print("split holds:", np.allclose(y @ y, yhat @ yhat + r @ r))
Why: Reproducing these unaided, rather than reading them, is what tells you the method has transferred. The total energy of y splits cleanly into the fitted part (83.6) and the residual part (2.4 = the minimized error).
Worked example
Because Hy ⊥ (I−H)y, the squared lengths add: ‖y‖² = ‖ŷ‖² + ‖r‖². This is the identity that underlies R² and every ANOVA table. Verify it on our data.
import numpy as np
x = np.array([1., 2., 3., 4., 5.])
y = np.array([2., 4., 5., 4., 5.])
X = np.c_[np.ones(5), x]
H = X @ np.linalg.inv(X.T @ X) @ X.T
yhat = H @ y
r = y - yhat
print("||y||^2 =", round(float(y @ y), 4))
print("||yhat||^2 =", round(float(yhat @ yhat), 4))
print("||r||^2 (RSS) =", round(float(r @ r), 4))
print("split holds:", np.allclose(y @ y, yhat @ yhat + r @ r))86 = 83.6 + 2.4 exactly
Why: The total energy of y splits cleanly into the fitted part (83.6) and the residual part (2.4 = the minimized error). No cross term survives — that's the perpendicularity paying off.
| quantity | value (verified) |
|---|---|
| ‖y‖² | 86.0 |
| ‖ŷ‖² (fit) | 83.6 |
| ‖r‖² (RSS) | 2.4 |
| 83.6 + 2.4 | 86.0 ✓ |
Comparison
Comparison matrix
From The Pythagorean sum-of-squares split: refill the value (verified) column from what you know. The rest of the table is as it appeared.
| quantity | value (verified) |
|---|---|
| ‖y‖² | 86.0 |
| ‖ŷ‖² (fit) | 83.6 |
| ‖r‖² (RSS) | 2.4 |
| 83.6 + 2.4 | 86.0 ✓ |
Section
Part 5 of 7
Concept
Since ŷ = Hy, entry i of the fit is ŷᵢ = Σⱼ Hᵢⱼ yⱼ. The coefficient of a point's own yᵢ in its own fitted value is the diagonal entry hᵢᵢ.
leverage — hᵢᵢ = the diagonal of H. It measures how strongly point i's own yᵢ pulls its own fitted ŷᵢ. High leverage = an extreme x-position with lots of pull on the line. It depends on X only — never on y.
\[ \frac{\partial \hat y_i}{\partial y_i} = h_{ii}, \qquad 0 \le h_{ii} \le 1 \]
Definition probe
Sort into buckets
Every line below is part of the definition of orthogonal projection matrix or of leverage — one or the other, never both. Put each where it belongs.
Concept
Leverage is bounded because H is a symmetric projector. The diagonal of such a matrix is hᵢᵢ = Σⱼ Hᵢⱼ² (using H = H² = HᵀH), a sum of squares — so hᵢᵢ ≥ 0.
And hᵢᵢ = hᵢᵢ² + Σ_{j≠i} Hᵢⱼ² ≥ hᵢᵢ² forces hᵢᵢ ≤ 1. A leverage near 1 means point i almost single-handedly determines its own fitted value — the line is chasing it.
\[ 0 \le h_{ii} \le 1, \qquad \text{average } \bar h = \frac{\operatorname{tr}(H)}{n} = \frac{p}{n} \]
Fill the middle
Fill in the blanks
From Read leverage off diag(H) — one line has had its right-hand side removed. Put it back.
import numpy as np
x = np.array([1., 2., 3., 4., 5.])
X = np.c_[np.ones(5), x]
H = X @ np.linalg.inv(X.T @ X) @ X.T
lev = np.diag(H) # leverage = diagonal of H
print("leverage =", lev.round(4))
print("sum =", round(float(lev.sum()), 4), " trace =", round(np.trace(H), 4))
Why: H is what everything below it consumes, so the wrong expression here fails later and somewhere else. The two endpoints tie at 0.6 (most pull), the center point is lowest at 0.2, and they sum to the number of parameters.
Worked example
Pull the diagonal and confirm it sums to tr(H) = p = 2. Predict first: the endpoints x=1 and x=5 are farthest from the mean x̄=3, so they should carry the most leverage.
import numpy as np
x = np.array([1., 2., 3., 4., 5.])
X = np.c_[np.ones(5), x]
H = X @ np.linalg.inv(X.T @ X) @ X.T
lev = np.diag(H) # leverage = diagonal of H
print("leverage =", lev.round(4))
print("sum =", round(float(lev.sum()), 4), " trace =", round(np.trace(H), 4))leverage = [0.6, 0.3, 0.2, 0.3, 0.6]; Σ = 2 = tr(H) = p
Why: The two endpoints tie at 0.6 (most pull), the center point is lowest at 0.2, and they sum to the number of parameters. Leverage always sums to p.
| point (x) | leverage hᵢᵢ | note |
|---|---|---|
| 1 | 0.6 | endpoint — max pull |
| 2 | 0.3 | |
| 3 | 0.2 | center — min pull |
| 4 | 0.3 | |
| 5 | 0.6 | endpoint — max pull |
Intuition
Picture the regression line as a see-saw balanced at the mean x̄. A point far out on the end has a long lever arm, so nudging its y swings the whole line hard.
A point sitting right at the center x̄ is on the pivot — moving its y barely tilts the line at all. That is exactly why leverage grows with distance from x̄.
Pattern
Predict first
The table runs: 1 | 0.2 | 0.4 | 0.6 | 0.6 · 3 | 0.2 | 0.0 | 0.2 | 0.2
In Leverage the closed-form way, given the rows so far: what is the next one — the row where x is 5?
Correct: 5 | 0.2 | 0.4 | 0.6 | 0.6
| x | 1/n | (x−3)²/10 | hᵢᵢ | diag(H) |
|---|---|---|---|---|
| 1 | 0.2 | 0.4 | 0.6 | 0.6 |
| 3 | 0.2 | 0.0 | 0.2 | 0.2 |
| 5 | 0.2 | 0.4 | 0.6 | 0.6 |
Why: The relationship between the columns, not the individual numbers, is what generates the next row. x=1: 0.2 + 4/10 = 0.6. x=3: 0.2 + 0/10 = 0.2.
Worked example
For simple regression there's a hand formula, and it must match diag(H). With n=5, x̄=3, and Sxx = Σ(xᵢ−x̄)² = 4+1+0+1+4 = 10:
\[ h_{ii} = \frac{1}{n} + \frac{(x_i - \bar x)^2}{\sum_k (x_k - \bar x)^2} = \frac{1}{5} + \frac{(x_i - 3)^2}{10} \]
import numpy as np
x = np.array([1., 2., 3., 4., 5.])
X = np.c_[np.ones(5), x]
H = X @ np.linalg.inv(X.T @ X) @ X.T
n = 5
xbar = x.mean()
Sxx = np.sum((x - xbar)**2) # 10.0
hand = 1/n + (x - xbar)**2 / Sxx # closed form for simple regression
print("hand =", hand.round(4))
print("diag(H) =", np.diag(H).round(4))
print("match:", np.allclose(hand, np.diag(H)))The closed form equals diag(H) exactly
Why: x=1: 0.2 + 4/10 = 0.6. x=3: 0.2 + 0/10 = 0.2. x=5: 0.2 + 4/10 = 0.6. The 1/n floor plus a term that grows with (xᵢ−x̄)². Two independent routes, same numbers.
| x | 1/n | (x−3)²/10 | hᵢᵢ | diag(H) |
|---|---|---|---|---|
| 1 | 0.2 | 0.4 | 0.6 | 0.6 |
| 3 | 0.2 | 0.0 | 0.2 | 0.2 |
| 5 | 0.2 | 0.4 | 0.6 | 0.6 |
Reverse engineer
Discussion prompt
Work backwards. The example finished here:
The closed form equals diag(H) exactly
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:
For simple regression there's a hand formula, and it must match diag(H). With n=5, x̄=3, and Sxx = Σ(xᵢ−x̄)² = 4+1+0+1+4 = 10:
Intuition
Each unit of leverage is a slice of a data point 'spent' on fitting a parameter. Summed over all points, the model spends exactly p units — one per free parameter. That total is tr(H) = p.
The n − p left over (tr(I − H)) is what remains to estimate the noise. It's why you divide by n − p, not n, for an unbiased variance — a 2-point line through 2 points has zero residual freedom and can't estimate noise at all.
Section
Part 6 of 7
Intuition
High leverage only says a point could move the line a lot — it has a long lever arm. It does not say the point is bad.
A high-leverage point sitting exactly on the trend actually stabilizes the fit. The danger is a point with high leverage and a big residual — long lever arm and off-trend. That combination is influence.
Concept
Cook's distance Dᵢ measures how much the whole fitted vector shifts if you delete point i. It multiplies the point's squared residual by a leverage factor:
\[ D_i = \frac{r_i^2}{p\,s^2}\cdot\frac{h_{ii}}{(1 - h_{ii})^2}, \qquad s^2 = \frac{\sum_k r_k^2}{n - p} \]
s² is the mean squared error (RSS/(n−p)). A point scores high only when both factors are large — a real residual rᵢ and real leverage hᵢᵢ. Neither alone is enough.
Intuition
The residual you see, rᵢ = yᵢ − ŷᵢ, is smaller than the point's true error, because a high-leverage point drags its own ŷᵢ toward itself — hiding its miss. The factor 1/(1−hᵢᵢ)² un-hides it.
As hᵢᵢ → 1, that amplifier blows up: a point so influential that the line nearly passes through it shows almost no residual, yet deleting it would move the fit a lot. Cook's distance corrects for exactly this masking.
Missing information
Discussion prompt
RSS = 2.4, n−p = 3, so s² = 0.8. Feed residuals and leverage into the formula. Which point is most influential?
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:
Point 1 (x=1) has BOTH high leverage 0.6 AND a big residual −0.8, so its D = 1.50 dwarfs the rest. Point 3 has the largest residual (1.0) but low leverage (0.2), so only D = 0.20.
Worked example
RSS = 2.4, n−p = 3, so s² = 0.8. Feed residuals and leverage into the formula. Which point is most influential?
import numpy as np
x = np.array([1., 2., 3., 4., 5.])
y = np.array([2., 4., 5., 4., 5.])
X = np.c_[np.ones(5), x]
p = X.shape[1] # 2 parameters
H = X @ np.linalg.inv(X.T @ X) @ X.T
h = np.diag(H)
r = y - H @ y # residuals
s2 = np.sum(r**2) / (5 - p) # MSE = RSS/(n-p) = 2.4/3
D = r**2 / (p * s2) * h / (1 - h)**2
print("Cook's D =", D.round(4))
print("most influential point:", int(np.argmax(D)) + 1)Cook's D = [1.50, 0.14, 0.20, 0.14, 0.09]; point 1 wins
Why: Point 1 (x=1) has BOTH high leverage 0.6 AND a big residual −0.8, so its D = 1.50 dwarfs the rest. Point 3 has the largest residual (1.0) but low leverage (0.2), so only D = 0.20.
| point | residual r | leverage h | Cook's D |
|---|---|---|---|
| 1 | −0.8 | 0.6 | 1.5000 |
| 2 | 0.6 | 0.3 | 0.1378 |
| 3 | 1.0 | 0.2 | 0.1953 |
| 4 | −0.6 | 0.3 | 0.1378 |
| 5 | −0.2 | 0.6 | 0.0938 |
Pattern
Step through it
Step through Compute Cook's distance for all five points one row at a time. What is driving the change, and what would the row after the last one be?
Estimation
Predict first
Cook's distance predicts point 1 shifts the fit most. Test it directly — refit with each point deleted and compare w to the full [2.2, 0.6].
Commit before you compute: what does Prove it: leave one point out come out to? A rough magnitude and the right form is enough — the point is to have something concrete to be wrong about.
Correct: Drop point 3 → w = [1.95, 0.6]: barely moves
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 center point had the biggest residual but tiny leverage, so deleting it hardly touches the line — matching its small Cook's D of 0.20.
Worked example
Cook's distance predicts point 1 shifts the fit most. Test it directly — refit with each point deleted and compare w to the full [2.2, 0.6].
import numpy as np
x = np.array([1., 2., 3., 4., 5.])
y = np.array([2., 4., 5., 4., 5.])
X = np.c_[np.ones(5), x]
w_full = np.linalg.solve(X.T @ X, X.T @ y) # [2.2, 0.6]
for drop in (0, 2): # drop point 1 (endpoint) then point 3 (center)
keep = [i for i in range(5) if i != drop]
Xd, yd = X[keep], y[keep]
wd = np.linalg.solve(Xd.T @ Xd, Xd.T @ yd)
print(f"drop point {drop+1}: w = {wd.round(4)}")
print("full fit: w =", w_full.round(4))Drop point 1 → w = [3.8, 0.2]: a huge swing
Why: Removing the high-influence endpoint moves the intercept from 2.2 to 3.8 and the slope from 0.6 to 0.2. That massive shift is exactly the D = 1.5 warning made real.
Drop point 3 → w = [1.95, 0.6]: barely moves
Why: The center point had the biggest residual but tiny leverage, so deleting it hardly touches the line — matching its small Cook's D of 0.20. Influence, not residual, is what matters.
| deleted point | refit w = [w₀, w₁] | Cook's D | shift |
|---|---|---|---|
| none (full) | [2.2, 0.6] | — | — |
| point 1 (x=1) | [3.8, 0.2] | 1.50 | large |
| point 3 (x=3) | [1.95, 0.6] | 0.20 | tiny |
Error analysis
Annotate
Walk the callouts on Prove it: leave one point out. Each one is a place this is easy to get subtly wrong.
Concept
Cook's distance is a screening tool, not an auto-delete rule. A common rule of thumb flags any point with Dᵢ > 4/n for a closer look.
\[ \frac{4}{n} = \frac{4}{5} = 0.8 \]
Only point 1 (D = 1.5) clears the 0.8 bar — every other point sits well below it. That single flag is the model telling you: 'look at student 1 before you trust this line.'
Explain it
Discussion prompt
Explain Reading Cook's distance 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:
Cook's distance is a screening tool, not an auto-delete rule. A common rule of thumb flags any point with Dᵢ > 4/n for a closer look.
Anomaly
Predict first
A student writes this, and it looks reasonable:
Point 1 and point 5 both have leverage 0.6, the highest — they're outliers dragging the fit, so drop them.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: Leverage is computed from X alone — it's pure x-position, not error.
Judge points by Cook's distance, which needs leverage and a residual. Only point 1 is actually influential.
Why: Leverage is computed from X alone — it's pure x-position, not error. Point 5 sits nearly on the line (residual −0.2, Cook's D 0.09); deleting it just throws away good data and widens your intervals.
Trap
Point 1 and point 5 both have leverage 0.6, the highest — they're outliers dragging the fit, so drop them.
Delete both high-leverage endpoints
Why: Leverage is computed from X alone — it's pure x-position, not error. Point 5 sits nearly on the line (residual −0.2, Cook's D 0.09); deleting it just throws away good data and widens your intervals.
Judge points by Cook's distance, which needs leverage and a residual. Only point 1 is actually influential.
Flag point 1 (D=1.5); keep point 5 (D=0.09)
Why: Same leverage 0.6, wildly different influence, because point 1 is off-trend and point 5 is on it. Investigate high-D points; don't reflexively delete high-leverage ones.
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.
w★ that make Xw★ the closest point in the column space of X to the target y. The residual came out perpendicular to that space.; We reuse Lesson 7's data so every number connects: five students, hours x and score y, fit by ŷ = w₀ + w₁·x.; The hat matrix is built from X alone — the feature positions. It does not depend on the targets y at all.P² = I — apply it twice and you're back where you started.; H is 5×5 and packed with nonzero entries, so it's an invertible matrix like any other — just call inv(H).Section
Part 7 of 7 — the project
Ranking
Put in order
These are the steps of The projection / hat-matrix toolkit, scrambled. Put them back in order before the next slide shows you.
P² = P (idempotent) and Pᵀ = P (symmetric) ⇒ eigenvalues 0/1, singular, rank = tr(P)H = X(XᵀX)⁻¹Xᵀ; the fit is ŷ = Hy — no need to solve for wr = (I − H)y, orthogonal to the fit (r·ŷ = 0); tr(I − H) = n − phᵢᵢ = diag(H), sums to tr(H) = p; closed form 1/n + (xᵢ−x̄)²/SxxDᵢ combines leverage and residual — flag high D, don't just delete high hWhy: This is the order the recipe itself gives. Recalling the sequence without the slide in front of you is the difference between recognising the method and being able to run it — most of what goes wrong in practice is a step done out of turn.
Pattern
P² = P (idempotent) and Pᵀ = P (symmetric) ⇒ eigenvalues 0/1, singular, rank = tr(P)H = X(XᵀX)⁻¹Xᵀ; the fit is ŷ = Hy — no need to solve for wr = (I − H)y, orthogonal to the fit (r·ŷ = 0); tr(I − H) = n − phᵢᵢ = diag(H), sums to tr(H) = p; closed form 1/n + (xᵢ−x̄)²/SxxDᵢ combines leverage and residual — flag high D, don't just delete high hEdge cases
Discussion prompt
The projection / hat-matrix 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:
P² = P (idempotent) and Pᵀ = P (symmetric) ⇒ eigenvalues 0/1, singular, rank = tr(P)H = X(XᵀX)⁻¹Xᵀ; the fit is ŷ = Hy — no need to solve for wr = (I − H)y, orthogonal to the fit (r·ŷ = 0); tr(I − H) = n − phᵢᵢ = diag(H), sums to tr(H) = p; closed form 1/n + (xᵢ−x̄)²/SxxDᵢ combines leverage and residual — flag high D, don't just delete high hElimination
Eliminate the wrong options
An orthogonal projection matrix P satisfies which pair of properties?
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.
Survives elimination: A
Why: Idempotent (P² = P: projecting twice equals once) plus symmetric (Pᵀ = P: the drop is perpendicular). Together these force the eigenvalues to be only 0 and 1, so P is singular whenever it isn't the identity.
Check
Picture the shadow on the floor before you answer.
Check your understanding
An orthogonal projection matrix P satisfies which pair of properties?
Answer: A
Why: Idempotent (P² = P: projecting twice equals once) plus symmetric (Pᵀ = P: the drop is perpendicular). Together these force the eigenvalues to be only 0 and 1, so P is singular whenever it isn't the identity.
Prediction
Predict first
For the hat matrix H of a regression with n data points and p parameters (intercept included), tr(H) equals:
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: p — the number of parameters / dimension of the column space
Why: H projects onto the p-dimensional column space, so its eigenvalues are p ones and (n−p) zeros. The trace is the sum of eigenvalues, hence p — the model's degrees of freedom. For our data that is 2.
Check
Think eigenvalues: H has p ones and n−p zeros.
Check your understanding
For the hat matrix H of a regression with n data points and p parameters (intercept included), tr(H) equals:
Answer: A
Why: H projects onto the p-dimensional column space, so its eigenvalues are p ones and (n−p) zeros. The trace is the sum of eigenvalues, hence p — the model's degrees of freedom. For our data that is 2.
Prediction
Predict first
Two points share the same high leverage hᵢᵢ = 0.6, but point 1 has residual −0.8 and point 5 has residual −0.2. What follows?
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: Point 1 is far more influential — high leverage AND a large residual give it a big Cook's distance
Why: Cook's distance multiplies the squared residual by a leverage factor, so it's large only when both are large. Point 1 (h=0.6, r=−0.8) scores D=1.50; point 5 (h=0.6, r=−0.2) scores just 0.09 — and deleting point 1 swings w from [2.2,0.6] to [3.8,0.2].
Check
Recall: point 1 and point 5 both had leverage 0.6.
Check your understanding
Two points share the same high leverage hᵢᵢ = 0.6, but point 1 has residual −0.8 and point 5 has residual −0.2. What follows?
Answer: A
Why: Cook's distance multiplies the squared residual by a leverage factor, so it's large only when both are large. Point 1 (h=0.6, r=−0.8) scores D=1.50; point 5 (h=0.6, r=−0.2) scores just 0.09 — and deleting point 1 swings w from [2.2,0.6] to [3.8,0.2].
Elimination
Eliminate the wrong options
You call np.linalg.inv(H) on a 5×5 hat matrix from a 2-parameter fit. What happens?
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.
Survives elimination: A
Why: H has eigenvalues [0,0,0,1,1]; three zeros mean det(H) = 0 and no inverse exists. inv(H) raises 'Singular matrix'. A projector (other than the identity) is always singular — it destroys the n−p residual directions, and that information can't be recovered.
Check
What are H's eigenvalues again?
Check your understanding
You call np.linalg.inv(H) on a 5×5 hat matrix from a 2-parameter fit. What happens?
Answer: A
Why: H has eigenvalues [0,0,0,1,1]; three zeros mean det(H) = 0 and no inverse exists. inv(H) raises 'Singular matrix'. A projector (other than the identity) is always singular — it destroys the n−p residual directions, and that information can't be recovered.
Concept
Build H for the 5-student data, prove it's a projector, recover the OLS fit, and read leverage off the diagonal — assembling every piece you just derived, by hand.
| # | requirement | tool |
|---|---|---|
| 1 | H = X(XᵀX)⁻¹Xᵀ; verify H²=H, Hᵀ=H, tr(H)=p | np.linalg.inv, np.trace |
| 2 | ŷ = Hy; residuals r = (I−H)y ⊥ fitted | matmul, dot |
| 3 | leverage = diag(H); sums to tr(H); find the max | np.diag, np.argmax |
Build rules: type every line yourself, always include the ones column in X, and when a shape error appears, read it — check X.shape before you delete anything.
Analogy
Discussion prompt
Explain Project: hat matrix, residuals & leverage 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:
Build H for the 5-student data, prove it's a projector, recover the OLS fit, and read leverage off the diagonal — assembling every piece you just derived, by hand.
Worked example
Your turn: build H and confirm it's idempotent and symmetric. Predict its rank out loud before printing (hint: how many parameters?).
Hint: H = X @ np.linalg.inv(X.T @ X) @ X.T, then np.allclose(H @ H, H) and np.allclose(H, H.T).
import numpy as np
x = np.array([1., 2., 3., 4., 5.])
X = np.c_[np.ones(5), x]
H = X @ np.linalg.inv(X.T @ X) @ X.T
print("H@H==H:", np.allclose(H @ H, H))
print("H.T==H:", np.allclose(H, H.T))
print("rank =", np.linalg.matrix_rank(H), " trace =", round(np.trace(H), 4))| check | value |
|---|---|
| H@H==H, H.T==H | True, True |
| rank(H) | 2 |
| trace(H) | 2 ( = p ) |
Pattern
Step through it
Step through Milestone 1 — build & verify H one row at a time. What is driving the change, and what would the row after the last one be?
Worked example
Your turn: compute ŷ = Hy and the residual r = y − ŷ, then confirm r·ŷ ≈ 0. Predict the fitted values from the by-hand w = [2.2, 0.6] first.
Hint: yhat = H @ y; r = y - yhat; then r @ yhat should be about 0.
import numpy as np
x = np.array([1., 2., 3., 4., 5.])
y = np.array([2., 4., 5., 4., 5.])
X = np.c_[np.ones(5), x]
H = X @ np.linalg.inv(X.T @ X) @ X.T
yhat = H @ y
r = y - yhat
print("yhat =", yhat.round(4))
print("r =", r.round(4))
print("r . yhat =", round(float(r @ yhat), 8))| quantity | value |
|---|---|
| ŷ | [2.8, 3.4, 4.0, 4.6, 5.2] |
| r | [−0.8, 0.6, 1.0, −0.6, −0.2] |
| r · ŷ | 0.0 |
Worked example
Your turn: extract leverage from diag(H), confirm it sums to tr(H) = 2, and find the most-leveraged point. Predict which x wins before printing.
Hint: lev = np.diag(H); lev.sum(); np.argmax(lev) (remember it's 0-indexed — add 1).
import numpy as np
x = np.array([1., 2., 3., 4., 5.])
X = np.c_[np.ones(5), x]
H = X @ np.linalg.inv(X.T @ X) @ X.T
lev = np.diag(H)
print("leverage =", lev.round(4))
print("sum =", round(float(lev.sum()), 4))
print("argmax (1-indexed):", int(np.argmax(lev)) + 1)| point | leverage | note |
|---|---|---|
| 1 (x=1) | 0.6 | endpoint — ties for max |
| 3 (x=3) | 0.2 | center — min |
| 5 (x=5) | 0.6 | endpoint — ties for max |
Trade off
Comparison matrix
From Milestone 3 — leverage: every row here is a choice with a cost. Fill the leverage column, then say which row you would actually pick and what you give up for it.
| point | leverage | note |
|---|---|---|
| 1 (x=1) | 0.6 | endpoint — ties for max |
| 3 (x=3) | 0.2 | center — min |
| 5 (x=5) | 0.6 | endpoint — ties for max |
Concept
import numpy as np
x = np.array([1., 2., 3., 4., 5.])
y = np.array([2., 4., 5., 4., 5.])
X = np.c_[np.ones(5), x] # 1. bias column + feature
H = X @ np.linalg.inv(X.T @ X) @ X.T # 2. hat matrix
yhat = H @ y # fitted values ŷ = Hy
r = y - yhat # residuals = (I - H)y
lev = np.diag(H) # 3. leverage scores
print('projector:', np.allclose(H @ H, H) and np.allclose(H, H.T))
print('yhat =', yhat.round(3))
print('r . yhat =', round(float(r @ yhat), 8))
print('leverage =', lev.round(3), ' sum =', round(float(lev.sum()), 3))
print('tr(H) =', round(np.trace(H), 3))| printed line | value |
|---|---|
| projector: | True |
| yhat = | [2.8, 3.4, 4.0, 4.6, 5.2] |
| r . yhat = | 0.0 |
| leverage / sum | [0.6, 0.3, 0.2, 0.3, 0.6] / 2.0 |
| tr(H) = | 2.0 |
If H is a projector, ŷ matches the OLS line, r·ŷ is 0, and leverage sums to p — you've turned least-squares geometry into a single matrix.
Comparison
Comparison matrix
From The full program: refill the value column from what you know. The rest of the table is as it appeared.
| printed line | value |
|---|---|
| projector: | True |
| yhat = | [2.8, 3.4, 4.0, 4.6, 5.2] |
| r . yhat = | 0.0 |
| leverage / sum | [0.6, 0.3, 0.2, 0.3, 0.6] / 2.0 |
| tr(H) = | 2.0 |
Concept
Slides closed, out loud: explain (1) why H² = H (the (XᵀX)⁻¹(XᵀX) cancellation), (2) why residuals are perpendicular to fitted values, and (3) what tr(H) counts geometrically.
Stretch: rebuild H = Q Qᵀ from the QR factorization Q, _ = np.linalg.qr(X) and confirm it matches — the numerically sound way that never forms XᵀX. Then reproduce the Cook's-distance table and the leave-one-out swing on your own.
Counterexample
Discussion prompt
Slides closed, out loud: explain (1) why H² = H (the (XᵀX)⁻¹(XᵀX) cancellation), (2) why residuals are perpendicular to fitted values, and (3) what tr(H) counts geometrically.
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.
Connect it up
Draw it
One page, no notation unless you need it: draw how these connect — The idea: least squares as a matrix · Projection matrices · Building the hat matrix · Residuals & the I − H projector · Leverage & the trace · Influence: Cook's distance. Put an arrow wherever one of them is what makes another possible, and label the arrow with why.
Recap
P² = P, Pᵀ = P — eigenvalues 0/1, singular, rank = trH = X(XᵀX)⁻¹Xᵀ, get ŷ = Hy, and prove H² = H and Hᵀ = H by handI − H for residuals, perpendicular to the fit, with tr(I − H) = n − phᵢᵢ off diag(H) (or 1/n + (xᵢ−x̄)²/Sxx), summing to tr(H) = p| idea | the one thing to remember |
|---|---|
| projector | P² = P, Pᵀ = P ⇒ eigenvalues 0/1, singular |
| hat matrix | ŷ = Hy; H = X(XᵀX)⁻¹Xᵀ — no need to solve for w |
| residuals | r = (I−H)y ⊥ fit; tr(I−H) = n − p |
| leverage | diag(H); sums to tr(H) = p; x-extremeness |
| influence | Cook's D needs leverage AND a residual — not leverage alone |
Want this taught 1-on-1? Alexander tutors Machine Learning — $55/session, free consultation.