◈ quant roadmapPart 2 · Ch 20/45
Quantitative Finance — the Mathematics of Markets · chapter 20

20OLS Regression: Mechanics & Diagnostics

Chapter 19 left us screening candidates one at a time and paying a bill for every look. There is an obvious improvement available, and we are about to take it. Put every candidate driver into one model and ask what each one is worth once the others are accounted for. That model is ordinary least squares, and it is the most-run calculation in quantitative finance. Here is the thing almost nobody is told about it. The whole first half of this chapter needs no probability at all. Not one distribution, not one assumption, not one random variable. A regression is a perpendicular, dropped from a point onto a flat plane, and that act is available on any table of numbers you will ever hold. The famous fine print arrives later and it is not a precondition for the arithmetic. It is admission money for a different question, about whether the answer means anything. And of the five assumptions, exactly one protects the number. The rest protect only the error bar. That single split organises everything in the back half of this chapter, and it is the sentence to carry out the door.

Look at what this page stands on, because almost all of it is already yours. Chapter 6 gave us the column space, rank, the overdetermined system, and the orthogonal projection that it deliberately set up and left uncompleted. Chapter 7 gave us the condition number and the pseudo-inverse. Chapter 8 gave us contour maps and the flat spot at the bottom of a convex bowl. Chapter 16 gave us the estimand, the sampling distribution, and Bessel's correction with a promise attached to it. Chapter 17 gave us the whole testing template. Chapter 18 gave us the identification ρ = cos θ, and Chapter 19 gave us the family and its bill.

Ch 19 left you screening drivers one at a time. Tap the lanes, watch the bill climb — then press ONE MODEL and see what does not reset.
THE SCREENING BENCH · ONE DRIVER AT A TIME ▸ tap a lane to test it DRIVER SAMPLE ρ t p AT α = 0.05 BILL market tap to run this test 0.61 5.9 <0.001 LOOKS REAL value tap to run this test 0.28 2.3 0.024 LOOKS REAL momentum tap to run this test 0.22 1.8 0.078 no · misses size tap to run this test 0.31 2.6 0.011 LOOKS REAL vol tap to run this test 0.09 0.7 0.49 no · misses FAMILY‑WISE ERROR RATE nothing tested yet 0.0% THE MAP SO FAR tap a chapter ▾ Ch 6 Ch 16 Ch 18 Ch 20 Ch 21 Ch 22 Ch 24 Ch 30 Ch 20 · you are here: five columns, one fit, and still five t‑tests.

One regression asks a better question of each column. It does not ask fewer questions.

THE BENCH · 5 SEPARATE LOOKS
Each lane is one candidate driver, screened alone: its correlation ρ with the target, its t, its p. Tap a lane to actually run that test — and watch the gold bill climb.
0 looks · 0.0% risk
What you’re looking at — five separate looks, then the same five inside one call
the five candidate drivers — one lane each on the bench, one column each in the design matrix X.
passes at α = 0.05 (a 1-in-20 false-alarm rate per test)
does not pass — and merging flips two of these verdicts, because “worth something alone” and “worth something once the others are in” are different questions.
the bill: 5 tests at 5% each → 1−0.95⁵ = 22.6% chance of at least one fake winner. One function call prints five t-statistics, so the bill moved — it did not vanish.
Fig. 1. Five drivers screened one at a time, then the same five as five columns of one design matrix: the question each column answers gets better, and the number of tests you just ran does not go down.

That is the seam. Testing candidates one at a time was never the best available move, and putting them all in one model is a genuine improvement. But a model with twelve columns prints twelve t-statistics, so hold your enthusiasm. Chapter 19 is waiting inside a single function call.

01The number a correlation cannot give you

Start with a trade you actually have to place, because the gap opens the moment you try.

You are long £10m of a single stock and you want to hedge it with index futures. Chapter 18 hands you the relationship between the two return series: ρ = 0.80. Good. Now write the ticket. How many contracts?

You cannot answer. Correlation is unitless by construction, because we divided by both standard deviations, and that was the entire point of doing it. A trade needs a slope, a number in pounds of index per pound of stock. So the first honest statement of this chapter is that we need a different object from the one Chapter 18 gave us.

Bring the two volatilities back and the slope appears. The stock runs at 28% a year and the index at 16%, so β = ρ·σ_y/σ_x = 0.80 × 28/16 = 1.400. Your stock moves 1.4 pounds for every pound the index moves, so the hedge notional is £14.0m. With the index at 8,200 and £10 a point, one contract carries £82,000 of exposure, which makes the trade 171 contracts. Notice what happened there. The correlation alone was not enough, and the thing we actually wanted was a slope the whole time.

Now make it harder in the direction real work goes. You rarely have one candidate driver. You have the market, a sector ETF, and a currency, and the question is how much of each.

Chapter 6 already has a word for a weighted mix of columns. It is a linear combination, and the mix you are hunting for is a vector of weights. So write it down properly. Stack 500 days of predictor observations into a matrix X, one row per day and one column per predictor, put the 500 target returns into a vector y, and the model is Xβ = y.

A correlation of 0.80 will not tell you how many contracts to sell — drag it as far as you like, then put the two volatilities back.
DEALING TICKET £10.0m long correlation ρ 0.80 σ stock (annual) — not supplied — σ index (annual) — not supplied — β = ρ × σs ÷ σi cannot compute hedge notional cannot compute CONTRACTS · fut @ £82,000 UNITLESS · CANNOT SIZE ρ divides Cov by BOTH σ’s — that is where the units died. AND IF 3 THINGS DRIVE IT? X β y index × ? = stock ⋮ 494 more rows (one per day) EQUATIONS 500 UNKNOWNS 1 NO EXACT SOLUTION · 500 vs 1 y residual span = a line
▼ drag it — the ticket still refuses
ρ correlation0.80
σs stock vol28.0%
σi index vol16.0%
ρ is unitless · cannot size
1 unknown — one slope, one number.
Still 500 equations for it.
What you’re looking at — a ticket a correlation cannot fill in, and the system that appears once three things drive the stock.
β = ρ·σs/σi = 0.80×28/16 = 1.400 — the correlation with its units put back. A slope: pounds of index per pound of stock. That is what a ticket needs.
each blue column is one driver’s 500 daily returns; every driver you add is one more column and one more unknown weight, so β stops being a number and becomes a vector.
500 equations, 3 unknowns: Xβ = y has no exact answer, ever — the target sits off the space the columns can reach, and the gap is the residual. Ch 6’s overdetermined system, with money on it.
Fig. 2. Divide a covariance by both standard deviations and you get a pure number — and pure numbers cannot be sold. Multiply the units back in and the number that appears is a slope; ask three drivers at once and that slope becomes a vector we have 500 equations and no way to satisfy.

Now count what you just wrote. Five hundred equations. Three unknowns. Chapter 6 named this exactly: an overdetermined system, with the target sitting outside the column space and no exact solution.

Do not read that as failure, because it is not a symptom of bad data and no amount of cleaning will fix it. Five hundred arbitrary numbers cannot be produced by three knobs, and that is the permanent situation for every regression anyone has ever run. What it does is convert the whole problem into one open question. Since we cannot hit y, what does closest mean?

One more object before we answer that, because it is the thing the rest of the chapter is about. For any candidate β, the residual vector e = y − Xβ holds one number per observation. It is the whole of the model's failure, carried as a single arrow.

02What does closest actually mean?

We have to choose what closest means, and the choice is not cosmetic. It is the definition of the answer.

Take the smallest experiment that settles it. Here are three numbers: 1, 2 and 12. Fit a single constant c to them, which is the tiniest regression imaginable, one column of all ones.

First, notice you cannot just minimise the plain sum of residuals. Push c upward and Σ(yᵢ − c) runs away to minus infinity, so there is no minimum to find. The criterion has to be non-negative before it can mean anything at all.

There are two obvious ways to do that, and both of them sound perfectly sensible. You can take absolute values, or you can take squares. So run both and see what each one picks.

CodeRun — fit ONE number to {1, 2, 12}. Before you drag: which c makes each loss smallest? One criterion says 5, the other says 2.
python ↓ 1 import numpy as np 2 y = np.array([1, 2, 12]) 3 4 # plain sum: no bottom at all 5 print(np.sum(y - 99)) # -282 6 7 for c in range(1, 8): 8 r = y - c # residuals 9 sse = np.sum(r**2) 10 sad = np.sum(np.abs(r)) 11 n = np.linalg.norm(r) 12 print(c, sse, sad, n**2) 13 14 # n**2 IS sse. Always. Exactly. stdout ↓ c = 5 c SSE SAD 1 122 12 2 101 11 3 86 12 4 77 13 5 74 14 6 77 15 7 86 16 ← median ← mean norm(r)**2 sum(r**2) 74.00 = 74.00 len 8.602 shortest ⇒ nearest point drag → median mean
the guess  c = 5◀ drag ▶
c = 5 · squares bottom out: 74
Σ(y−c)²74
Σ|y−c|14
length of r8.602
Gold follows the squares, violet the absolutes. Watch where each one bottoms out.
What you're looking at — one number fitted to {1, 2, 12}, judged by two equally honest rules that disagree
Σ(y−c)² bottoms at c = 5, the mean — and 74 = 8.602325², so this sum is a squared length: least squares = nearest point.
Σ|y−c| bottoms at c = 2, the median. Just as non-negative, just as honest — so squares are a choice, not a law.
Σ(y−c) = 15−3c dives forever: no bottom, no answer. That is why a criterion must be non-negative.
Fig. 3. The smallest regression there is: fit one constant c to the three numbers 1, 2, 12. First, why the obvious criterion fails — the plain sum of residuals Σ(y−c) is 15−3c, so pushing c up drives it to −∞ and there is nothing to minimise. Press + plain sum and watch the red line walk straight off the bottom. So the criterion must be non-negative, and there are two obvious ways to do that: take absolute values, or square. The program runs both. The squares print 122, 101, 86, 77, 74, 77, 86 and bottom at c = 5 — the mean. The absolutes print 12, 11, 12, 13, 14, 15, 16 and bottom at c = 2 — the median. Identical data, identical honesty, two different answers; drag the rail and watch the gold bar and the violet bar sink to floors in different places. Then the line that carries the rest of the chapter: at c = 5 the sum of squares is 74.00, and the residual arrow’s length is 8.602325, whose square is 74.00. That is not a coincidence and it is not bookkeeping — a sum of squares is a squared length, so “least squares” means nearest point. Squaring was never about making the numbers positive; absolute values do that too, and they hand you the median instead. Squaring is what turns the fit into a distance — which is what will let us drop a perpendicular.

Minimising Σ|yᵢ − c| gives c = 2, which is the median. Minimising Σ(yᵢ − c)² gives c = 5, which is the mean, exactly as Chapter 16 proved in one line of calculus. Sit with that for a second, because it settles the question we opened with. Same three numbers, two perfectly reasonable criteria, two different answers, and neither is wrong.

So why does the whole field build on squares? The usual answers are that squaring makes residuals positive and punishes large errors more heavily. Both are true, and both are cover stories for the reason that actually matters.

Write the squared-error criterion out as a sum: Σ(yᵢ − ŷᵢ)². Chapter 6 and Chapter 18 both told us that a list of n numbers is a vector in ℝⁿ, and that the length of a vector is the square root of the sum of its squared entries. So that sum is nothing other than ‖y − ŷ‖², the squared distance from the point y to the point ŷ.

At c = 5 the sum of squares reads 74.00, and the residual arrow has length 8.6023, whose square is 74.00. Same number, twice.

So least squares does not mean a loss function that happens to square things. It means NEAREST POINT. That is the whole vocabulary shift of this chapter, and everything from here is a consequence of it.

Be honest about what we just discarded, because respecting the alternative is what makes the choice credible. Absolute deviation gives you a median, which shrugs off a crazy outlier in a way squares never will, and that is a genuine advantage and the reason quantile regression exists. It also has kinks where a residual crosses zero, it is not differentiable there, its answer can be non-unique, and it has no closed form. Squares are smooth, convex, uniquely minimised, solvable in one line of algebra, and they are a distance. That last property is the one we are about to spend the entire chapter cashing in.

03★★ Least squares is a perpendicular

This is the move the whole chapter turns on, and it is worth going slowly, because there are two different pictures in play and mixing them up is the most common permanent confusion in this subject.

Picture one is the row picture, and you already have it. Put n dots on two axes, x across and y up, and run a candidate line through them. Each residual is a vertical gap between a dot and the line.

Picture two is the column picture, which belongs to Chapter 6 and Chapter 18, and in it each data column becomes one arrow in ℝⁿ. So the predictor x is a single arrow, the target y is a single arrow, and a candidate fit ŷ = βx is a point sliding along the line spanned by x. Same numbers, transposed.

Name the trap now rather than later, because it catches everybody. In the row picture the residuals are vertical, and they are not perpendicular to the fitted line. In the column picture the residual arrow is about to become exactly perpendicular to the predictor arrow. Both statements are true, because they are statements about two different drawings of the same three numbers.

Now do the experiment yourself. Take three observations and one predictor, slide β across its range, and watch three things at once: the vertical gaps, the running total Σeᵢ², and the dot product x·e. Before you touch anything, commit to a guess about what happens to that dot product at the best fit.

One fit, drawn three ways. Before you touch the slider: at the β that makes Σe² smallest, what does the big number in C do?
A · ROW picture Σe² 9.86 0 y 1 2 3 x ↕ bars are VERTICAL — ⊥ is in B B · COLUMN picture 0 x y βx e Σe² across all β β = −0.5 2.5 C · the dot product x · e ? commit a prediction first
① commit a prediction ↓
What does C do at the best fit?
A’s bars are vertical.
B’s residual is the ⊥ one.
What you’re looking at — three observations, one knob β, and the same fit drawn three ways.
x, the predictor. In A it is the horizontal axis; in B it is one arrow, and the dashed line is every multiple βx you can reach.
y, the target. Three dots in A; one arrow in B that does not lie on that dashed line.
e = y − βx, the leftover: vertical bars in A, the joining arrow in B, and its dot product with x in C.
At one β only, Σe² bottoms out and e turns square on x — because dΣe²/dβ = −2(x·e).
Fig. 4. Three panels, one slider, one fit. In panel A you already know what you are looking at: three observations, a candidate line ŷ = βx through the origin, and the gaps — call each one ei = yi − βxi, the amount the line missed that point by — drawn as bars, with their squares added up into the single score Σei². Least squares is the instruction to make that one number as small as possible, and nothing more. Panel B is the identical fit wearing different clothes. Stop reading the three observations one at a time and read them down the columns: x = (1, 2, 3) is now a single arrow, y = (2.4, 1.0, 3.2) is another, and the dashed line is the only territory your model can reach — every scalar multiple βx, a one-dimensional world inside a three-dimensional one. Because x and y together span a plane, this flat picture is not a cartoon: lengths and angles in it are the true ones. The gold arrow joining the sliding point to y is the same leftover e as panel A’s bars, and its length squared is exactly Σei². And panel C is one number with nothing else on it: x·e = x1e1 + x2e2 + x3e3, the dot product of the predictor with what it failed to explain. Now the reason you were asked to commit before dragging: almost everyone expects the drama to be in A, the panel they already understand, and predicts that C does nothing in particular. Drag β and watch. Σei² falls, bottoms out, and climbs again — the parabola under panel A traces the whole sweep — and at the exact bottom, at β = 1.00 and nowhere else on the slider, panel C reads 0.000 while the gold arrow in B visibly snaps square against x. Two facts arrive in the same instant, and the honest response is to ask why they should have anything to do with each other. Press ∂ SLOPE for the answer, which is one line of school calculus: Σei² = Σ(yi − βxi, so differentiating term by term gives dΣei²/dβ = −2 Σxi(yi − βxi) = −2(x·e). Read that slowly. The number in panel C is the slope of panel A’s curve, up to a factor of −2. You have not been watching two quantities; you have been watching one quantity in two costumes, which is why the tangent goes flat at precisely the moment C crosses zero — it is the same event, reported twice. Setting a derivative to zero is what Chapter 8 taught you to do to find a minimum; setting a dot product to zero is what Chapter 6 taught you means perpendicular. They are the same equation. That is why the normal equations, X′(y − Xb) = 0, read as a sentence rather than a manipulation: the leftover must be perpendicular to every column you used. Not by luck, not by assumption — by construction, because it is the derivative you set to zero. One last thing, and it is the trap that ruins the picture for most people. Look back at panel A and ask whether those bars are perpendicular to the line. They are plainly not. They are vertical, and they always were — measured straight down the y-axis, because the thing being minimised is error in y, not distance to the line. The perpendicular lives in panel B, in a space whose axes are the three observations, not the two variables. Confusing those two pictures is the single most common way this subject goes wrong, and now you have seen them side by side, moving together, from the same slider.

At the β that minimises the sum of squares, and at no other β, the dot product hits exactly zero.

Confirm it in one line of Chapter 3 calculus. Differentiating gives d/dβ Σ(yᵢ − βxᵢ)² = −2Σxᵢ(yᵢ − βxᵢ) = −2(x·e). So "set the derivative to zero" and "set the dot product to zero" are literally the same equation, and Chapter 18 already told us that a zero dot product means a right angle. The calculus route and the geometry route are one sentence read in two languages.

Solving it gives β̂ = (x·y)/(x·x), which is worth reading rather than memorising. It is how much of y lies along x, measured per unit of x's own squared length.

Now generalise, and notice that generalising costs nothing at all. With k predictors the reachable set is the column space of X, which is a k-dimensional plane. The nearest point on it is the orthogonal projection ŷ = Xβ̂. And perpendicular to the plane means perpendicular to every column, which written out is Xᵀe = 0. Substitute e = y − Xβ̂ and you have the normal equations:

XᵀXβ̂ = Xᵀy, and if XᵀX can be inverted, β̂ = (XᵀX)⁻¹Xᵀy.

Read the normal equations out loud, because that is what they are. The part of y you could not explain has to be perpendicular to everything you used to explain it.

And it has to be, by an argument with almost no algebra in it. Suppose some of the leftover still lay along one of your columns. Step a distance δ along that column and the sum of squares changes by exactly −2δ(x·e) + δ²(x·x). Choose δ = (x·e)/(x·x) and the error falls by (x·e)²/(x·x), which is strictly positive whenever the dot product is not zero. A free improvement was available, so you were not at the minimum.

Spend the leftover along a column — watch the squared error fall, then climb if you overspend
e still leans on both columns spend, and the error falls x₁ x₂ e fit y the target COLUMN x₁ · spend δ₁ x₁·x₁ = 4.0 x₁·e (the leftover) 20.000 −2δ(x·e) 0.0 +δ²(x·x) 0.0 net 0.00 best δ = ? COLUMN x₂ · spend δ₂ x₂·x₂ = 20.0 x₂·e (the leftover) 22.000 −2δ(x·e) 0.0 +δ²(x·x) 0.0 net 0.00 best δ = ? RSS = |e|² 126.00 spend both leftovers to empty it
Drag a slider to spend a step δ along that column. It buys you −2δ(x·e) and it costs you +δ²(x·x). Overspend and the cost wins.
RSS 126.00 · leftover on both
What you're looking at — a plane you cannot leave, and a leftover you can still spend
x1 and x2 are the two columns of X — your predictors. Every fit you can build is δ1x12x2, which is exactly the shaded plane. y floats above it.
e = y − fit, the leftover. Stepping δ along a column changes the squared error by exactly −2δ(x·e) + δ²(x·x) — a saving that grows with δ, a cost that grows with δ².
Best step δ = (x·e)/(x·x), which buys (x·e)²/(x·x) — and there the red cost is exactly half the green saving. Spend both and every leftover dies: XTe = 0, i.e. XTX b = XTy. A surviving leftover would be free money, so the minimum cannot have one.
Fig. 5. Spend a step δ along a column and the squared error changes by exactly −2δ(x·e) + δ²(x·x) — a saving that is linear against a cost that is quadratic. Push past δ = (x·e)/(x·x) and the red term overtakes the green, which is why there is a best step and not an infinite one. Empty both columns and the two dot products read 0.000: the residual is square-on to the plane, X′e = 0, and that single line expands into the normal equations X′X b = X′y.

That is why the apparatus is inevitable rather than conventional. Any leftover still lying along a predictor is unexploited signal, and at the minimum there cannot be any.

Two last things before we start collecting the interest. First, the dimension is not a problem. The three vectors y, ŷ and e span at most a three-dimensional world, whether n is 3 or 3 million, so the picture on the page is not an analogy. It is the actual geometry, seen from the only angle that matters.

Second, and this will organise the entire back half of the chapter, count the probabilistic assumptions we just used. Zero. Not one. The fit is deterministic geometry, and it is available on any data anyone will ever hand you.

04Can you even name the answer?

Here is a question that sounds pedantic and is about to become the most expensive practical issue in the chapter. Does β̂ exist, and is it the only answer?

Separate the two objects the projection quietly produced. ŷ is a point, the nearest point of the plane to y, and a point on a plane is unique however you choose to describe it. β̂ is a coordinate vector, the recipe that says how much of column one and how much of column two. Coordinates need an independent basis.

Make that concrete, because this failure is a rite of passage. Build a design matrix with an intercept, a column that is 1 on up-days, and a column that is 1 on down-days. Those two dummies add up to the ones column, exactly.

CodeRun — this really ran. Drag t: the three β vectors swing, and the eight predictions never move a digit.
$ dummy_trap.py · X = ones | up | down up = np.array([1,0,1,0,1,1,0,0]) X = np.c_[np.ones(8), up, 1-up] matrix_rank(X), det(X.T @ X) [X @ b for b in (bA, bB, bC)] the ŷ plane up down ŷ rank(X) = 2 of 3 columns det(XᵀX) = 0.0 ← singular · β not unique bA = bB = bC = [ [ [ ] ] ] 0.175 0.925 −0.750 1.175 −0.075 −1.750 −1.825 2.925 1.250 ← whatever numpy returns = bA + 1·(1,−1,−1) = bA − 2·(1,−1,−1) X @ bB → X @ bC → 1.100 −0.575 1.100 −0.575 1.100 1.100 −0.575 −0.575 1.100 −0.575 1.100 −0.575 1.100 1.100 −0.575 −0.575 rank(X₂) = 2 of 2 columns det(X₂ᵀX₂) = 16.0 ← invertible · β unique b = [ −0.575 1.675 ] ← honest, and unique no bB, no bC · the free direction is gone same eight numbers · same RSS · nothing moved coefficients · three different answers, all t-shifted X @ b · the eight predicted days, printed not rounded X @ bA → 1.100 −0.575 1.100 −0.575 1.100 1.100 −0.575 −0.575 RSS = 0.847500 max|ŷA − ŷB| = 0.000000 ← identical distinct β printed so far: 3 β is not identified
PREDICT FIRST
t = +0.00 · RSS 0.847500
THE COLUMNS
β swings · ŷ never moves
What you're looking at — one fit wearing three different names. The ones column is up + down, so one coefficient is free to be anything.
rank 2 of 3, det(XᵀX) = 0 — singular. You can add any multiple t of (1,−1,−1) to β and change nothing.
the three β vectors — and the inset route: origin → along ones → along up → along down. Drag t and the route bends.
ŷ — the eight predictions and RSS 0.847500. The gold pin never moves, however wild the coefficients get.
drop one column: β = (−0.575, 1.675), the same ŷ, and now the only answer.
Fig. 6. Eight trading days. Column one is all ones (the intercept), column two is up (a dummy: 1 on an up day, 0 otherwise), column three is down (1 on a down day). Innocent enough — except that every day is either up or down, so up + down = ones, exactly. The third column is already inside the first two, and the code says so out loud: rank 2 of 3, det(XᵀX) = 0 — there is no inverse, so the normal equations have no single solution. Look at what that costs. Three coefficient vectors, wildly different — (0.175, 0.925, −0.750), (1.175, −0.075, −1.750), (−1.825, 2.925, 1.250): one says up days add +0.925, another says they subtract 0.075, a third says +2.925. Multiply each by X and all three print the same eight numbers, 1.100 on every up day and −0.575 on every down day, the same RSS = 0.847500, and a largest disagreement of 0.000000. Now drag t. You are sliding β along (1,−1,−1) — the one direction the columns cannot feel, because X (1,−1,−1) = ones − up − down = 0. The coefficients pour past by the thousand and not one digit of the prediction row twitches. That is the sentence to keep: ŷ is a point; β is a set of coordinates for that point, and coordinates are only meaningful when the basis is independent. The inset draws it honestly — the route from the origin bends and stretches while the gold pin stays nailed. Then press drop “down”: two columns, det = 16, β = (−0.575, 1.675), the identical predictions — and the swing is simply gone, because the free direction no longer exists. The intercept now reads “a down day” and the slope reads “what an up day adds.” That is the whole repair: not better data, just an independent basis. Perfect multicollinearity is this, undisguised; the merely-severe kind in the next figure is this same disease with a small denominator instead of a zero one.

Three completely different coefficient vectors, and every one of them predicts 1.100 on up days and −0.575 on down days, with an identical RSS of 0.8475. The predictions agree to the last bit. Nothing is wrong with the data and nothing is wrong with the fit. The question how much is due to the intercept versus the up-dummy simply has no answer, because you asked for coordinates in a basis that is not a basis.

Now name it with Chapter 6's chain, all of which fires at once. The columns are dependent, so X is rank-deficient, so XᵀX is singular, so it cannot be inverted, so β̂ = (XᵀX)⁻¹Xᵀy has no meaning. The run confirms it flatly: rank 2 out of 3 columns, and det(XᵀX) = 0. Chapter 6 already told us why in one sentence, which is that a collapse destroys information, and destroyed information cannot be recovered.

Two practical notes are worth having now, and the first one costs people real money. Software rarely refuses this fit. It typically reaches for Chapter 7's pseudo-inverse and hands back one of the infinitely many answers, or it silently drops a column, so a coefficient you are reading may be an arbitrary member of a family.

Second, the far more common case in real work is not exact dependence. It is near dependence, where columns are almost but not quite mixes of each other. Then XᵀX is technically invertible and practically dreadful, Chapter 7's condition number blows up, and the inverse amplifies noise ferociously. That is multicollinearity. We now know precisely what it is, and we will come back for it properly once we have error bars to read it with.

05Fitting spends dimensions

Here is a small structural fact that pays for three later ideas, so it earns its own beat. The intercept is not a special object. It is a column of ones.

Write it into X like any other predictor, and "the model has an intercept" becomes "one of my columns is constant". Now run the previous sentence through it. The residual must be perpendicular to every column, so it is perpendicular to the ones column. A dot product with a vector of ones is just a sum, so Σeᵢ = 0, exactly and always, whenever an intercept is included.

That is not a modelling assumption and it is not a coincidence. It is orthogonality to one particular direction. Two consequences fall out of that immediately. The fitted line passes through the point (x̄, ȳ), because the residuals average to zero. And the mean of y is inside the model's reach, which is what makes it legitimate to measure everything relative to ȳ.

Chapter 16 said exactly this once already. Its Bessel argument was that the residual vector is perpendicular to the all-ones direction, for the case where the ones column is the only column.

Now generalise the accounting, because it answers a question that everybody gets wrong. Each column you fit imposes one perpendicularity constraint on the residual. With k independent columns, e is forced perpendicular to k independent directions, so it cannot roam freely in ℝⁿ. It is confined to a subspace of dimension n − k.

Three data points, so the residual lives in a 3-D box. Switch a column on and watch its home lose a dimension: solid → plane → line → a single dot.
n = 3 observations · residual e = (e₁, e₂, e₃) drag the gold dot inside the region e₁ e₂ e₃ RSS = 0 — nothing learned COLUMNS k 1 DIRECTIONS LEFT n−k 2 Σeᵢ 0.00 RSS = e·e 1.42 σ̂² = RSS / (n−k) 1.42 / 2 = 0.71 A PLANE — 2 free directions e ⊥ the ones column, so Σeᵢ = 0: one dimension gone. σ̂² divides RSS by what is LEFT to move in, never by n.
tap a chip ↓
COLUMNS OF X
READ THE SAME PICTURE AS
1 column → a PLANE, 2 left
What you're looking at — a degree of freedom is not a fudge factor. It is a dimension count, and here you can watch them get spent one column at a time.
the columns of X1 (the intercept), x, . Each one you switch on adds the equation e ⊥ that column. The intercept is just a column, which is why the exam's "n−k or n−k−1?" is a non-question.
the region the residual is still allowed to live in. Solid → plane → line: one perpendicularity equation, one dimension. Its size is n−k, and that is the only honest divisor for σ̂². With only the ones column on, the region is Σeᵢ = 0 and n−k is Ch 16's n−1 — one theorem, two names.
k = n: three columns, three points, the parabola passes through all of them. RSS = 0, and σ̂² = 0/0 prints UNDEFINED. A perfect fit with nothing left over is not a good model — it is a model with no room to be wrong.
Fig. 7. Three data points, so a residual has three numbers — one per point — and it lives somewhere in this box. Now switch on the columns of X one at a time and watch what fitting actually costs. Turn on 1, the intercept, and least squares forces e perpendicular to it: Σeᵢ = 0. That is one equation, and one equation kills one dimension — the residual can no longer be anywhere in the box, only on a flat plane through the middle of it. Drag the gold dot: it slides freely on that plane and refuses to leave. Add x and a second perpendicularity clamps down; the plane is sliced to a line. Add and there is nowhere left: the residual is pinned to the origin, RSS = 0, a parabola through three points, a flawless fit that learned nothing. So n−k was never a correction factor someone bolted on. It is the number of directions the residual can still move in after the columns have taken theirs, which is exactly why σ̂² = RSS/(n−k) divides by what is left rather than by n — and why at k = n it prints UNDEFINED instead of zero. Flip to Ch 16's n−1 and nothing on screen moves except the labels: the sample variance you have been using since Chapter 16 is this same picture with exactly one column switched on, the ones column. One theorem. And the exam's favourite trap — n−k or n−k−1? — simply dissolves, because the intercept was never special. It is a column like any other; count the columns and you have your answer.

That is what degrees of freedom means. Not a fudge factor. A dimension count. And it is why the honest noise estimate is σ̂² = RSS/(n−k) rather than RSS/n. Chapter 16 proved the one-column case and openly owed us the rest, and this is the rest, the same theorem with more columns. A quick check makes the size of the correction concrete: over 200,000 samples of five draws from a standard Normal, dividing by n−1 gives a mean of 0.9985 against a truth of 1.0, while dividing by n gives 0.7988.

The tedious exam question dissolves too. Is it n−k or n−k−1? Count columns, and the intercept is a column.

Now watch the extreme, because it will matter enormously later. With three observations and one column the residual lives in a plane. Add a second column and it is confined to a line. Add a third and it is pinned to the origin. Fit as many columns as you have observations and the residual is forced to zero, the fit is perfect, σ̂² is 0/0, and you have learned precisely nothing. Hold that picture, because it is the geometry of overfitting and we meet it twice more.

06R² is a squared cosine

Now collect the interest, because the most quoted number in applied statistics falls out with no work at all.

Centre everything about ȳ, which is legitimate because we just showed the mean lives inside the model. You now hold three vectors: the centred target y − ȳ1, the centred fit ŷ − ȳ1, and the residual e. The residual is perpendicular to everything in the column space, which includes both the fit and the ones column, so it is perpendicular to the centred fit.

So those three vectors form a right-angled triangle, with the centred target as the hypotenuse.

The right triangle nobody draws — five beats from centring to R² = cos²θ
BEAT 1/5 beat the five points and the fitted line   tap a beat dot · or press next ▶ BEAT 1 · centre it, legally       y − ȳ1 = (ŷ − ȳ1) + e       TSS ESS RSS 14.800 12.100 2.700  
Five beats. Each one changes one line — and the triangle follows it.
centring is legal: 1 ∈ col(X)
What you're looking at — one right triangle, and every famous regression formula falls out of it
Gold, the hypotenuse = the centred target y − ȳ1 (each y minus the mean 4.200). Its squared length is TSS = 14.800, the total variation you set out to explain.
Blue, the base = the centred fit ŷ − ȳ1, squared length ESS = 12.100 — the part the x-column could reach.
Cyan, the upright = the residual e, squared length RSS = 2.700. It is perpendicular by construction (that is what the normal equations say), so the cross term is 2×0 and Pythagoras applies: 14.800 = 12.100 + 2.700. Divide by TSS and R² = cos²θ = 0.8176 — Ch18's ρ = 0.9042, now aimed at a subspace instead of a line. ρ is the cosine; the share is its SQUARE, which is why ρ = 0.7 buys 49%, not 70%.
Red = broken. Hit NO INTERCEPT: without the ones column ȳ1 is no longer something the model can build, the angle stops being 90°, and the three definitions of R² that always agreed — ESS/TSS, 1−RSS/TSS, cos²θ — give three different numbers, one of them above 1. On other data 1−RSS/TSS goes negative. R² is only a “share” while the triangle is right-angled.
Fig. 8. Nobody draws the triangle, so “the cross term vanishes” sounds like a lucky cancellation. It isn't. Step the five beats: centring is legal because the ones column can build ȳ1; the residual dots to exactly zero against the fit because that is the normal equation; so the decomposition is Pythagoras and R² is a squared cosine. Then pay the toll — guess what ρ = 0.7 explains before you look — and flip NO INTERCEPT to watch the whole thing stop being true.

Pythagoras, and nothing else: ‖y − ȳ1‖² = ‖ŷ − ȳ1‖² + ‖e‖². Those three squared lengths have names. TSS, ESS and RSS, the total, explained and residual sums of squares. On the five-point example the numbers read 14.800 = 12.100 + 2.700, and the cross-term that textbooks make vanish through half a page of algebra is a dot product between perpendicular vectors, which computes to 0.0 exactly. That is the whole proof.

Now define R² = ESS/TSS, the fraction of the squared length the plane accounted for, and read what it actually is. In a right triangle, the ratio of the adjacent leg squared to the hypotenuse squared is cos²θ, where θ is the angle between the centred target and the column space.

R² is a squared cosine. And now Chapter 18's keystone comes back with interest. There, ρ was the cosine of the angle between two centred data vectors. Here is the cosine squared of the angle between one centred data vector and an entire subspace. With a single predictor those are the same angle, so R² = ρ² exactly. On the five-point example, ρ = 0.9042 and R² = 0.8176, and 0.9042 squared is 0.8176.

Which makes a very cheap and very useful test possible. A stock has a correlation of 0.7 with the index. What fraction of its variance does the index account for? The instinct says 70%. The answer is 49%, because R² is a cosine squared, and the missing 51% is the length of the perpendicular leg you were not picturing.

One honesty note to carry. All of this assumed the model contains an intercept, which is what puts ȳ inside the column space. Drop the intercept and the decomposition no longer holds, which is why a regression without one can report a negative R² and surprise everybody.

07What R² is not

Having built R² honestly, spend one section dismantling what people do with it. Notice as we go that every criticism below is geometry, not statistics.

Start with the criticism that matters most, and it takes one sentence. Add a column to X and the column space gets bigger. The old fit is still available inside that new, larger space, because you can always set the new coefficient to zero. So the nearest point of the bigger plane cannot be further from y than the nearest point of the smaller one.

Which means RSS cannot rise and cannot fall. Ever. For any column, including a column of numbers you generated with a random number generator this morning.

CodeRun — this really ran. Sixty days of returns, fifty-nine columns of pure noise. Drag k and watch R² buy what it never earned.
$ python noise_ladder.py n, y = 60, stock_returns E = rng.normal(size=(60,59)) # 59 columns of pure noise X = np.c_[ones(60), E[:,:k]] b = lstsq(X, y)[0] r = y - X @ b R2 = 1 - r@r/tss adj = 1 - (1-R2)*59/(59-k) stdout · nothing broke k adj R² RSS 0 0.0000 0.0000 78.0432 2 0.0505 0.0172 74.1020 5 0.0911 0.0069 70.9335 10 0.2090 0.0476 61.7322 20 0.3450 0.0091 51.1183 40 0.7646 0.2690 18.3714 50 0.9284 0.5308 5.5863 59 1.0000 0/0 1.3e−31 live at k = 0 noise columns 0.0000 adj R² 0.0000 FREEDOM 59 rows free gap never grows y span X gap = 1.0000
PREDICT FIRST
k = 0 · n−k−1 = 59
RSS = 78.0432
residual sum of squares
k = 0 · nothing fitted yet
What you're looking at — the same sixty returns, refitted on more and more columns of nothing.
— the share of the spread the fit captured. It never falls: 0.0000 → 0.3450 → 0.9284 → 1.0000, bought entirely with noise.
adjusted R² — the same ratio charged rent for each column, 1 − (1−R²)·59/(59−k). It holds near zero… then it starts climbing too.
the inset: span X is everything the columns can reach. Add a column and that space only grows, so the dashed gap to y can only shrink. That is the whole proof.
the FREEDOM strip is n − k − 1, the rows left over after the columns take theirs. At k = 59 it is 0, and adjusted R² divides by it.
Fig. 9. Sixty trading days of one stock's returns — and then fifty-nine columns of pure random noise, drawn once from a generator that has never heard of the stock. Column by column we hand them to least squares and let it do the only thing it knows: drop y onto the space the columns can reach. Read the ladder. — the fraction of the returns' spread the fit accounts for — goes 0.0000, 0.0505, 0.0911, 0.2090, 0.3450, 0.7646, 0.9284, and with fifty-nine noise columns beside the intercept it reads 1.0000 with RSS = 1.3e−31 — zero wearing floating-point clothes. Sixty numbers explained perfectly by nothing at all, and not one warning printed. The reason is one sentence long, and the inset draws it: span X is the set of vectors your columns can build, the projection is the point of that set closest to y, and adding a column makes the set bigger. A bigger set cannot have a further nearest point — the old fit is still sitting inside it, available. So the dashed gap can only shrink, and R² = 1 − gap² can only rise. The climb is arithmetic, not evidence. Which is why R² can never choose a model for you. Adjusted R² is the honest attempt: the same ratio, charged rent for every column you spend — 1 − (1 − R²) · 59/(59 − k), where 59 − k is n − k − 1, the rows of freedom left after the columns take theirs. Watch it work: at k = 20 raw R² boasts 0.3450 while adjusted reads 0.0091 — correctly, nothing. Then watch it fail: at k = 50 it still reads 0.5308, because the rent is a fixed multiplier and the denominator is nearly spent. Drag the strip down past ten free rows and it turns red for a reason. Adjusted R² is rent, not a defence; the actual defence — testing the fit on data it has never seen — is Chapter 21.

Sixty days of returns, and columns of pure noise added one batch at a time. One noise column reads 0.0505. Five read 0.0911. Twenty read 0.3450. Fifty read 0.9284. And fifty-nine noise columns beside the intercept read 1.0000, with the residual crushed to 1.3e−31, which is zero wearing floating-point clothes.

Nothing broke here. The geometry is behaving exactly as specified, and what you are watching is the collapse we drew when the residual ran out of room to move.

That is precisely why an unadjusted in-sample R² cannot compare models of different sizes, and it is why adjusted R² exists. Adjusted R² is not a fudge factor. It is the same ratio recomputed with the honest degrees of freedom: 1 − (RSS/(n−k))/(TSS/(n−1)). A column now has to earn more than the dimension it costs, and if it does not, the number falls.

Watch it work and then watch it fail, because both are honest. At twenty noise columns, R² reads 0.3450 while adjusted R² reads 0.0091, which is the rent doing its job. At fifty noise columns on sixty rows, adjusted R² still reads 0.5308 on pure noise. With nine degrees of freedom left there is nothing honest to compare against, so treat adjusted R² as rent charged, never as a defence.

The rest of the list is one sentence each. R² says nothing about causality, and Chapter 18's four explanations are all still live. It says nothing about whether the functional form is right. It says nothing about out-of-sample performance, which is Chapter 21's entire subject.

And it says nothing about economic size, which is where finance readers most need recalibrating. A regression of daily stock returns on any honest signal produces an R² of about 0.01, and practitioners routinely read that as failure. It is not. It is the correct order of magnitude for a market that is mostly unpredictable. A signal with an information coefficient near 0.05, which is an R² of 0.0025, applied across a thousand names and rebalanced for years, is a serious business. The money is not in explaining the variance. It is in the small predictable part, repeated.

08The line: geometry above, inference below

Stop and draw a line across the page, because everything changes here and almost nobody says so.

Look back at what we have built. A projection, a residual, degrees of freedom, R². Now count the probability in it. There is none. Not one distribution, not one expectation, not one random variable. Everything so far is linear algebra performed on a table of numbers. It is always computable, it never fails, and it means exactly one thing, which is that ŷ is the closest point reachable from your columns.

If all you want is to fit a curve through data you already hold, you can stop reading. The chapter is over and it needed nothing.

But nobody stops there. You want to say your hedge ratio is 0.83, that a plausible range for it is 0.83 ± 0.06, and that the value coefficient is significant. Every one of those sentences is a claim about a truth you never see, a number the world would have if you could sample forever. To reach it you must first assert that such a truth exists and describe how your data came from it. That is what an assumption is for.

So write the model of the world: y = Xβ + ε, where β is a fixed unknown vector, which is Chapter 16's estimand, and ε is an unobservable random shock, one per observation.

And now mark the most expensive notation collision in this subject, loudly, because it is the reason one assumption gets misread as trivially true. The residual e is what your fit left over. You can compute it, plot it, and it is orthogonal to your columns by construction, always, on any data, even if the model is nonsense. The error ε is what the world added. You can never observe it, and whether it is orthogonal to X is a claim about reality. Same word in casual speech, two different objects, and every assumption below is about ε.

With that separation in hand, β̂ becomes what Chapter 16 trained us to see. It is a function of a random sample, therefore a random variable, therefore one dot in a sampling distribution.

Now the assumptions. The move that makes this chapter usable is refusing to list them flat.

Draw the line: arithmetic above it costs nothing — every claim below it costs an assumption
ABOVE THE LINE ASSUMPTIONS USED SO FAR: 0 ŷ = Xb e = y − ŷ df = n − k R² = 1 − SSE/SST all computable today BELOW THE LINE ASSUMPTIONS USED SO FAR: 5 y = Xβ + ε β — a fixed unknown number you aim at ε — one invisible shock per row e — the RESIDUAL you compute X′e = 0 BY CONSTRUCTION true even if the model is nonsense ε — the ERROR you never see X′ε = 0 is a CLAIM about reality and that claim is called A2 above the line: 0 assumptions. below: every claim costs one. what it buys → EXISTS UNBIASED SE CORRECT t EXACT BREAK IT A0 full rank · · · A1 linearity · · · A2 exogeneity · · · A3 equal spread · · A4 independence · · A5 normal errors · · · read the EXISTS column read the UNBIASED column read the SE CORRECT column read the t EXACT column read A0 read A1 read A2 read A3 read A4 read A5 break A0 break A1 break A2 break A3 break A4 break A5
tap a row · flip BREAK IT
how to read this tableTap a row to read one assumption. Tap a column button to see all that protect one claim. Flip BREAK IT.
all 4 guarantees still hold
What you're looking at — one tier table, read down a row and read down a column
Above the line is arithmetic on numbers you already have: the projection ŷ = Xb, the residual e, the degrees of freedom, R². The counter there stays at 0 — not one assumption was spent to get any of them.
Below the line is the model y = Xβ + ε. β is a fixed unknown you will never see; ε is one invisible shock per row. e is not ε: X′e = 0 always, by construction, even on nonsense — X′ε = 0 is a claim about reality, and that claim is A2.
A tick means "this assumption protects this claim". Flip BREAK IT and watch which columns die: A3 or A4 kills SE CORRECT and t EXACT and leaves the coefficient columns untouched. The assumptions were never preconditions for the arithmetic — they are admission money, and each one buys a different claim.
Fig. 10. Everything above the line — the projection ŷ = Xb, the residual e, the degrees of freedom, R² — is arithmetic on numbers you already hold, and the counter there never leaves 0. The assumptions live below the line, where β is a fixed unknown you will never see and ε is a shock you can never observe. That is why e is not ε: X′e = 0 holds by construction on any data at all, even nonsense, while X′ε = 0 is a claim about the world. Read the table down a row to see what one assumption buys; read it down a column to see everything guarding one claim — and note that UNBIASED lights only A1 and A2, because A1 says the target exists and A2 says you hit it. Then break a row: A3 or A4 kills SE CORRECT and t EXACT and leaves the coefficient columns standing. The assumptions were never preconditions for the arithmetic. They are admission money, and only the two you cannot diagnose protect the number itself.

Sort them by what each one buys. A0, no perfect collinearity, buys existence and uniqueness of β̂, and that is a fact about your matrix rather than about the world. A1, linearity in the parameters, buys that the truth is reachable at all. Note that it does not forbid curves, because , log x and interactions are all perfectly legal columns. What is forbidden is β entering non-linearly.

A2, exogeneity, written E[ε|X] = 0, buys unbiasedness, meaning E[β̂] = β. A3, homoscedasticity, and A4, no autocorrelation, buy the correctness of the standard-error formula, and together with A1 and A2 they buy Gauss–Markov, that OLS is the best linear unbiased estimator. A5, normal errors or a large sample and the CLT, buys that the t-statistic really follows a t-distribution, so the p-value is exact.

Now read down the unbiasedness column, because this is the sentence to carry out of the chapter. Two assumptions sit there, and they do different jobs. A1 says the target exists. A2 says your estimate is aimed at it. Every other assumption on the table sits in an error-bar column.

So of the things people actually diagnose after a fit, exactly one protects the coefficient. Everything in the rest of this chapter is a consequence of that single asymmetry.

09The error bar, and the lever arm

Now build the error bar, and refuse to leave it as a matrix formula.

Under A0 to A4, the covariance matrix of the estimate is Var(β̂) = σ²(XᵀX)⁻¹. That is one object holding every coefficient's variance on its diagonal and every pair's covariance off it. As written, it teaches nothing. So collapse it to one predictor and read it as a sentence:

SE(β̂) = σ_e / (σ_x √n)

Three levers, each with a physical meaning. Noisier residuals mean a worse-measured slope, which is obvious. More data shrinks the error like 1/√n, which is Chapter 16's law arriving unchanged. And then the one people never internalise: a bigger σ_x, more spread in the predictor, improves the estimate.

Same 500 days, same noise — now squeeze the predictor's spread. Predict what happens to the error bar before you drag.
−3% +3% σe σx = 1.00% ← the lever arm x = the market's daily move arm = σx = 1.00% wobble = σe/√n = 0.054 swing = wobble ÷ arm = 0.0537 same wobble, shorter arm → wider swing same days, same noise spread is the only change the three levers SE = σe ÷ ( σx × √n ) 0.0537 standard error of the slope 95% half-width ±0.105 your hedge ratio, honestly 1.40 ± 0.105 the baseline setting
σx spread1.00%
← drag this one first (the SQUEEZE)
σe noise1.20%
n days500
baseline · SE = 0.0537
What you're looking at — the slope's error bar, built from three levers: SE(β̂) = σe / (σx √n).
the days. Each dot is one day: the market's move x against the stock's move y. More days (n) → more dots → a tighter fan, exactly as you'd expect.
σe, the residual noise — the vertical scatter the line can't explain. More noise, wider fan. Also as expected.
σx, the spread — how far the predictor itself moves. This is the lever arm. Squeeze it 1.00% → 0.40% with the same 500 days and the same noise and the error bar goes 0.0537 → 0.1342: exactly 2.5× wider.
the fan — every slope the data can't rule out (±1.96 SE). In the LEVER view the vertical wobble is σe/√n — identical at both ends whatever the spread; only the arm changes, and the angle is wobble ÷ arm. (The wobble is drawn magnified, or you'd never see it.) That is why (X′X)⁻¹ punishes a predictor that barely moves.
Fig. 11. The standard error of a slope is three levers in one line: SE(β̂) = σe / (σx √n). Two of them behave exactly as instinct says — more noise widens the error bar, more days narrow it. The third is the one nobody expects. Hold the noise at 1.2% and the sample at 500 days, touch nothing else, and just squeeze the predictor's own spread from 1.00% to 0.40%: the identical data compresses sideways into a huddle and the fan of plausible fitted lines flares from ±0.105 to ±0.263 — the error bar exactly 2.5× wider, because σx fell by a factor of 2.5. Switch to the LEVER view for the reason. The vertical wobble at each end of the baseline is σe/√n and it never changes with the spread; the spread is the arm. Slope uncertainty is wobble ÷ arm — an angle — so halving the arm doubles the swing. That is (X′X)⁻¹ in physical form, and the seed of multicollinearity: two predictors that move together leave the fit reading an angle over a two-inch baseline.

That is the lever arm. If x barely moves across your sample you are measuring a slope over a two-inch baseline, so any wobble in y swings the fitted angle wildly. Spread x out over a long baseline and the same wobble barely tilts it. Put numbers on it. With a daily residual of 1.2%, a predictor spread of 1.0% and 500 days, the standard error is 0.0537, so the hedge ratio reads 1.40 ± 0.11. Squeeze the predictor's spread to 0.4% and change nothing else, and the standard error becomes 0.1342, exactly 2.5 times wider.

Which tells you what (XᵀX)⁻¹ is doing in general. XᵀX is a variance-like summary of your predictors, so its inverse punishes predictors that do not move, and predictors that move together. Hold that second half, because it is the seed of the next problem.

The inference is then Chapter 17 with nothing new whatsoever. The t-statistic for a coefficient is t = (β̂_j − 0)/SE(β̂_j), the same universal template, and the null value is usually zero because the natural question is whether this predictor does anything at all. Compare it against a t-distribution on n − k degrees of freedom, which is the same n − k we counted as a dimension, so Chapter 17's mysterious parameter is now something you can point at.

There is a joint version worth naming too. The F-test asks whether the columns together explain more than nothing, which is a question about the whole subspace rather than any one coordinate. It becomes important the moment individual coefficients start disagreeing with the group.

And now the sting, which is the bridge we walked in on turning round and biting.

One regression call, twelve simultaneous tests — and nothing on the printout says so
OLS output · all true β = 0 ★ 0 pred t p pred t p specs tried 1 · honest m = 12 one spec — the printout is honest 0 0.5 1.0 1 10 20 k = predictors 50% 1−0.95k seen honest m measured meets theory noise alone did that chance of ≥1 star, k=12 46.0% re-runs that starred 0 / 1 = 0%
12 rows, 12 tests. Every true effect below is exactly 0.
k=12 · FWER 46.0% · seen 0%
What you're looking at — a printout where nothing is real, and the stars appear anyway
Every t and p is drawn from a model where all 20 true coefficients are exactly 0. There is nothing to find.
A is |t| > 1.96 — what the printout calls "significant at 5%". Click any row to "report" it.
1−0.95k, the family-wise error rate: the chance at least one star shows up. At k = 12 it is 46.0%.
The fraction of your own re-draws that produced a star — press run ×50 and watch it land on the gold curve.
Fig. 12. Twelve predictors is twelve simultaneous tests: with every true β set to zero, a star still shows up 46% of the time — and re-running with a different column subset quietly doubles and trebles the honest test count while the printout keeps saying twelve.

A regression printout with twelve predictors displays twelve t-statistics and twelve p-values, and everybody reads them one at a time, hunting stars. That is Chapter 19's crime committed inside a single function call. Twelve tests at 5% carry a 46.0% chance of at least one false star even if every coefficient is truly zero. The regression table is a multiple-testing machine, and running it fifty times with different column combinations is the garden of forking paths with a nicer interface.

10What a coefficient actually means

Before we can talk about what goes wrong, we have to say precisely what a coefficient means in a multiple regression. The standard phrase is that it gives the effect of x_j holding the other variables constant, and that phrase is a spell rather than a mechanism.

Nothing was held constant, because your data was observed rather than controlled. The market and the sector ETF moved together on every single day of the sample, and nobody froze either of them.

So what does the software actually do? Three things, in order. It strips x_j of everything the other columns can explain, then strips y of everything the other columns can explain, then regresses the first leftover on the second.

That is the whole meaning of controlling for something, and the astonishing part is that it is exactly, numerically true.

CodeRun — 400 rows, four real regressions. Press RUN, then drag the STRIP dial and watch “holding the others constant” actually happen.
$ python fwl.py # n = 400 rows y = 1.5x1 - 0.8x2 + 2.0x3 + noise b = lstsq(np.c_[1,x1,x2,x3], y)[0] b[1] = the coefficient on x1 # SUBTRACT what x2,x3 explain: Z = np.c_[1, x2, x3] r1 = x1 - Z @ lstsq(Z,x1)[0] ry = y - Z @ lstsq(Z, y)[0] full fit b[1] -------------- slope r1 → ry -------------- difference - y x1 — raw column STRIP 0% SLOPE of y on x1 1.920914 raw pairwise slope SPREAD of x1 left 0.9309 of 0.9309 VIF 1.00 100% left PRESS RUN ▶ predict first: will two regressions on leftovers give b[1]?
STRIP SHARED PART0%
drag → to subtract
THE DATAtap
Predict before RUN: the raw pairwise slope of y on x1 is 1.9209. Will two regressions on leftovers give b[1]?
press RUN — 4 real regressions
What you’re looking at — “holding x2 and x3 constant” is not a freeze. It is a subtraction, and you can watch it happen.
the raw cloud at STRIP 0% — plain x1 against plain y, slope 1.9209. A different question’s answer.
the leftover — what x2 and x3 could not explain. Its spread shrinks 0.9309 → 0.6587.
b[1] = 1.483528484235, printed twice by two different programs. Difference: −1.55e−15.
x2 = COPY: the equality still holds — but only 6.5% of x1 is left to divide by. VIF 235.
Fig. 13. Everyone is told that a regression coefficient is the effect of x₁ “holding the other variables constant”, and almost everyone pictures a laboratory: x₂ and x₃ pinned in place while x₁ is nudged. Nothing is pinned. Four hundred rows sit here with y = 1.5x₁ − 0.8x₂ + 2.0x₃ + noise and predictors that are deliberately entangled, and the machine does something quite different. Press RUN and it performs four honest regressions in front of you. The first is the ordinary four-column fit; its coefficient on x₁ is 1.483528484235. The next two throw x₁ away entirely: regress x₁ on the other columns and keep only the residual r₁ — the part of x₁ that x₂ and x₃ cannot account for — then do the identical thing to y and keep r⃰. The fourth regression is a single-variable fit of one leftover on the other, and it prints 1.483528484235. The difference between the two is −1.55e−15: not “close”, not “approximately” — the last bit of a double-precision float, which is the arithmetic saying same number. That is the Frisch–Waugh–Lovell theorem, and you did not take it on trust; you watched it happen. Now drag the dial and watch what “holding constant” physically is. At 0% you see raw x₁ against raw y, and the line through that cloud has slope 1.9209 — a perfectly honest number, and the answer to a different question, because raw x₁ still carries x₂ and x₃ inside it. As the dial runs, the shared component drains out of both columns at once, the cloud collapses along the horizontal, and the printed slope walks — 1.9209, 1.7983, 1.6583, 1.5349 — continuously down to 1.4835. There is no moment where anything is frozen. Three payoffs fall out of this one picture. First, a coefficient is the price of the part of x₁ that nothing else explains: the spread you are actually paying per unit of shrinks from 0.9309 to 0.6587, so half of x₁'s variation was never x₁'s to sell. Second, the pairwise slope is not a worse estimate of the same thing — it answers “when x₁ is high, what is y?”, while the coefficient answers “when x₁ is high for reasons x₂ and x₃ do not share, what is y?”. Third, and this is the part that pays your rent later: the size of the leftover is the whole diagnosis. Switch the data to x₂ = COPY, where x₂ is 98% a duplicate of x₁. The theorem does not budge — both programs still agree to twelve decimals — but only 6.5% of x₁ survives the subtraction, the variance inflation factor goes from 2 to 235, and b[1] comes back as 1.9573 when the truth that generated the data was 1.5. A coefficient is a ratio, and you are now dividing by a stub. That is exactly why multicollinearity makes individual coefficients wild while R² barely notices, and exactly why a standard error is a statement about how much unique variation a column had left. (Everything on the screen is computed live from the same 400 rows — the LCG seed is fixed, so the numbers reproduce. Standard errors and t-statistics on these coefficients: Ch. 16–17. Whether the fit survives data it has never seen: Ch. 21. Shrinking wild coefficients on purpose rather than by accident — ridge and lasso: Ch. 22.)

The full three-predictor regression gives β̂₁ = 1.484167662730. The two residual regressions, run separately and then combined, give a slope of 1.484167662730. The difference is 1.55e−15, which is the floating-point noise floor and nothing else. It has a name, Frisch–Waugh–Lovell, and you should watch it happen rather than take it on faith.

Nothing was frozen. Something was SUBTRACTED.

Read what that means and three separate mysteries dissolve at once. First, β_j is the price of the part of x_j that no other column could account for. In this run the predictor has a standard deviation of 0.951, and after the other columns take their share the leftover has a standard deviation of 0.676. Only that leftover identifies the coefficient.

Second, a coefficient can flip sign when you add a column, and that is not a bug and not a betrayal. Regressing y on this predictor alone gives 1.8838, while the partial coefficient is 1.4842. The leftover is a different vector from the original column, so of course its slope against y is a different number. A raw correlation and a partial coefficient are answers to different questions.

Third, this one picture already tells you how regression fails, in both directions. If the other columns explain nearly all of x_j, the leftover is a tiny noisy stub, and you are estimating a slope on almost no variation, so the standard error explodes. And if something that matters was never put into X, it never got subtracted, so it is still sitting inside the leftover, contaminating the slope.

One picture, both diseases. We take them in that order, worst first.

11The only fatal violation

This is the violation that poisons the number itself, and it deserves to be met first because everything else is comparatively cosmetic.

Exogeneity says that knowing your predictors tells you nothing about the shock. Break it and β̂ is no longer an estimate of β. It becomes a precise estimate of a different quantity.

Run it with a generator you own, so the truth is not in doubt. Build data where y = 1.0·x + 2.0·z + noise, and let x and z be correlated at 0.6. Now fit y on x alone, because z is something you did not measure. An unobserved regime, a liquidity factor, a fund flow.

Predict before you look. What will the coefficient on x be? Almost everyone says about 1, a bit noisy.

Confidently, precisely, wrong — commit a guess, then run the fit at 1,000, 10,000 and 100,000 rows
left: the truth YOU wrote · right: what OLS reports back # the world — you wrote it z = N(0,1) # NEVER measured x = 0.6*z + 0.8*e # corr .6 y = 1.0*x + 2.0*z + noise # the fit you can run ols(y ~ x) # no z column THE ARITHMETIC 1 + 2×0.6 = 2.2 ← the fit x carries z. Nothing removes it. $ python ovb.py n coef SE t ? seal a guess to run it 1,000 2.0926 0.0609 34.4 ◀1.00 10,000 2.2228 0.0190 116.9 100,000 2.2041 0.0060 367.4 1k +z 0.9611 0.0395 24.3 truth: b1 = 1.0000 (unknowable) WHERE THE ESTIMATE IS AIMED   truth 1.00 2.0926 1.0 1.5 2.0 2.5 miss 1.09 ERROR, SPLIT IN TWO n=1,000 SE ×1.00 bias ×1.00
Most people guess 1.0 — the number in the source. Commit yours first.
seal a guess, then run it
What you're looking at — an estimate that gets sharper and sharper about the wrong number
Blue = the truth, b₁ = 1.0. You wrote it yourself in line 4, so there is no doubt about it — and no way to see it from the data.
Red = z, the column you never measured, and the miss it causes. Because x is built from z (corr 0.6), x carries z's effect into the fit and nothing subtracts it: 1 + 2×0.6 = 2.2. That is the whole bias.
Green = SE, the precision. Ten times the data cuts it 3.2× (that is 1/√n), and a hundred times cuts it again — t climbs 34 → 117 → 367. Only this half shrinks.
Gold = the estimate, and your sealed guess (the pin ◀ and the rail marker). Endogeneity is a different species from noise: the estimate isn't wobbly, it is aimed at the wrong number. Put z back in X and it snaps to 0.9611 — one row of code, and the bias is gone.
Fig. 14. You wrote the truth yourself — 1.0 on x — so when the fit comes back 2.0926, the only question is where the extra came from. Commit a guess on the rail, then seal it and push MORE DATA: the standard error collapses 0.0609 → 0.0190 → 0.0060 and t climbs to 367, while the distance from the truth sits there at 1.1 and will not move. That is the arithmetic 1 + 2×0.6 = 2.2, exactly the leftover picture — x inherits z's effect and, with no z column, nothing ever subtracts it. Sampling noise is cured by more rows; bias is not a small-sample problem, it is the wrong target. Add z back and the number snaps to 0.9611.

The answer is 2.0926, with a standard error of 0.0609 and a t-statistic of 34.4. Not noisy. Not uncertain. That estimate is confidently, precisely and beautifully wrong.

And here is the sentence that makes endogeneity a different species from every other problem in this chapter. Bias does not shrink with n. Variance does, and that is the whole content of 1/√n. Bias does not. Collect ten times the data and the estimate goes to 2.2228 with a standard error of 0.0190 and a t-statistic of 116.9. Push to a hundred thousand rows and the t reaches 367. More data makes an endogenous estimate more confidently wrong.

Where did 2.2 come from? The leftover picture already told us. The coefficient is a slope on the part of x that the other columns did not account for, and z was never a column, so it was never subtracted. The arithmetic is β̂₁ → β₁ + β₂·δ, where δ is the slope of z on x. That is the omitted effect times how well x stands in for it: 1.0 + 2.0 × 0.6 = 2.2. Chapter 18's confounder, drawn as two arrows pulled toward a third, now has a number on it. Put z back into the regression and the coefficient snaps to 0.9611 with z's own coefficient at 2.0001.

Endogeneity is not only omission, and it wears several coats in finance. Simultaneity: you regress your returns on order flow, but your own trading moved the price, so the arrow runs both ways. Measurement error in a regressor: noise in x pulls its coefficient toward zero, which is called attenuation, and the honest reading is that you measured a proxy's slope rather than the thing's. Selection: you regressed on the funds that survived.

There is a trap in the opposite direction too, and it needs saying because the instinct is so strong. Faced with omitted-variable bias, everyone concludes control for everything. That is wrong in a specific way. Conditioning on a variable that is caused by x, which is a mediator, subtracts part of the very effect you are trying to measure. Conditioning on a collider, something that both x and y influence, manufactures a correlation that was never there. Adding columns is not automatically safer, and it is a modelling claim like any other.

Finally the verdict, and it is why this violation comes first. None of the repairs in the rest of this chapter touch it. Robust standard errors, HAC standard errors, a bootstrap: every one of them is a better description of the spread of a wrong number. Only a better model, a natural experiment, or an instrument helps.

12Stable plane, unstable coordinates

Now the violation everyone has heard of and almost nobody can state precisely. Multicollinearity is near-dependence among the columns, which is the case we named and deferred.

Ask the diagnostic question the tier table trained us to ask, which is the only one that decides what you do next. What does it damage?

Slide the correlation between two predictors from 0 up toward 0.99, with the true coefficients both fixed at 1.0, and watch what moves.

Two predictors, both true coefficients exactly 1.0. One dial — and four panels that flatly refuse to agree.
1 · COEFFICIENTS b₁+b₂ = 2 r = −0.87 SE(b₁) 0.178 SE(b₁+b₂) 0.080 2 · THE FIT b=(1.52, 0.67) preds differ ≤0.78 R² fit 0.8083 R² wild 0.7939 3 · RSS CANYON drag ▸ 4.4× · same cost marble +0.0% 4 · VIF = the overlap R²(x₂ from x₁) = 0.8100 VIF = 1/(1−0.8100) = 5.26 SE × √5.26 = 2.29 wider 1 VIF 10 60 GOAL — PREDICT Do nothing. The fit is fine. drop one combine ridge Ch22 new data ◆ Same plane, new names.

Both slopes really are 1.0. Only how much x₁ and x₂ overlap changes.

at ρ = 0.99, R² will…
▸ drag the blue marble, panel 3
guess first — then drag the dial
What you’re looking at — the plane never moves; only the names for it come loose
blue = the pair (b₁,b₂), the coordinates. 1,000 bootstrap refits; the cloud stretches into a streak.
gold = the sum b₁+b₂ and the fit itself. Its spread and R² barely twitch.
violet = one wild pair from the cloud’s far end: absurd coefficients, near-identical predictions.
red = the cost of crossing the sum. Both bars in panel 3 cost the same 10% of RSS — the blue one is 14× longer.
Fig. 15. Multicollinearity, exactly. Slide ρ from 0.90 to 0.99: R² moves 0.8083→0.8154 and the predictions hold, while SE(b₁) triples and the cloud collapses onto the line b₁+b₂ = 2. The projection is stable; the coordinates are not.

Between ρ = 0.90 and ρ = 0.99, goes from 0.8083 to 0.8116. The predictions barely move. Meanwhile the standard error on each coefficient goes from 0.178 to 0.544, and bootstrapped across resamples the cloud of (β̂₁, β̂₂) pairs stretches into a long thin diagonal streak that runs from −0.91 to 2.52 on one axis.

Now look at what is pinned and what is free. The bootstrap spread of the sum of the two coefficients is 0.070 at ρ = 0.90, and 0.070 at ρ = 0.99. Identical. The spread of each one alone triples over the same move, and their correlation across resamples reaches −0.992.

That is the entire disease in one sentence. A stable projection with unstable coordinates. It is the dummy trap with the word "nearly" inserted. The plane is fine and the point on it is fine, but the two columns naming it point in nearly the same direction, so many different recipes reach nearly the same place.

Chapter 8 gives the same fact as a landscape. The RSS surface, which for independent columns is a clean bowl, becomes a long flat canyon running along the direction where the two coefficients trade off. A canyon floor is exactly where small changes in the data slide you a long way. Chapter 7 gives it as a number: XᵀX is ill-conditioned, the condition number is huge, and inverting it magnifies noise.

Now measure it, using something you already own. The coefficient is priced on the leftover of x_j after the other columns are subtracted. If the other columns explain most of x_j, that leftover is a stub. How much of x_j do they explain? That is an , the R² of regressing predictor j on all the other predictors.

Call it R²_j, and the variance inflation factor is VIF_j = 1/(1 − R²_j), the factor by which the coefficient's variance is multiplied. So R²_j = 0.9 gives a VIF of 10 and a standard error 3.16 times larger. VIF is not a new formula. It is R² pointed sideways at your own design matrix.

Recognise the signature in the wild, because it looks like a contradiction and is not. A strongly significant joint F-test, a high R², and not one individually significant t-statistic. Together the columns explain plenty. Individually no single one can be credited, because each one's unique contribution is a stub.

And notice that multicollinearity is not a violation of A1 to A4 at all. β̂ remains unbiased and still best linear unbiased. The data is simply mute about the split. So sort the fixes by what you actually want out of the model. If you only want to predict, then do nothing at all, because the projection was never harmed. If you must attribute, get data where the columns separate, or combine them into one factor with PCA in Chapter 24, or drop one on economic grounds and say so out loud. Or accept a little bias to buy a lot of stability, which is ridge regression in Chapter 22, and geometrically it is the operation that rounds the canyon floor back into a bowl.

13Two liars about the error bar

Two violations left, and the tier table tells us in advance what to expect from both. They sit in the standard-error row, so the coefficient survives and only the error bar lies. That is genuinely good news and genuinely dangerous news, because a wrong error bar is invisible.

First, heteroscedasticity. The spread of the errors depends on X. The picture is a fan, which you get by plotting the residuals against the fitted values and watching the cloud widen as you move right. In finance this is not an exotic failure. It is the default, because Chapter 18's leverage effect and volatility clustering mean the scale of returns changes through time.

Wind the FAN up and the noise starts growing with x. Watch what happens: the estimate barely moves, but the error bar underneath it quietly turns into fiction.
① THE DATA + THE FIT ② RESIDUAL vs FITTED ③ THE MEAT Ω β̂ = 0.955 x → σ span ×1.0 area = e² ④ THE 95% ERROR BAR ON β̂ β = 1, the truth CLASSICAL 0.0484 ROBUST 0.0502 TRUTH·400 0.0490 robust still short 0.8 0.9 1.0 1.1 1.2 t = β̂ / SE classical 19.72 robust 19.03 too big by ×1.04
① THE FANdrag →
σ(x) ∝ x^0.00 · flat
② PARK ITtap one
③ THE DAMAGE400 runs
robust ÷ classical×1.04
truth ÷ classical×1.01
mean β̂ of 4000.9994
95% bar really hits95.0%
… with robust SE89.5%
predict: which bar grows?
What you’re looking at — one dataset, fitted once. β̂ is the slope OLS returns; SE is the “plus-or-minus” printed beside it, and the 95% bar is β̂ ± 1.96×SE. Winding the FAN makes the noise grow with x. The slope stays honest. The bar does not.
the fan + the CLASSICAL bar. The classical SE assumes one single noise size for every point, so it never notices the fan — its bar barely moves.
Ω, the sandwich meat + the ROBUST bar. White’s fix keeps the bread and swaps the filling: one square per point, sized by that point’s own e². No assumption, just measurement.
the TRUTH bar — the real spread of β̂ across 400 independent repeats. Robust chases it and never quite arrives, so a robust SE is a repair, not a guarantee.
Fig. 16. Wind the fan up: β̂ hardly budges, but the honest error bar doubles while the printed one stands still — a 95% interval that is right two thirds of the time.

Here is what breaks and what does not. Across 400 independent repeats the coefficient averages 0.9929 against a truth of 1.0, so β̂ is still unbiased. What fails is the arithmetic of the error bar. The classical formula averaged one σ² across observations that do not share one, and it reports 0.0472 when the true spread of the estimate is 0.1008. The t-statistic prints 20.65 and has no right to.

The fix is elegant and cheap. Keep β̂, and recompute its variance with each observation's own squared residual in the middle. Those are White, or heteroscedasticity-consistent, standard errors, and the shape is a sandwich: (XᵀX)⁻¹ Xᵀ diag(eᵢ²) X (XᵀX)⁻¹. On this run the robust standard error reads 0.0836, which is 1.77 times the classical one and much closer to the truth. An honest note goes with it. Robust closes most of the gap and not all of it, since 0.0836 still sits under the true 0.1008 in a finite sample. It is a repair, not a guarantee.

Second, serial correlation, and this one is the quiet killer in finance because it does not look like a mistake. The residuals predict their own neighbours, so today's leftover tells you something about tomorrow's. Read it two ways: the ACF of the residuals, which is Chapter 18's correlation applied to a series against its own lag, or the Durbin–Watson statistic, which is about 2(1 − ρ̂₁), so 2 means clean and near 0 means badly positively autocorrelated.

What breaks is the same thing. β̂ is unbiased and the error bar is wrong. The magnitude is what people miss, and it comes down to one idea. Effective sample size. If consecutive rows carry overlapping information, then n rows are not n independent facts, and a formula that divides by √n is dividing by the wrong number.

Now the specific finance trap, which is manufactured by bookkeeping rather than by markets. Sample the 12-month forward return monthly, and consecutive observations share eleven of their twelve months by construction. You did nothing wrong. You built the dataset the natural way, and adjacent rows are nearly the same measurement.

Predict before the arithmetic, because the gap between the guess and the answer is the whole lesson. You have 240 such monthly observations, so how many independent ones do you actually hold?

You sampled the 12-month forward return every month, so 240 rows rolled in. Drag the OVERLAP dial and count how many of them are actually new information.
① EACH BAR = 12 MONTHS rows 7+8 share 11 of 12 tap a bar ↕ months ② THE t-STAT ACROSS 4,000 ZERO-EDGE RUNS overlapped an honest t ±1.96 = the 5% line sealed — guess first 4.0 → 1.09 −8 −4 0 4 8
① OVERLAP DIALdrag →
step 1 month · 11 shared
② SEALED GUESStap one
③ THE COUNT240 rows
shared months11 of 12
independent n
t inflation
5% test fires
history needed20 yrs
④ t-CORRECTORtype a t
how many rows are independent?
What you’re looking at — 240 rows that look like 240 facts. Each row is a 12-month return; sampling monthly means row 8 repeats eleven of row 7’s months, so the sample only ever covers 20 separate years.
the bars — one 12-month window each. Slide the dial and they pull apart.
the shared months (count the slices) and the fat red t they cause: with zero real edge the t-stat still spreads ×3.66, so a 5% test fires in 58.3% of runs.
an honest t spreads 1.00.
divide by the inflation: a reported 4.0 is really 1.09.
Fig. 17. Twenty-four of the 240 rows, drawn as the months each one actually covers. At a step of 1 month the neighbours overlap by 11 of 12 months — count the slices in the red block — so the 240 rows carry only 20 independent years. Across 4,000 runs of a strategy with no edge whatsoever, that bookkeeping alone spreads the t-statistic by ×3.655 (the honest spread is 1.000, and √12 = 3.464 is where the number comes from), so a nominal 5% test fires 58.3% of the time and a proud t = 4.0 is really 1.09. Drag the overlap dial: the bars separate, the shared count falls to zero, and the inflation drains away — but paying for it needs 240 years of history, not 20.

People say 240. The honest count is 20 non-overlapping windows. Across 4,000 runs of a zero-edge series built this way, the t-statistic comes out with a spread of 3.655 when an honest t-statistic has a spread of 1.000. That is close to the bookkeeping factor √12 = 3.464. So a nominal 5% test fires in 58.3% of runs, and the t-statistic of 4.0 that ended the meeting is really about 1.09.

Hand that straight back to Chapter 19. Understated standard errors are a false-discovery factory, and a research group with this bug in its pipeline generates significant strategies indefinitely.

The fixes are known. Newey–West HAC standard errors widen the bar to account for dependence out to a chosen lag. Or model the dependence explicitly. Or simply stop overlapping. And the honest caveat stands: HAC is a patch, it needs a lag choice, and it is not absolution.

14The diagnostic kit

Every violation above announced itself in a picture, and not one of them announced itself in the numbers. So here is the argument for looking, and then the kit.

The argument is Anscombe's quartet. Four datasets with the same intercept of 3.00, the same slope of 0.500, the same standard error of 0.118, the same t of 4.24, and the same R² of 0.667. Before you see them, guess how similar the four scatter plots are.

Four identical printouts — guess how alike the four pictures are, then put each set under an instrument.
the printout — all four agree on every number
1 · predict: how alike are the four pictures?
2 · the dataset
3 · the instrument
guess first — then look.
What you're looking at — one printout, four worlds, and the instruments that tell them apart.
Set I — a plausible cloud. Residual‑vs‑fitted shows no pattern at all: this is what a healthy fit looks like, and it is the only one of the four that deserves the printout.
Set II — a perfect parabola. Same slope, same t, same R², but the residuals draw an arch: the form is wrong, not the noise. Any pattern at all means a missing column.
Set III — a clean line plus one outlier. The Q‑Q plot is built here: sort the residuals, put them against Ch 13's expected Normal order statistics, then draw the 45° line — and that one point is flung off it.
Set IV — ten points stacked at one x and one distant point with leverage h = 1.000, so the fit is forced exactly through it (its residual is 0). Leverage is the diagonal of the hat matrix H = X(XTX)−1XT, and that diagonal sums to k. The LEVERAGE panel runs the same instrument on a six‑day beta desk: 0.2598…0.9668, summing to 2.000, flagged at 2k/n = 0.667 — delete the crash day and beta falls 1.62 → 0.58: stable, and blind.
Fig. 18. Anscombe's quartet: four datasets that print the same intercept 3.00, slope 0.500, standard error 0.118, t of 4.24 and R² of 0.667 — and look nothing alike. Guess first, then reveal the pictures; then run each set past four instruments. Residual‑vs‑fitted is the general one (any pattern means a missing column), the Q‑Q plot gets built one step at a time out of sorted residuals and expected Normal positions, the ACF asks whether the residuals remember their own past, and leverage — the diagonal of H = X(XTX)−1XT, which sums to k — finds the one day that is holding the whole slope up by itself.

They are a plausible linear cloud, a perfect parabola, a perfect line with one outlier dragging it, and a vertical stack of points at one x-value plus a single distant point. In that last one the far point carries a leverage of 1.000, which means it sets the entire slope by itself. Identical summaries, four completely different worlds, one of which is not even a relationship.

Now the kit, four instruments and what each is for.

First, residual-versus-fitted, the general-purpose instrument. It should look like a shapeless cloud, and any structure is a message. Systematic curvature means the functional form is wrong. A widening fan means heteroscedasticity. And any pattern at all means there is signal left in the leftover, which by the exploitation argument means a column you have not included.

Second, the Q-Q plot, and we build it rather than show it, because it is the plot people pattern-match without understanding. Sort your residuals. Ask what the k-th smallest of n standard Normal draws should be, which is Chapter 13's order statistics sitting at a predictable expected position. Plot observed against expected. If the residuals are Normal, the points lie on the diagonal.

Notice what that is. It is exactly the picture from Chapter 19, where sorted p-values were laid against the diagonal pure noise would have produced, and the departure was the finding. Same move, different sorted quantity. So the reading is one sentence: ends peeling away above and below the line mean your tails are fatter than the Normal's. That is the default in finance, which is why A5 is the assumption to worry about least and the CLT is the thing carrying your inference.

Third, the ACF of the residuals and the Durbin–Watson statistic, which between them read the dependence from one row to the next. Fourth, the VIF table, which reads how much of each predictor its neighbours already account for.

And then one more instrument that gets skipped and should not. Influence. The projection can be written ŷ = Hy with H = X(XᵀX)⁻¹Xᵀ, called the hat matrix, which is nothing other than the projection operator itself. It is the machine that turns y into ŷ. Its diagonal entry hᵢᵢ is how much observation i determines its own fitted value, and that is called leverage.

The trace of H is k, so the leverages sum to k and the average is k/n. Put one far-out point in a six-point sample and you can watch it happen: the leverages read 0.2598, 0.2252, 0.1987, 0.1801, 0.1694 and 0.9668, summing to exactly 2.000, which is the column count. Anything past about 2k/n is a point with a loud vote. Combine leverage with the size of a residual and you have Cook's distance, which asks how much the whole coefficient vector moves if you delete that one observation.

Then the finance sting, which is a genuine dilemma rather than a rule. In a beta regression the single most influential day is almost always a crisis day. Delete it and beta looks stable, and your risk model has been taught to be blind to precisely the event it exists to measure. The diagnostic tells you where the number came from. It does not tell you to throw the day away.

15The bootstrap, checked before it is trusted

One tool left, and it is the one to reach for when you would rather not sign the fine print at all.

Every error bar so far came from a formula that assumed something. Constant variance, independent errors, sometimes normality. Suppose you want an error bar for something with no formula, like a Sharpe ratio, a maximum drawdown, a median, or a ratio of two coefficients. Or suppose you simply do not believe A3 and A5.

Go back to Chapter 16's definition. The sampling distribution is the law of your statistic over all the samples you could have drawn from the population. The reason it is unreachable is that you have exactly one sample and no access to the population.

Here is the whole idea of the bootstrap, in one sentence. You do have an estimate of the population, because your sample is one: the empirical distribution that puts mass 1/n on each row you observed. So sample from that.

Draw n rows with replacement, refit the model, and record β̂. Do that a few thousand times and you are holding a cloud of estimates you can actually plot. Its standard deviation is a standard error, and its 2.5th and 97.5th percentiles are a confidence interval, with no formula and no distributional assumption anywhere.

Now, everyone's first reaction is that this is cheating. You invented data and learned something from nothing. It deserves a straight answer rather than a reassurance. You are not inventing data. You are sampling from your best available estimate of the population, which is the same plug-in principle you used every time you put s in place of σ.

And you can check it rather than trust it, which is the move that should make it credible.

CodeRun — run the bootstrap where the answer is already known, then take it where no formula can follow.
the bootstrap’s answer, vs B 0.09 0.11 0.13 0.15 s/√n = 0.1096 50 1k 10k why this is not cheating your SAMPLE stands in for the world
THE RUN
RESAMPLES B = 10,000 ← drag
THE STATISTIC
0.1102 vs 0.1096 — it works.
The gold line is the formula’s answer. The blue trace is the bootstrap’s. Drag B.
What you’re looking at — the bootstrap, checked against an answer we already know, then taken where none exists
gold = the answer you can already check. On tab 1 that is the formula SE = s/√n from Ch 17; on tabs 2–3 it is the true spread, because we built the world ourselves. This is the only reason the demo can prove anything.
blue = what resampling says. Draw n rows from your own sample with replacement, refit, repeat B times, take the spread of the answers. Drag B: at 50 it wobbles (that is Monte-Carlo noise, not error), by 10,000 it has settled on gold.
red = the formula used where it does not hold. With the error fan, the classical SE reads 0.0472 against a truth of 0.1008 — a t-stat inflated 2.1×. Switch to a residual bootstrap and blue collapses onto red: pooling residuals smuggles equal-spread back in.
violet = robust (HC0), which was told about the fan in its algebra. The pairs bootstrap lands beside it at 0.0848 vs 0.0836 knowing nothing. Its two honest limits: it assumes iid rows (dependence needs a block bootstrap), and it measures spread, never bias — tab 3.
Fig. 19. The objection first, because it is the right one: resampling your own sample to learn how much that sample wobbles sounds like pulling yourself up by your bootstraps — hence the name. So do not argue; check it where the answer is already known. A sample of 100 has s = 1.0961, so Chapter 17’s formula says SE = s/√n = 0.1096; 10,000 resamples say 0.1102, and the two 95% intervals land within 0.0005 of each other. Drag B down and the bootstrap’s answer wobbles — that is Monte-Carlo noise from too few resamples, not error — then watch it settle onto the gold line as B grows. It is the same plug-in move you already accepted when s stood in for the unknown σ: your sample is your best estimate of the population, so resampling it is sampling from your best estimate of the world. Now take it where the formula is wrong: on the fanned regression the classical SE reads 0.0472 against a truth of 0.1008, while the pairs bootstrap returns 0.0848 and parks itself beside robust HC0’s 0.0836 — having been told nothing. Flip to a residual bootstrap and it collapses back to 0.0466: pooling residuals quietly re-assumes the equal spread you were trying to escape, so resample rows, not residuals. Where there is no formula at all — the median — one word changes in the code and the answer appears. And the two honest limits: it assumes iid rows (dependence needs a block bootstrap that resamples chunks), and it estimates spread, never bias. Tab 3 proves the second: an endogenous fit whose truth is 1.000 returns a confident [1.972, 2.209], and quadrupling the data merely halves the width around the same wrong number.

Bootstrap the sample mean, where Chapter 16 already tells us the right answer. The formula says s/√n = 0.1096. Ten thousand resamples say 0.1102. The intervals agree to three decimals as well. Validate the new instrument against a formula you already believe, on a case where the formula is known to be right, and then take it where formulas run out.

So take it there, and point the same procedure at the heteroscedastic regression from the fan, where the classical formula reported 0.0472 against a true spread of 0.1008. Resampling whole rows gives 0.0848, which lands right beside the robust answer of 0.0836. The bootstrap found the correction without being told that anything was wrong. And on a statistic with no clean formula, the median of that same sample, it returns a standard error of 0.1744 with no extra theory required.

Two flavours are worth distinguishing. The pairs bootstrap resamples whole rows together, which makes no assumption about the error variance and therefore survives heteroscedasticity. The residual bootstrap refits, then reshuffles the residuals onto the fitted values, which assumes the errors are interchangeable across observations and therefore quietly assumes homoscedasticity back in.

Then the honest limits, because the bootstrap is sold as assumption-free and is not. It assumes the rows are iid, which is precisely what serially correlated financial data is not, so the naive bootstrap on a time series is as over-confident as the classical standard error. The repair is the block bootstrap, resampling contiguous chunks so the local dependence rides along inside the block.

And the harder limit. The bootstrap estimates spread, never bias. Bootstrap the endogenous regression and it returns a beautifully tight 95% interval of [1.972, 2.209] around a truth of 1.000. Every resample inherits the same contamination, so the tightness is real and the aim is still wrong.

One loan forward. This is the tool that gives a Sharpe ratio a standard error in Chapter 30, where no clean formula exists at all.

16The audit, in order

Put it back together, because after fifteen sections the risk is that the lesson reads as "regression is fragile, check five things". That is demoralising and it is also wrong.

Here is the accurate summary, in two sentences. A regression is an orthogonal projection, always valid, always computable, never in question, and it tells you the closest point reachable from the columns you supplied. Everything else is a stack of claims about the world, each one auditable separately.

The whole chapter, folded into one rail. Four questions, in one order. Walk them, then re-order them the way most people actually do — and watch the fatal one sink to the bottom.
AUDIT ORDER — tier-table order tap a row THE REPAIR 1 THE COORDINATES REPAIRABLE rank & VIF — is b̂ identified? 2 THE AIM FATAL omitted · feedback · selection 3 THE ERROR BAR REPAIRABLE robust · HAC · bootstrap · true n 4 THE SHAPE REPAIRABLE plot residuals vs fitted — curve? drop or combine the twin column. If you only PREDICT, leave it — it is harmless. NO REPAIR REACHES THIS ONE ANSWERED HERE BY the VIF slider the column collapse 1 never falls when    you add junk 2 silent on aim and    on causation 3 measured on the    fitting rows ✗ NOT ON THE LIST THE DOOR · CH 21 shade the stations to open it. AUDIT ORDER — cheapest first, fatal second. Tap a station to see the one repair that applies. Only ONE of the four has none — and it is the only one that poisons the coefficient.
① WALK THE RAILtap one
② RE-ORDERswap
③ HUNT FOR R²search
④ IN-SAMPLE SHADEthe door
tap a station to audit it
What you’re looking at — the chapter as a checklist, in the order that protects you. is the coefficient OLS returns; the ± beside it is its standard error. The number to the left of each row is its place in the audit, and it moves when you re-order.
the coordinates. Twin columns collapse the column space — b̂ wobbles, though prediction survives. VIF measures it.
the aim — the fatal one. Omission, feedback, measurement error, selection. No estimator repairs it; only different data or a different design does.
the error bar. Robust, HAC, bootstrap, effective n — these fix the ±, never the number.
the shape. Always plot the residuals. And note what is missing from the whole rail: — hunt for it and see.
Fig. 20. Four questions, one order. The fatal one sits second — above the two most people spend their day on — and never appears at all. Shade the rail and the last confession shows: every check here was computed on the rows the fit was chosen on.

And the audit has a fixed order, because the tier table sorted it for us.

One. Do the coordinates exist, and are they identified? Check rank, check VIF, and remember that a stable projection can carry wildly unstable coordinates. If you only need predictions, this question may not even matter.

Two. Is the number aimed at the right target? What is omitted, what runs in both directions, what is measured with noise, who was selected out of the sample. This is the only question in the whole chapter whose wrong answer poisons the coefficient, and no computational repair reaches it.

Three. Is the error bar honest? Robust standard errors as the default, HAC when the data is a time series, the bootstrap when the statistic has no formula. And always ask what the effective sample size really is.

Four. Is the shape right? Plot the residuals, because four datasets can agree on every printed number and disagree about everything that matters.

Notice what that ordering does. It puts the fatal question second, above the two that most practitioners spend their time on. And it puts the number everybody quotes, , nowhere on the list at all. In-sample R² cannot fall when you add columns, it reaches 1.0000 for a model that has memorised its data, and it is silent about causation, functional form and the future.

Which is precisely the shape of the door into the next chapter, and it is worth naming the shape exactly.

Every diagnostic in this one was computed on the same data the fit was chosen on. The residuals were made orthogonal to the columns by construction. The R² was maximised on those rows and no others. And Chapter 19 already taught us that a search leaves its fingerprints on the number it selects.

So there is exactly one question none of this machinery can answer. Does the relationship hold on data the fit has never seen? Answering it needs no formula, no assumption and no correction factor. It needs data the search never touched, and that is Chapter 21.

iolinked.com
Written by Ajai Raj