What is actually strange here
Nothing about the arithmetic. Sums of fractions are allowed to behave this way and there is no error to find, no rounding to blame, no bug in the query. What is strange is that two correct summaries of the same rows recommend opposite actions, and that the information needed to choose between them is not present anywhere in the rows.
★ What you walk out with tonight. A reversal you built by hand from nine hundred rows a side, so it stops feeling like a trick. The rule that decides which number to act on: the stratifier's role in the graph, confounder against mediator against collider. And the reason the two most common pieces of advice in analytics, "always segment" and "never trust the aggregate", are each wrong about half the time.
LiveThe same numbers, two opposite conclusions3 min▶
The shape has a precise definition. An association between two variables holds in every level of a third variable, and reverses when that third variable is ignored. It also runs the other way round: no association in the aggregate, a strong one in every subgroup. Both are the same phenomenon and both are ordinary arithmetic.
What makes it worth a session is the frequency. Any time a treatment is allocated unevenly across groups that differ in baseline outcome, the ingredients are present. Uneven allocation is the normal state of affairs outside an experiment, because somebody chose who to treat and they chose for a reason.
The famous instance is the 1973 Berkeley graduate admissions figures, where the university-wide rate favoured men and almost every individual department favoured women. No department was doing what the aggregate suggested. Women applied in larger numbers to departments that admitted fewer of everybody.
Self-studyThe vocabulary for tonight3 min▶
- Stratum - one level of the variable you split on. Two strata tonight; the effect is identical with twenty.
- Aggregate - the comparison with the stratifier ignored, which is the same thing as pooling the strata weighted by their own row counts.
- Reversal - the sign of the comparison differs between every stratum and the pool.
- Unequal allocation - the treated and untreated groups have different proportions in each stratum. This is the engine of the reversal; with equal allocation it cannot happen.
- Berkson's paradox - the collider-driven cousin, where selecting on a common effect creates an association between two unrelated things. Session 2.
- Stratifier role - confounder, mediator, collider, or bystander. The whole resolution turns on this one word, and the word comes from the graph.
The same numbers, two opposite conclusions
10 min liveHere is a reversal small enough to check on paper. A subscription business offers a renewal discount to 900 of its 1,800 accounts due for renewal, and afterwards counts who renewed. Two strata: routine accounts, and accounts the churn model had already flagged as at risk.
| Stratum | Group | Accounts | Renewed | Renewal rate |
|---|---|---|---|---|
| Routine | Offer | 100 | 80 | 80.0% |
| Routine | No offer | 800 | 600 | 75.0% |
| At risk | Offer | 800 | 240 | 30.0% |
| At risk | No offer | 100 | 25 | 25.0% |
| Both | Offer | 900 | 320 | 35.6% |
| Both | No offer | 900 | 625 | 69.4% |
The offer wins by five points among routine accounts and by five points among at-risk accounts. Pooled, it loses by nearly thirty-four. The row counts are where the reversal lives: 800 of the 900 offers went to at-risk accounts, whose renewal rate is low whatever you do to them, while the no-offer group is mostly made of routine accounts, whose renewal rate is high whatever you do to them.
LiveCheck the arithmetic by hand, because it is the point3 min▶
Four divisions, each exact. Routine offers, 80 of 100, is 80.0 percent. Routine no-offers, 600 of 800, is 75.0 percent. At-risk offers, 240 of 800, is 30.0 percent. At-risk no-offers, 25 of 100, is 25.0 percent. The offer is ahead by exactly five points in both strata.
Now pool. The offer column: 80 plus 240 renewals is 320, out of 100 plus 800 accounts, which is 900. That is 35.6 percent. The no-offer column: 600 plus 25 renewals is 625, out of 800 plus 100 accounts, also 900. That is 69.4 percent. Same 1,800 accounts, same 945 renewals, and the winner has changed.
The reason is visible in the counts and nowhere else. The offer group is 89 percent at-risk accounts, whose ceiling is low. The no-offer group is 89 percent routine accounts, whose floor is high. Pooling compares a mostly-hard sample against a mostly-easy one, and the five-point advantage inside each stratum is buried by a forty-five-point difference in stratum composition.
Equal allocation kills the paradox. Had 450 offers gone to each stratum and 450 no-offers to each, the pooled rates would be the plain averages of the strata rates and the offer would win by five points overall. Reversal needs both a baseline difference and an allocation difference; remove either one and it cannot occur.
LiveIt is not a paradox, and calling it one hides the real question3 min▶
A paradox is a contradiction. There is no contradiction here: two different quantities were computed and they came out different, which is what different quantities do. The stratified comparison answers "among accounts like this one, does the offer help". The pooled comparison answers "of the accounts that got the offer and the accounts that did not, which group renewed more". Those are separate questions with separate answers and both answers are right.
The surprise comes from an unstated assumption that one of them is the effect of the offer. Neither is, automatically. A comparison becomes an effect only when the groups being compared differ in nothing but the treatment, and whether that holds is a claim about how accounts came to be treated, which lives outside the table.
- The arithmetic is never in dispute. Do not go looking for the bug. There is no bug, and hunting for one wastes the afternoon that should have been spent on the graph.
- The dispute is about which comparison is the causal one. That is a modelling question, and it has an answer, and the answer is not in the data.
- Both numbers can be reported honestly. What cannot be done honestly is reporting one of them as the effect without saying why the other was rejected.
Self-studyWhere the ingredients show up in ordinary work4 min▶
- Any targeted campaign. Targeting is deliberate unequal allocation, so the ingredients are present by design in every campaign readout that was not randomised.
- Any triage. Treatments given preferentially to severe cases, support tickets routed by difficulty, remedial teaching given to struggling students. The treated group is worse off before anything happens.
- Any comparison across time. If the mix of customers changed between two periods, the aggregate can move in the opposite direction to every segment within it.
- Any weighted average that somebody unweighted. Pooling raw counts silently reweights by group size, and group size is rarely a quantity anybody chose on purpose.
- The tell is always the same. Look at the allocation, not the outcome. If the treated and untreated groups have very different compositions, the aggregate is a comparison of compositions wearing a treatment label.
The graph decides, not the table
8 min liveTake the identical table and hang it under two different graphs. Under the first, the stratified numbers are the ones to believe. Under the second, stratifying is the mistake and the aggregate is closer to right. Nothing in the rows changed. Everything about the recommendation did.
LiveThree roles, three verdicts4 min▶
Session 2 named the shapes. Applied to a stratifier, each one gives a different answer to "should I split on this".
- Confounder, a common cause of treatment and outcome. Split. The stratified numbers are the causal ones and the pooled figure is contaminated by the back-door path. In the renewal table, if the churn risk both determined who got the offer and predicted renewal on its own, this is the case: the offer helps, by five points, in both strata.
- Mediator, on the causal path from treatment to outcome. Do not split. Holding it fixed removes part of the effect you are trying to measure, so the stratified numbers understate and the pooled figure is closer to the total effect. Session 10 measures exactly this on Kestrelmark's
openedvariable, at 5.48 against a total of 6.23. - Collider, a common effect of treatment and outcome or of their causes. Do not split. Conditioning on it manufactures an association that was not there, so the stratified numbers are worse than the pooled ones. Session 10 prices Kestrelmark's two colliders at 0.97 for the loyalty score, which precedes the email, and 3.64 for the ticket flag, which the email helps cause: the downstream one is by far the more expensive of the pair.
- Bystander, connected to neither. Splitting changes nothing at all. Kestrelmark's
devicevariable moves the estimate by nothing to two decimal places, which is the cleanest possible reminder that harmful variables cannot be spotted by feel.
The uncomfortable part is that the table looks identical in all four cases. There is no column of the data, no correlation, no fit statistic that distinguishes them. The distinguishing information is the direction of the arrows, and arrows come from knowing the business.
LiveKestrelmark's own version4 min▶
The re-engagement email has the same ingredients. The winter campaign calendar sends more email, and people buy more in winter regardless of email, so season both allocates the treatment and drives the outcome. Long-tenured accounts sit on more lists and spend more anyway, so tenure does the same. Two confounders, two back doors, unequal allocation across both.
The aggregate comparison of emailed against not emailed gives 10.54. Holding season and tenure fixed gives 6.56, against a true effect of 6.23 known by construction from the model that generated the customers. The aggregate overstates by 4.31 units, which is two thirds of the true effect again.
Both roles are confounders here, so the verdict is unambiguous: 6.56 is the number to act on and 10.54 is the number to explain. Note how little the size of the gap tells you on its own. A gap of that size under a mediator would have meant the opposite, and no amount of staring at 10.54 and 6.56 would reveal which case you were in.
The board deck version reads "the campaign drove 10.54 units of incremental spend". Nobody in that room can check it, because checking it requires the graph and the graph was never written down. The analyst who asks "what did you hold fixed, and why those variables" converts a slide into a conversation.
Self-studyWhy "always segment" and "never segment" are both wrong3 min▶
Both rules of thumb are attempts to replace a causal judgement with a procedure, and neither can work, because the two cases they are trying to cover recommend opposite actions on identical tables.
- "Always segment" fails on mediators and colliders. Segmenting by something the treatment caused answers a different question at best and manufactures bias at worst. The habit is popular because segmenting almost always produces an interesting-looking difference.
- "Never trust the aggregate" fails on mediators too, and on any case where the pooled figure was the total effect all along. It also has no stopping rule: there is always one more variable to segment by, and segmenting far enough reaches subgroups of one.
- The replacement rule is short. Name the role of the variable in the graph before splitting on it. If nobody can name the role, that is the finding, and the split waits.
- Berkson's paradox is the same lesson in the collider case. Selecting on a common effect creates an association between causes that were independent. Session 2 built it; here it is one of the four verdicts.
Reproduce it, then resolve it
★ 18 min · everyone buildsBuild the small table in SQL first, because a reversal you typed yourself is a reversal you believe. Then run the same two comparisons on the Kestrelmark customers, write both numbers side by side, and classify the stratifier before saying which one is the effect.
Step 1. Type the four cells and let the database pool them. Two queries against the same rows: one grouped by stratum and offer, one grouped by offer alone. Nothing else. The reversal appears without any modelling at all.
Step 2. Check the pooled row counts against your own addition. 100 plus 800 is 900 on each side. If the two sides had come out unequal you would be looking at a different phenomenon and it would be worth stopping to find out which.
Step 3. Run the naive comparison on Kestrelmark and write down 10.54. This is the aggregate, and it is what a dashboard reports.
Step 4. Hold season and tenure fixed and write down 6.56 beside it. Two numbers, one line apart, from one dataset. Both correct as arithmetic.
Step 5. Classify the stratifier with the session 2 rules and commit to one number in writing. Season is a common cause of email and spend, so it is a confounder, so the held-fixed number is the causal one. Write the sentence, not just the figure.
Step 6. Now do it wrong on purpose. Hold opened fixed instead and watch the estimate fall to 5.48. Same procedure, same code, a stratifier with a different role, and a number that answers a question nobody asked.
Keep the allocation column in the output. The reversal is invisible in the rates and obvious in the counts. An output that shows only percentages hides its own explanation, which is why a readout with rates and no denominators should always be sent back.
★ What just happened. Three numbers came out of one dataset with one line of difference between them: 10.54, 6.56, 5.48. All three are correct arithmetic and only one answers the question on the spec. The thing that separates them is a single word about each stratifier, and the word is not in the data.
Before session 6
30 min- Find a reversal in your own data. Take any treated-against-untreated comparison your team reports and split it by the variable that most influenced who got treated. Record whether the sign flips, narrows, or holds.
- For that stratifier, write one sentence naming its role: common cause, on the causal path, common effect, or unrelated. Bring the sentence, not the number.
- Take one segmented readout your team publishes regularly and check whether any segmenting variable is caused by the thing being measured. Those splits are producing a different quantity every week.
- Rewrite one dashboard tile so it shows denominators next to rates. Half of the reversals in a business are hiding behind a missing count.
Three questions
You have the renewal table and nothing else: 80.0 against 75.0 in one stratum, 30.0 against 25.0 in the other, 35.6 against 69.4 pooled. Which number is the effect of the offer?
The table is identical under both graphs, so no property of the data can separate them. The deciding information is the direction of the arrows, which comes from knowing how accounts were selected for the offer.
Kestrelmark's aggregate gives 10.54 and holding season and tenure fixed gives 6.56, against a true effect of 6.23. What made the aggregate wrong?
Two confounders, two open back doors, and unequal allocation across both. Confounding is bias rather than noise, so more customers would have produced 10.54 with tighter error bars.
A colleague proposes a standing rule: "always segment, because aggregates lie". What is wrong with it?
"Never segment" fails the same way in the confounder case. Both rules of thumb try to replace a judgement about the graph with a procedure, and the two cases they cover recommend opposite actions on the same table.
What tonight maps to
learn-experimentation-with-phoebe.