chapter 00 · before the answer
the members you can see
"The engineers examined the planes that came back." The ones you can see are never the whole population — they are the ones that survived long enough to be counted.
chapter 02 · the shape of data
the average and the tail
"When the mean and median diverge, the distribution is skewed. The gap between them tells you how much the average is being distorted by the tail."
univariate.py reports skewness and flags when the mean stops being an honest summary.chapter 02 · the shape of data
the ghost segment
"The average lands inside the majority. It says nothing about the quarter who are barely here at all."
distribution_matching.py runs a dip test — it catches bimodality that skewness alone reports as zero.chapter 02 · the shape of data
why the average of many draws is a bell
"The data isn't normal, so none of this applies." The data doesn't have to be. Only the average of many draws does — and it gets there fast.
The population — every transaction, unfiltered
300 samples of size n, each reduced to its own mean
when the line is wrong
"A straight line through curved data is not an approximation. It is a systematic error that changes direction across the range."
nonlinearity.py tests the residual pattern itself, not just the fit — a straight line can have a decent R² and still be systematically wrong.a log transform straightens a tail
"Logs are a statistician's trick." Not a trick — a change of ruler. Slide λ from 1 (the ruler you're used to) to 0 (a ruler marked in percent) and watch the same real data read differently.
transformations.py tests a Box-Cox range and picks λ by what minimises skew, not by convention.why it is missing
"The instinct, when you see a column with missing values, is to ask how many are missing. That is the wrong first question. The right question is why."
This isn't hypothetical. ActiveEdge's real satisfaction_score column is 34.6% missing — and the gap tracks exactly who the ghost segment already flagged as barely here.
missing_values.py diagnoses the mechanism before anything is imputed, and refuses to impute under MNAR without a stated assumption.mean imputation flattens the truth
"Just fill the blanks with the average — it doesn't change the mean." True of the mean. Watch what happens to everything else.
chapter 05a · when the answer is a number
three questions, three kinds of answer
"Every model is a lens. Some clarify. Some distort."
model_selection.py picks between these three before you do — and reports adjusted R², not raw, by default.the class effect
"The gym chain saw its class-goers renew more and prepared to expand the program. It should have asked one question first: who was already choosing to show up?"
causal_psm_ipw.py matches or reweights by the confounder before comparing groups — the same idea as this figure's visit-frequency split, done properly.simpson's paradox
"Standard plan members renew better than Premium overall. Split by tenure and Premium wins in both groups. Both statements are true."
membership_type column — the real data shows no such reversal on any plan split checked. Kept as a clean, worked example of the mechanism itself.the range around the number
"The slide said five kilometres. It did not say between 4.2 and 5.8 kilometres, at the current level of precision."
the campaign that did nothing
"The November report showed nothing. AE almost pulled the campaign — three months before it actually started working."
media_transforms.py's geometric_adstock() models exactly this: a campaign's effect spread across future periods with decay, never credited to the launch month alone.fits the past, fails the future
"The more flexible model fits better, so it is better." It fits the 60 points you gave it better. Watch what it does to the ones you didn't.
model_selection.py checks held-out performance before reporting a fit, precisely so a curve like this can't pass by only looking good on the data it was trained on.the column from the future
"99% accuracy in testing" with no suspicion. A model predicting renewal, built on ActiveEdge's own real columns, including the two with an underscore in their name — the ones that look hidden, internal, suspicious.
twenty predictors, one driver
"We screened twenty predictors and found a significant driver." Screen twenty real columns that have nothing to do with the outcome, and by chance alone, about one of them will look significant too.
chapter 12 · the right tool for the question
the member who hasn't left
"Still-active members are missing data — drop them." Or: "count them as churned at the cutoff." Both give you a confident number. Only one of them is honest about what you don't know yet.
survival_model.py fits Kaplan-Meier by default and reports "not yet reached" explicitly rather than a number that implies more certainty than the data has.also on the site
the p-value that peeked
"The p-value crossed 0.05 on day 9, so we stopped and shipped." Two arms with the real 57.25% renewal rate on both sides — genuinely no difference — checked every day until one of them looked significant.
also on the site
two lines that had nothing to do with each other
"These two series move together — r = 0.8 — so one must be driving the other." Two random walks, generated with no connection to each other whatsoever, routinely correlate this strongly. Persistence alone is enough to manufacture it.
One pair — sixty months, generated with no connection to each other
Correlation across 200 independent pairs at this persistence
also on the site
western electric rules
"Nothing breached the control limit, so the process is fine." A single point beyond three standard deviations is the blunt signal. A slow, sustained drift can be caught much earlier — by a pattern, not a threshold.
spc_control_chart.py runs all six Western Electric and Nelson run rules on every chart, not just the 3σ threshold.also on the site
the month everyone remembers
"The manager remembered exactly why the bad month happened. The record remembered something else — that it wasn't unusual at all."
outliers_univariate.py asks the same question of any spike before anyone builds a story around it: is this extreme relative to the actual distribution, or just the most memorable point in it?