A practitioner's series

Causal Inference:
Four Methods
Compared

Most data science answers the wrong question. Correlation is easy to find; causation is what decisions are made on. This series builds four causal methods from scratch — on real data, in real notebooks.

notebooks/A-B%20Testing.py
# Estimate ATE — three equivalent ways # A: Difference in means ATE = Y1.mean() - Y0.mean() # B: OLS regression model = OLS(purchased, ['treatment', 'age']).fit() ATE = model.params['treatment'] # C: Bootstrap 95% CI for i in range(2000): s = df.sample(n=N, replace=True) boot_ates[i] = s[s.treatment==1].purchased.mean() \ - s[s.treatment==0].purchased.mean() ci = np.percentile(boot_ates, [2.5, 97.5]) # Log to MLflow mlflow.log_metric("ATE", round(ATE, 5)) mlflow.log_metric("CI_lower", ci[0]) mlflow.log_metric("CI_upper", ci[1])
5 Methods
3 Datasets
9 Phases
The series

Nine phases, one cohesive project

Each phase introduces a new method by showing what the previous one couldn't handle — building genuine intuition for when and why each approach exists.

PHASE 01
● Live
A/B Testing

The gold standard. Randomization eliminates confounders by design. Build intuition for what a causal estimate means — and see what happens when you break the experiment.

ATERCT Bootstrap CIMLflow
PHASE 02
● Live
Difference-in-Differences

LaLonde job training dataset. Workers self-selected into training — no randomization. DiD uses the time dimension to remove selection bias, under one testable assumption.

ATTLaLonde Parallel TrendsPlacebo Test
PHASE 03
● Live
Propensity Score Matching

Same LaLonde data, no panel structure needed. Match treated and control workers on their probability of treatment. Love plots, SMD, covariate balance.

ATTPSM Love PlotSMD
PHASE 04
● Live
Inverse Probability Weighting

PSM discarded 55% of treated workers. IPW keeps everyone — reweighting controls by how "treated-like" they are. ATT = $1,212. Best observational estimate in the series so far.

ATTIPW AIPWDoubly-Robust
PHASE 05
● Live
Synthetic Control

One treated state, 20 donors, known true effect of $1,500. ATT = $1,521. RMSPE ratio 4.36. Permutation p = 0.000. The cleanest result in the series.

ATTQP Optimization RMSPEPlacebo-in-space
PHASE 06
● Live
Regression Discontinuity

A scholarship cutoff at score 70 creates quasi-random assignment. McCrary density test, Imbens-Kalyanaraman bandwidth, local linear regression, sharp vs fuzzy.

LATEMcCrary Test BandwidthSharp vs Fuzzy
PHASE 07
● Live
Double Machine Learning

LaLonde + CPS-3. Robinson PLR with GBM nuisance models (A DML approach), 5-fold cross-fitting. ATT = $1,499 (83.6% recovery). Best point estimate in the series. CI crosses zero — sample size is the binding constraint.

ATTDML - PLR GBM nuisanceCross-fitting
PHASE 08
● Live
Causal Inference at Scale — DoWhy + EconML

401(k) eligibility, n=9,915. Seven methods, two estimands. ATE ≈ $7,594, ATT ≈ $9,166 (mean across methods). DoWhy backdoor regression underestimates both — flat-effect assumption breaks under real heterogeneity. Capstone of the series.

ATE + ATTDoWhy DAG EconMLCausalForest

Why correlation keeps getting people fired

1
Correlation ≠ Causation

Ice cream sales and drowning rates are correlated. Neither causes the other — summer does both. The same logic applies to most business metrics.

2
Selection Bias

Users who click on premium features are not comparable to those who don't. The click caused the difference, or did a pre-existing difference cause the click?

3
The Fundamental Problem

You can only observe each unit in one state — treated or untreated. The counterfactual ("what would have happened otherwise?") is always missing. Every causal method is a different strategy to reconstruct it.

Choose your method by your data

Decision guide

Can you randomize? → A/B Test
Have panel data + control group? → DiD
Have rich covariates, no panel? → PSM or IPW
One treated aggregate unit? → Synthetic Control
Score-based treatment cutoff? → Regression Discontinuity
High-dimensional confounders? → Double ML

MethodEstimandKey Assumption
A/B TestATERandomization
DiDATTParallel Trends
PSMATTNo hidden confounders
IPWATTNo hidden confounders
Synthetic ControlATTPre-period fit
RDLATENo manipulation
Double MLATTNo hidden confounders

Why A/B Testing is the Gold Standard — and What Breaks When You Can't Use It

Before learning four causal methods, you need to understand the one method that needs no assumptions. Then you need to see it fail. That's what this phase is about.

Start with a question, not a method

Your team redesigned a product page. Someone in a Monday meeting says "let's check if the new page performs better." You pull a report showing users who saw the new page converted at 13%, versus 10% for the old page. A three percentage point lift. Ship it?

Not yet. That 3pp difference has two possible explanations: the new design caused more purchases, or the users who happened to see the new design were already more likely to buy. You cannot tell which is true from that number alone. This is the fundamental problem of causal inference — and it comes up in every business decision involving data.

"Randomization doesn't just control for confounders you can think of. It controls for confounders you haven't thought of yet."

What makes an A/B test causal

An A/B test is a Randomized Controlled Trial (RCT). You randomly assign each user to either the old page (control) or the new page (treatment). The word "randomly" is doing enormous work here.

When assignment is truly random, every characteristic of a user — their age, their purchase history, their device, their income, their mood — is equally distributed across both groups in expectation. The treated and control groups are statistically identical before the experiment starts. So any difference in outcomes afterwards can only come from one place: the thing you changed.

This is why the naive mean difference is the causal effect in a proper A/B test:

ATE = E[Y | D=1] − E[Y | D=0] = Ȳ_treated − Ȳ_control

No adjustment. No modeling. No assumptions beyond "the randomization actually worked." This simplicity is the gold standard everyone else is trying to approximate.

The estimand: ATE

We're estimating the Average Treatment Effect (ATE) — the average causal effect across the entire user population, both those who would be treated and those who wouldn't. Formally:

ATE = E[Y(1) − Y(0)]

Where Y(1) is a user's outcome if they see the new page, and Y(0) is their outcome if they see the old page. The problem: you never observe both for the same user. Randomization lets you reconstruct this average across groups.

Building the dataset

We simulate 10,000 users with a known true effect of exactly 3 percentage points. Crucially, we also include covariates — age, device type, prior visits — that will become confounders in Phase 3 (PSM). This is intentional: one dataset, used across multiple phases, each time exploiting different structure.

TRUE_EFFECT = 0.03  # 3pp lift — the answer we want to recover

# Random assignment — the core of an A/B test
treatment = np.random.binomial(1, 0.5, N)

# Outcome probability — treatment adds 3pp on top of covariates
log_odds = (
    -2.5
    + TRUE_EFFECT * 4 * treatment
    + 0.02 * (age - 35)
    + 0.05 * prior_visits
)
purchased = np.random.binomial(1, sigmoid(log_odds), N)

The DGP (data generating process) is the true model that created your data. In real life you never know it. Here you do — which is what makes simulation so powerful for learning. Your estimator should recover 0.03.

Three estimators, same answer

We estimate ATE three different ways — not because we need to, but to build intuition for what an estimator actually is. In a proper RCT, all three converge on the same number.

Purchase rates by group with 95% confidence intervals
Figure 1. Purchase rates for control (old page) and treatment (new page) groups with 95% confidence intervals. The 3pp gap matches the true effect baked into the simulation — a sanity check that the estimator is working correctly.
Key insightAdding covariates to the OLS regression makes the standard error smaller (more precise) but barely changes the point estimate. That's because covariates are uncorrelated with treatment under randomization — they explain residual variance in Y but not the treatment effect. In Phase 3, adding covariates will change the estimate dramatically. That difference is worth internalizing now.

Confidence intervals: analytical vs bootstrap

A point estimate without an interval is incomplete. We compute CIs two ways: analytically (from OLS standard errors, assumes normality) and via bootstrap (model-free, resamples data 2,000 times). Both give similar results because our sample is large. The bootstrap becomes essential in smaller samples or non-standard estimands.

Bootstrap distribution of ATE across 2000 resamples
Figure 2. Bootstrap distribution of the ATE across 2,000 resamples. The distribution is centered on the estimated effect (~3pp), with the shaded region showing the 95% confidence interval. The red dashed line marks the true effect — confirming accurate recovery.

The most important cell: breaking the experiment

We deliberately remove randomization and re-run the same analysis. Younger, more engaged users now self-select into the treatment group. The naive estimate inflates to roughly 6–8 percentage points — more than double the true 3pp effect. The SMD (Standardized Mean Difference) on age and prior visits jumps from near zero to 0.3+.

This is not a hypothetical. This is exactly what the LaLonde dataset in Phase 2 looks like. Workers who chose to enroll in job training were already different from those who didn't. The naive estimate is biased by exactly this mechanism.

"Without randomization, the naive estimate was 2× the true effect. That's not noise — that's selection bias, and it will mislead every decision made from it."

Covariate balance: SMD before and after breaking randomization
Figure 3. Standardized Mean Difference (SMD) for each covariate in the proper A/B test (left) versus the broken experiment (right). In a properly randomized test, all SMDs sit near zero — the groups are balanced. After introducing selection bias, SMD on age and prior visits jumps above 0.3, revealing the imbalance that inflates the naive estimate.

Where the gold standard breaks down

Randomization eliminates confounders — but only if the experiment is run correctly. In practice, A/B tests fail more often from execution mistakes than from bad statistical design. These are the four ways a well-intentioned experiment produces a wrong answer.

1. Peeking — stopping the experiment early

You launch a test, check the dashboard two days later, see p=0.03, and stop. The problem: p-values are designed to be interpreted at a single pre-specified sample size. Checking repeatedly — at day 1, day 2, day 3 — gives you multiple chances to cross the significance threshold by random chance. With 20 peeks, your actual false positive rate climbs from 5% to roughly 40%. You ship a change that did nothing, or worse, harmed users, with the full confidence of a "statistically significant" result.

The fix: commit to a sample size before the experiment starts and don't stop early. If your team genuinely needs continuous monitoring, use sequential testing methods — always-valid p-values or Bayesian frameworks — which are designed for this use case.

2. Insufficient power — not knowing your sample size

An underpowered experiment produces false negatives: your test finds "no effect" and you don't ship a change that would have genuinely helped users. Power analysis answers a single question — how many users do I need? — and requires four inputs you should know before touching any data: baseline conversion rate, minimum detectable effect (the smallest lift you'd actually care about), significance level (α, usually 0.05), and desired power (1−β, usually 0.80).

These four inputs produce a required sample size per group. The practical failure: teams skip this step, run a test for one week because that feels right, and conclude "no effect" from a sample that was never large enough to detect one. An underpowered non-result is not a result.

MDE is a business decision, not a statistical oneThe minimum detectable effect should be set based on what lift is actually worth shipping. A 0.01pp improvement may not justify engineering time; a 0.5pp improvement might. Set it before the experiment — not after you see the data.

3. P-hacking and multiple comparisons

You designed the experiment to measure purchase rate. But your dashboard shows 15 metrics. Three are significant. You report those. This is p-hacking — not necessarily malicious, but statistically identical to running 15 experiments and showing the best result. At α=0.05, you expect one false positive for every 20 tests by pure chance. With 15 metrics, the probability of at least one spurious significant result is around 54%.

The fix: pre-register your primary metric before the experiment starts. That's the one that drives the shipping decision. Secondary metrics are exploratory — they generate hypotheses for future tests, not conclusions from this one. When you do need to test multiple metrics formally, apply Bonferroni correction (divide α by the number of tests) or Benjamini-Hochberg (controls false discovery rate, less conservative). Your analysis plan should exist before you see the data.

4. Novelty effects — users responding to change, not improvement

Your new design shows a 3pp lift in week one. You ship it. Two months later, conversion is back to baseline. What happened: users clicked the new design because it was different — not because it was better. The novelty wore off. The A/B test captured a real short-term effect that wasn't the long-term effect you cared about.

Novelty effects are most common with UI changes — new layouts, colors, navigation patterns — and less common with structural changes like pricing or checkout flow, where users engage with the mechanism rather than noticing something different. The diagnostic: segment your treatment effect by how long a user has been in the experiment. If new entrants show a large effect and users who've been in the test for two or three weeks show near zero, you're likely measuring novelty. The fix is usually to run the experiment longer — but this requires having done the power analysis first, so you knew how long "long enough" was before you started.

The common threadAll four failures produce a number that looks like a causal estimate but isn't one. Peeking gives you false positives. Insufficient power gives you false negatives. P-hacking gives you cherry-picked results. Novelty gives you a transient effect mistaken for a permanent one. The gold standard is only gold if the execution matches the design.

What you should take from Phase 1

Randomization is the only method that requires no assumptions about confounders — because it eliminates them by design. Every other method in this series is an attempt to approximate randomization when it's unavailable. DiD uses time variation. PSM uses observed covariates. Synthetic Control uses donor units. RD uses a threshold. Each approach makes a different assumption, and each assumption can be tested — but none of them is as clean as what you built here.

The discomfort you felt in the "broken experiment" cell — that feeling of not knowing whether your estimate is real — is what motivates the next four phases.

Next: Phase 2 — Difference-in-DifferencesThe LaLonde dataset has no randomization. Workers self-selected into training. But we have earnings data from before and after the program — and a comparison group that didn't receive training. If the two groups would have trended the same way without treatment, we can difference out the selection bias. That's DiD.

View full notebook on GitHub → Read on Medium →

Difference-in-Differences: When Time Becomes Your Control Group

The LaLonde job training dataset has a known true effect of $1,794. The naive comparison gives answers ranging from −$8,000 to +$2,000 depending on the approach. DiD uses the time dimension to get closer to the truth — under one testable assumption.

The dataset that broke observational methods

In 1986, Robert LaLonde published a paper evaluating the JTPA job training program. He had data from a genuine RCT — workers randomly assigned to training or not — and published the true treatment effect: $1,794 increase in annual earnings.

Then he replaced the randomized control group with workers from the PSID survey — real workers who hadn't been trained, but hadn't been randomly assigned to anything. He asked: what does the naive observational comparison give you? The answers swung from −$8,498 to +$2,249. The true effect was $1,794. This dataset became the benchmark every causal method is tested against.

"The PSID control group earns $13,000/year before training. The treated group earns $2,000/year. You're not comparing two groups — you're comparing two different economic realities."

Why the naive comparison fails

Workers who enrolled in training were younger, less educated, earned far less, and were economically disadvantaged before any training occurred. Comparing their 1978 earnings to the PSID workers confounds the training effect with an $11,000 pre-existing gap. Selection bias here isn't subtle — it's the entire signal.

Earnings trends 1974-1978 for treated and control groups
Figure 4. Left: DiD visualization — the dashed line is the parallel-trends counterfactual. The vertical bracket at 1978 is the DiD estimate. Right: 3-period view (1974, 1975, 1978) showing the pre-existing $11,000 earnings gap that naive comparison conflates with the training effect.

The DiD formula

Instead of comparing earnings levels, compare earnings changes. If the control group grew by $X between 1975 and 1978 due to macroeconomic forces, the treated group should have grown by the same $X without training. Any additional growth is the training effect.

DiD = (Treated₁₉₇₈ − Treated₁₉₇₅) − (Control₁₉₇₈ − Control₁₉₇₅)

In regression form: earnings ~ post + treat + post:treat. The coefficient on post:treat — the interaction — is the DiD estimate. It captures the additional earnings change for treated workers in the post-period, above and beyond what control workers experienced.

The parallel trends assumption

DiD works under one assumption: in the absence of treatment, the treated group's earnings would have followed the same trend as the control group. Not the same level — the same slope. The dashed line in Figure 4 is that counterfactual. You never observe it. You can only make it plausible.

Testing it: the pre-trends test

We have earnings from 1974 and 1975, both pre-treatment. Under parallel trends, the two groups should have moved similarly between these years. We run DiD on 1974→1975 only — treating 1975 as the "post" period and ignoring 1978. The interaction coefficient should be near zero and statistically insignificant. A large, significant pre-trend coefficient means the groups were already diverging before training — the assumption is in trouble.

DiD results: pre-trends test, decomposition, and method comparison
Figure 5. Left: pre-trends test (1974→1975) — the interaction should be near zero. Center: DiD decomposition showing the counterfactual and the estimated gap. Right: estimates compared to the LaLonde RCT benchmark of $1,794.

What breaking parallel trends looks like

The notebook adds $3,000 to the control group's 1978 earnings — simulating a macroeconomic boom that hit PSID workers harder than the disadvantaged treated group. The DiD estimate drops: treatment looks less effective than it was. The direction of bias depends entirely on how the assumption is violated. There is no way to know the direction from data alone — which is exactly why the pre-trends test exists.

Key resultDiD estimates land in the $1,200–$2,000 range across specifications — meaningfully closer to the $1,794 benchmark than the naive comparison's swing from negative to wildly positive. The pre-trends test result tells you how much confidence to place in the design.

What DiD leaves unsolved

DiD required panel data — the same workers observed before and after. It also required a control group that trends in parallel, which is genuinely hard to defend with the PSID comparison. What if you only have a single cross-sectional snapshot? What if there's no pre-period available? You need a different strategy — one that constructs a comparable control group directly from covariate information rather than from time variation.

Next: Phase 3 — Propensity Score MatchingSame LaLonde data, no panel structure needed. We estimate each worker's probability of receiving training given their characteristics, then match treated and control workers with similar probabilities. The matched pairs are comparable — and the average outcome difference is the ATT.

View full notebook on GitHub →    Read on Medium →

Propensity Score Matching: When the Method Tells You It Can't Help

We ran PSM on two versions of the LaLonde dataset — same treated workers, different control groups. On the first, the method failed completely and told us so. On the second, it worked marginally with documented limitations. That two-path result is the real lesson.

The prerequisite nobody emphasizes: overlap

Before matching a single pair, the propensity score model's AUC tells you whether matching is even possible. AUC 0.6–0.85 means the groups overlap enough to match. AUC above 0.95 means near-perfect separation — the groups are from fundamentally different populations and no algorithm can bridge that gap.

"A propensity model with 0.98 AUC isn't telling you the model is good — it's telling you the groups are incomparable. PSM correctly detected its own inapplicability."

Path A: PSID controls — correctly flagged as inapplicable

The PSID control workers average 34 years old with $13,000/year pre-training earnings. The treated workers average 25 years old with $2,000/year. The logistic propensity model achieves AUC ~0.98 on this combined dataset. The overlap plot shows two completely separated spikes. We documented the failure and moved on — running the matching anyway would have produced a meaningless number.

PSID overlap plot — near-complete separation, PSM inapplicable
Figure 6. Path A — PSID control group. The propensity score distributions for treated (red) and control (blue) workers are almost completely separated. AUC ~0.98. The common support region is a sliver. PSM is not applicable on this dataset.

Path B: CPS controls — borderline, documented

The CPS-3 trimmed control group (429 workers) is closer to the treated workers demographically. AUC is lower — borderline acceptable. The distributions share a meaningful common support region. Matching is feasible but some treated workers are dropped by the caliper. We document exactly how many and note that the ATT estimate applies only to the matchable subgroup.

Love plot — covariate balance before and after matching on CPS group
Figure 7. Love plot — CPS control group. Red circles show SMD before matching; blue diamonds after. Matching improves balance substantially, particularly on prior earnings (re74, re75). Some residual imbalance remains — the OLS adjustment on the matched sample partially corrects for this.
Phase 3 full results — paired differences, overlap comparison, estimates, Rosenbaum bounds, balance
Figure 8. Five-panel summary. Top center shows both control group overlaps side by side — PSID (red, AUC ~0.98, fail) vs CPS (green, borderline). Top right shows estimates vs the $1,794 RCT benchmark. Bottom left: Rosenbaum bounds, included as supplementary given residual imbalance. Bottom right: full covariate balance comparison.
On KNN memory at scalesklearn's NearestNeighbors indexes the control propensity scores — O(n_control) memory in 1D. Fine for LaLonde. At millions of controls or when matching on raw covariates in high dimensions, this blows up. Solutions: approximate nearest neighbors (FAISS, Annoy), stratification on PS deciles, or coarsened exact matching (CEM). This is one reason PS-based methods are preferred over direct covariate matching — keeping the problem in 1D prevents the dimensional blowup.
On the Rosenbaum boundsWe include them but scope them carefully. Rosenbaum bounds are most interpretable when matching achieved clean balance. Here, some residual imbalance remains. Reporting the bounds as primary robustness evidence would overclaim — they are supplementary context on a borderline dataset.
Next: Phase 4 — Inverse Probability WeightingIPW uses the same propensity scores but keeps every observation. Instead of matching and discarding, it reweights controls by how "treated-like" they are: w = e(X)/(1−e(X)). Treated units keep weight 1. Estimand is ATT — directly comparable to the $1,794 benchmark. Result: ATT = $1,212 on the full 185 treated workers, narrower CI than PSM's 83-pair estimate.

View full notebook on GitHub →    Read on Medium →

Reweighting Instead of Discarding: Inverse Probability Weighting

PSM dropped 102 of 185 treated workers and produced an estimate too noisy to use. IPW keeps every observation — reweighting the control group to look like the treated group. Same propensity model, entirely different strategy, and the best observational ATT estimate in the series so far: $1,212 against a benchmark of $1,794.

What PSM left unsolved

In Phase 3, the caliper matching algorithm matched 83 of 185 treated workers. The other 102 were dropped. The matched sample was too small to detect a $1,794 effect — SE ~$990, CI spanning $4,000, p-value above 0.6. The failure was not hidden confounding. It was data loss from a lossy matching operation.

IPW keeps every observation. Instead of finding a close match and discarding workers without one, it reweights the control group. Controls who look like the treated workers get upweighted; controls who look nothing like them get downweighted. No one is dropped.

Why ATT and not ATE

IPW is often described as naturally estimating the ATE — historically, because the Horvitz-Thompson (1952) estimator came from survey sampling where population-level inference was the goal. But for this problem, ATT is the right estimand.

The LaLonde RCT benchmark of $1,794 is an ATT: the effect on workers who actually enrolled in job training. ATE would measure the hypothetical effect if training were extended to the full CPS population — workers who would never realistically enroll, with different earnings histories and labor market attachment. We have no ground truth to compare an ATE against. ATT is the headline; ATE appears at the end of the notebook as a secondary result with its own interpretation.

The ATT weight formula: treated units keep weight 1. Control units get weight e(X) / (1 − e(X)) — how "treated-like" they are based on their propensity score. The reweighted control group becomes a synthetic comparison population that mirrors the treated group's covariate distribution.

Two control groups, two different stories

Same structure as Phase 3: two paths, one honest. Baseline imbalance tells the story before any reweighting.

CovariateSMD (Full CPS)SMD (CPS-3)
age−0.671−0.224
educ−0.5860.042
black2.8001.309
married−1.147−0.656
re74−1.240−0.544
re75−1.301−0.284
Mean |SMD|1.0870.443
AUC0.9710.874

Full CPS AUC = 0.971: near-perfect separation. The propensity model can almost perfectly predict who was in the training program just from demographics. IPW weights will be extreme. CPS-3 AUC = 0.874: borderline but workable.

Overlap plot: CPS-3 vs Full CPS propensity score distributions
Figure 9. Propensity score distributions. Left: CPS-3 — moderate overlap, green region shows common support. Right: Full CPS — control scores cluster near 0, treated near 1. Near-zero overlap means ATT weights e(X)/(1−e(X)) collapse toward zero for all controls, making any Full CPS estimate meaningless.

The ESS diagnostic

Before looking at any estimates, check the Effective Sample Size: ESS = (Σw)² / Σw². ESS tells you how many observations are actually contributing information, expressed as an equivalent unweighted sample size.

DatasetEstimatorNESSESS %
CPS-3HT (raw)61422736.9%
CPS-3Stabilized61435657.9%
CPS-3Trimmed61444672.6%
Full CPSHT (raw)16,1771490.9% ⚠
Full CPSStabilized16,17715,60696.5%
Full CPSTrimmed16,17716,177100.0%

The Full CPS rows reveal a subtlety. Raw HT weights collapse ESS to 149 (0.9%) — a single observation with weight 1,261 dominates. After stabilizing and trimming, ESS recovers to near-100%. But look at the Full CPS trim bounds: [0.989, 1.007]. Trimming forced all weights toward 1.0, stripping out any meaningful reweighting. The estimate becomes noise in a different way — not one observation dominating, but every observation treated equally despite massive covariate differences.

CPS-3 trimmed ESS of 446 (72.6%) is healthy. The reweighting is doing real work without any single observation dominating.

IPW weight distributions before and after trimming
Figure 10. ATT control weight distributions e(X)/(1−e(X)) before and after trimming. CPS-3 (top): trimming tames a moderate tail. Full CPS (bottom): untrimmed weights reach 1,261; after trimming, all weights collapse to [0.989, 1.007] — the reweighting is effectively neutralized.

Covariate balance after reweighting

IPW reduced mean |SMD| from 0.443 to 0.186 on CPS-3 — a 58% reduction. But several covariates remain above the 0.1 threshold:

CovariateBefore IPWAfter IPW
age0.2240.173⚠
educ0.0420.083✓
black1.3090.328⚠
hisp0.2570.068✓
married0.6560.379⚠
nodegree0.2310.030✓
re740.5440.306⚠
re750.2840.120⚠
Mean0.4430.186↓ 58%

Race, marital status, and prior earnings remain meaningfully imbalanced — the same variables that troubled PSM. A logistic propensity model with linear terms can't fully bridge the structural differences between NSW participants and CPS workers. This is a data problem, not a method problem.

Love plot: covariate balance before and after IPW reweighting
Figure 11. Love plot: before IPW (circles) vs after trimmed IPW (diamonds). CPS-3 (left): most covariates improve, five remain above |SMD|=0.1. Full CPS (right): balance improves numerically but the trim-to-flat weights make the result uninterpretable.

Results

Full results: ATT estimates, ESS, Love plot, CI comparison
Figure 12. Full results dashboard. Top-center: ATT estimates vs $1,794 benchmark — IPW trimmed ($1,212) is the closest observational estimate so far. Bottom-right: 95% CI comparison shows IPW's dramatically narrower interval vs PSM's $4,000-wide CI on 83 pairs.
MethodDatasetATT Estimate95% CIvs $1,794
Naive diffCPS-3−$635—wrong sign
PSM (Phase 3)CPS-3$123–$468[−$1,819, $2,064]68% off
IPW trimmedCPS-3$1,212[−$141, $2,718]68% recovery
AIPW (DR)CPS-3$476[−$1,132, $2,084]27% recovery
IPW trimmedFull CPS−$1,021[−$2,075, $127]wrong sign
AIPW (DR)Full CPS−$4,264[−$5,630, −$2,898]wrong sign
True ATT (RCT)—$1,794—benchmark

"IPW trimmed ATT = $1,212. The CI [−$141, $2,718] barely clips zero, but the point estimate recovers 68% of the $1,794 benchmark using all 185 treated workers. PSM recovered at most 26% on 83 pairs."

Why AIPW performed worse than raw IPW

The AIPW estimate of $476 is substantially worse than trimmed IPW's $1,212. This deserves a direct explanation.

AIPW is doubly robust: consistent if either the propensity model or the outcome regression model is correctly specified — not both. The outcome model here is OLS linear regression on re78. Earnings are highly right-skewed with a spike at zero — linear regression predicts poorly, especially for treated workers with zero prior earnings. When the outcome model is misspecified, the AIPW augmentation terms — designed to correct for propensity model errors — add noise instead. The result is a higher-variance estimate that moves further from the benchmark.

This is not a failure of the method. It is a demonstration of what "doubly robust" actually means: one model must be correct, not neither. Phase 7 (Double ML) will use flexible nonlinear outcome models that can handle skewed earnings — which is precisely why DML tends to outperform AIPW with linear nuisance models.

Key takeawayIPW used all 185 treated workers and produced ATT = $1,212 — the best point estimate of the series so far. The CI barely clips zero. The improvement over PSM ($123–$468, n=83) is directly traceable to the larger effective sample. Overlap is still the binding constraint: Full CPS fails completely, for the same reason PSM failed in Phase 3. IPW doesn't fix overlap; it just measures the damage differently — through ESS collapse rather than sample discard.
Next: Phase 5 — Synthetic ControlSynthetic Control abandons individual-level reweighting entirely. It works at the aggregate level: one treated unit (a state), a panel of donor states, and a weighted combination that matches the pre-treatment earnings trajectory. Designed for small N, large T — the opposite data regime from LaLonde. We simulate a state-level policy panel to demonstrate it.

View full notebook on GitHub →    Read on Medium →

Synthetic Control: Building a Counterfactual State

One treated state, 20 donors, true effect of $1,500. ATT = $1,521. Pre-period RMSPE = $353 (1.68% of mean). RMSPE ratio 4.36. Permutation p = 0.000. This is what causal inference looks like when the method fits the data regime.

A completely different data regime

Every phase from 2 through 4 operated on the LaLonde data: many treated units, many control units, estimate an average individual-level effect. Synthetic Control is designed for the opposite: N_treated = 1. One state, one firm, one country. You cannot run IPW or PSM on a single treated unit — there is no distribution to reweight.

Instead, Synthetic Control asks: can we find a weighted combination of untreated states whose pre-treatment income trajectory matches the treated state's history? If yes, that combination — the synthetic control — is the counterfactual. The post-treatment gap between the treated state and its synthetic version is the treatment effect.

Constrained quadratic programming

Find weights W = (w₁, …, w_J) minimizing the pre-period prediction error, subject to wⱼ ≥ 0 and Σwⱼ = 1. The constraints force a convex combination of real donor states — no negative weights, no extrapolation beyond the observed data. OLS would allow negative weights that have no meaningful interpretation as a "weighted average of states."

Six of 20 donors received non-zero weights. The top three — donor_16 (30.4%), donor_2 (29.8%), donor_18 (25.2%) — account for 85% of the synthetic state. The remaining 14 received weight zero. This sparsity is expected: a synthetic control that spreads weight across all donors is harder to interpret and risks overfitting pre-period noise.

Pre-period fit: treated state vs synthetic control
Figure 13. Pre-period fit: treated state (red) vs synthetic control (blue dashed). Left: full 30-period timeline with treatment at t=21 (shaded). Right: pre-period only with residual gap shaded. RMSPE = $353 — 1.68% of the treated state's pre-period mean. The synthetic control tracks the treated state closely with no systematic drift.

The gap plot

Pre-period (t=1–20): gap hovers near zero. The synthetic control is tracking the treated state on its own dynamics. Post-period (t=21–30): gap opens sharply and stabilizes around $1,500. Average post-period gap = $1,521. True embedded effect = $1,500.

Gap plot: treated minus synthetic control
Figure 14. Gap = treated − synthetic, period by period. Pre-period gap near zero confirms fit quality. Post-period gap (green shaded) averages $1,521 against a true effect of $1,500. The green dashed line is the ATT estimate; the orange dotted line is the true effect.

Placebo-in-time

Pretend treatment happened at t=10, t=13, and t=16. The placebo ATTs were −$115, −$236, and −$166. All small. No spurious pre-period effects appear at any false treatment date. The divergence is concentrated at the actual treatment date, not distributed across the pre-period.

Placebo-in-space: inference without distributional assumptions

Apply the same Synthetic Control procedure to each donor state. Compute the post/pre RMSPE ratio for each. The treated state's ratio = 4.36. The post-period gap grew to 4.36 times the pre-period noise level. 19 of 20 donor placebos were valid (one excluded for poor pre-fit). None came close to 4.36.

Placebo-in-space: gap series and RMSPE ratio distribution
Figure 15. Left: all gap series — treated state (red) vs donor placebos (grey). The treated state's post-treatment divergence is visually distinct. Right: post/pre RMSPE ratio distribution. Treated state ratio of 4.36 (red line) sits far to the right of all donor placebos. Permutation p-value = 0.000.
MetricValue
True ATT (embedded)$1,500
ATT estimate$1,521 (101.4% recovery)
Pre-period RMSPE$353 (1.68% of mean)
Post/Pre RMSPE ratio4.36
Permutation p-value0.000
Non-zero donors6 of 20
Valid placebos19 of 20

"The synthetic state is not an abstract statistical adjustment. It is a named, weighted combination of real donor states — donor_16, donor_2, donor_18 and three others — whose pre-treatment history matches the treated state's. You can look at those six states and ask whether they make sense as a comparison group."

Next: Phase 6 — Regression DiscontinuitySynthetic Control required a long pre-treatment time series and a panel of donor units. RDD requires neither. It exploits a sharp discontinuity in treatment assignment: units just above a score threshold receive treatment, units just below do not. The estimand is LATE — the Local Average Treatment Effect at the threshold. We simulate a scholarship cutoff dataset.

View full notebook on GitHub →    Read on Medium →

Regression Discontinuity: The Value of a Threshold

Naive estimate = $6,765 (badly biased by the ability confound). Local linear RDD LATE = $2,587 against a true LATE of $2,500. t = 10.33. No model for confounders needed — the threshold does the work.

Identification without a confounder model

Every method so far handled confounding by adjusting for observed covariates. RDD requires no such adjustment. Students just above and just below score 70 are nearly identical — the only thing that changes discontinuously at the threshold is the scholarship. The jump in outcomes at that point is the causal effect, regardless of what unobserved factors drive earnings.

The identification assumption: potential outcomes are continuous at the cutoff. Nothing else jumps at score 70. The McCrary density test checks whether students can manipulate their score to land just above the threshold.

Why the naive estimate is so wrong

The raw mean difference is $6,765 against a true LATE of $2,500 — biased upward by $4,265. Higher-scoring students earn more regardless of the scholarship, through ability, effort, and learning. RDD strips this out by comparing only students within a narrow band around the cutoff, where the ability distribution is effectively continuous.

Bandwidth: the central tradeoff

Cross-validation (LOO-MSE on each side separately) selected h = 18.45 score points — students scoring 51.6 to 88.5. That's 1,663 of 2,000 observations: 1,082 controls, 581 treated. Narrow bandwidth reduces bias; wide bandwidth reduces variance. CV finds the MSE-minimising balance.

RD plot
Figure 15. RD plot within h=18.45. Binned means (dots) and fitted local linear lines on each side. The green arrow shows the jump at score=70 — the LATE estimate of $2,587.
Bandwidth sensitivity
Figure 16. LATE estimates across bandwidths h=5 to h=35, local linear (left) and local quadratic (right). Estimates cluster near $2,500 across the full range with overlapping CIs — the result is not bandwidth-specific.
MethodLATE95% CIt-stat
Naive mean diff$6,765——
Local linear (h=18.45)$2,587[$2,096, $3,078]10.33
Local quadratic (h=18.45)$2,893——
True LATE$2,500benchmark—

The McCrary test: a false positive

The McCrary density test returned p = 0.000. In a real study this would be a stop signal. Here it is a false positive from our simplified implementation: scores simulated as normal(65, 12) produce a curved density near the cutoff, and our bin-based local linear fit misreads the curvature as a jump. A proper implementation (rddensity in R) uses local polynomial density estimation that handles this. The notebook documents the limitation explicitly.

Next: Phase 7 — Double MLRDD worked on a clean threshold dataset. Phase 7 returns to LaLonde. AIPW in Phase 4 failed because the linear outcome model misfitted skewed earnings. Double ML replaces it with gradient boosting — flexible nonlinear nuisance models that can handle the earnings distribution, with a Neyman-orthogonal score ensuring parametric convergence rates.

View full notebook →    Read on Medium →

Double ML: Partialling Out Confounders with Gradient Boosting

Phase 4's AIPW estimated ATT = $476 — worse than raw IPW's $1,212 — because OLS misfitted skewed earnings and the doubly-robust augmentation amplified the error. DML ATT = $1,499 (83.6% recovery). CI crosses zero. The point estimate is the best in the series. The uncertainty is honest.

Why AIPW failed and what DML does differently

AIPW's doubly-robust correction assumes the outcome model E[Y|X] is at least partially well-specified. Phase 4 used OLS on re78 — 1978 earnings, right-skewed with a mass at zero. OLS predicted negative earnings for some workers and missed the right tail systematically. The correction term amplified the misspecification instead of absorbing it. ATT fell to $476 despite IPW trimmed reaching $1,212.

DML fixes this at the root. The Robinson (1988) partialling-out estimator residualises both outcome and treatment on the same covariate set: Ytilde = Y − E[Y|X] strips confounding variation from earnings; Dtilde = D − E[D|X] strips it from the treatment indicator. The causal effect theta is recovered from the regression of Ytilde on Dtilde — a regression in residual space where all confounders are gone. Replace E[Y|X] with GradientBoostingRegressor and E[D|X] with GradientBoostingClassifier, and the outcome misspecification problem disappears by construction.

Cross-fitting and Neyman orthogonality

Fitting nuisance models on the same data used for estimation introduces overfitting bias: the learner memorises individual residuals, shrinking Ytilde and Dtilde toward zero and biasing theta. Cross-fitting prevents this. With K=5 folds, each observation's nuisance predictions come from a model trained on the other four folds — genuinely out-of-sample. The Neyman-orthogonal score provides an additional guarantee: small errors in E[Y|X] or E[D|X] have only second-order impact on theta, so the causal estimate converges at parametric rates even though GBM converges more slowly.

Mean outcome RMSE across folds: $7,179. Mean propensity AUC: 0.916. Residual means near zero (Ytilde: −73, Dtilde: 0.008) confirm the nuisance models are well-behaved.

DML diagnostics
Figure 17. DML nuisance diagnostics (CPS-3, Path B). Top-left: Dtilde distribution centred at zero — treatment residual signal is present and symmetric. Top-right: GBM propensity score overlap — common support region in green. Bottom-left: Ytilde vs Dtilde residual scatter — the PLR slope is the causal effect. Bottom-right: per-fold RMSE and AUC — stable across all 5 folds.

ATT via propensity-weighted PLR

The base Robinson estimator recovers ATE. To target ATT — the effect on workers who actually received training — each observation's contribution to the moment condition is reweighted by e(X) = P(D=1|X). Units in regions of covariate space where no treated workers live receive near-zero weight; treated-like units are up-weighted. This is the same estimand as PSM (Phase 3), IPW (Phase 4), and AIPW (Phase 4) — all results are directly comparable to the $1,794 RCT benchmark.

MethodATT95% CIRecovery
Naive mean diff———
PSM (Phase 3)$300[−$1,819, +$2,064]17%
IPW trimmed (Phase 4)$1,212[−$141, +$2,718]68%
AIPW (Phase 4)$476[−$1,132, +$2,084]27%
DML ATT (Phase 7)$1,499[−$492, +$3,519]83.6%
True ATT (RCT)$1,794benchmark100%

The Full CPS precision trap

Path A (Full CPS, 15,992 controls) produced ATT = $1,846, SE = $795, p = 0.020 — statistically significant, closer to the benchmark. A researcher without overlap diagnostics would use it. This would be a mistake.

With AUC = 0.977, GBM near-perfectly separates treated from control workers. The propensity-weighted moment condition concentrates on a handful of controls near the overlap boundary — ESS = 375 of 16,177 (2.3%). Mean |Dtilde| = 0.013 vs 0.194 for CPS-3: treatment signal is 15x weaker. The SE appears tight because N = 16,177 mechanically compresses it, not because identification is credible. The p-value measures precision about a non-representative boundary stratum, not the treated subpopulation. CPS-3's p = 0.127 is the honest answer.

DML results
Figure 18. DML results (CPS-3, Path B). Top-left: bootstrap distribution of ATT (500 draws). Top-right: cross-series ATT comparison — PSM, IPW, AIPW, DML vs $1,794 benchmark. Bottom-left: residual-on-residual scatter with PLR slope. Bottom-right: covariate balance before and after DML propensity weighting.

Propensity trimming as a robustness check

Trimming at e(X) ≥ 0.05, 0.10, 0.15 and re-running PLR ATT confirmed two things. First, the point estimate is stable: $1,496, $1,527, $1,486 — all within 2% of the untrimmed $1,499, confirming the trimmed observations were near-zero weight and contributed noise rather than information. Second, the CI crosses zero at every threshold. Sample size is the binding constraint, not low-propensity noise. Trimming confirms the result rather than rescuing it.

"The wide confidence interval is not a failure of DML. It is the correct answer given 185 treated workers and borderline overlap. DML recovered 83.6% of the $1,794 benchmark — the best point recovery in the series — but it cannot manufacture sample size. The uncertainty is real."

Next: Phase 8 — Causal Inference at Scale (DoWhy + EconML) Every phase so far answered one question with one method on one dataset. Phase 8 is the capstone: the 401(k) eligibility dataset, two estimand questions (ATE and ATT) answered simultaneously, and a comparative study across DoWhy DAG-based identification, EconML DML, CausalForest, and MetaLearners. Methods that don't work on this data are documented alongside those that do.

View full notebook on GitHub →    Read on Medium →

Causal Inference at Scale: A Comparative Study with DoWhy and EconML

Every prior phase answered one question with one method on one dataset. This phase breaks that formula: the 401(k) eligibility dataset (n=9,915), two estimand questions answered simultaneously, seven methods compared. Mean ATE ≈ $7,594 (84% of the $9,000 Chernozhukov benchmark). Mean ATT ≈ $9,166. The naive estimate — $19,559 — is more than double the truth.

The dataset

The 401(k) eligibility data is the standard DML benchmark, from Chernozhukov et al. (2018) — the paper that introduced the method used in Phase 7. Treatment is e401, employer-provided 401(k) eligibility. Outcome is net_tfa, net total financial assets. Seven covariates: age, income, family size, education, marital status, two-earner status, and IRA participation.

The naive comparison — mean assets for eligible vs ineligible workers — gives $19,559. This is badly confounded. Income has a standardised mean difference of 0.620 between groups: workers with employer-sponsored 401(k) plans are systematically higher earners, and higher earners save more regardless of eligibility. Three more covariates (education, two-earner status, IRA participation) exceed the 0.1 imbalance threshold. Unlike LaLonde, though, overlap here is good — propensity AUC = 0.699, effective sample size after weighting = 86.0% of the full data. Every method in this phase operates on genuinely overlapping populations, in contrast to the chronic overlap problems of Phases 3–7.

Two questions, answered simultaneously

This is the first phase to estimate both estimands on the same data and compare them directly.

ATE — "What is the effect of 401(k) eligibility on financial assets for a randomly drawn person in this population?" This is the question a regulator asks when considering universal eligibility.

ATT — "What is the effect for workers who are actually eligible?" This is the question an employer asks when considering whether to keep offering a plan.

The two estimands should differ here, and they do. Eligible workers are higher-income on average, and higher income means greater capacity to convert eligibility into actual savings. The mean ATT–ATE gap across methods is $1,572 — ATT exceeds ATE in every method except one, for a reason explained below.

Methods landscape: what works, what doesn't, and why

Before estimating anything, every major causal inference method from this series was assessed against this dataset. Four methods don't apply at all, one applies marginally, and five apply well.

MethodATEATTApplies?Why / why not
A/B testing✓✓NoEligibility isn't randomised — correlated with income, employer, industry
DiD✗✓NoSingle cross-section — no pre/post panel structure
Synthetic Control✗✓NoIndividual-level data — no donor panel of units
RDD✗✗NoEligibility is an employer decision, not a running-variable cutoff
PSM✗✓MarginalBetter overlap than LaLonde, but 7 continuous covariates degrade match quality; impractical at 100k+ obs
IPW✓✓YesOverlap sufficient (ESS 86%); used as DoWhy's baseline
DML / PLR✓✓YesLarge N, skewed outcome, nonlinear confounding — ideal conditions
CausalForest✓✓Yesn=9,915 supports reliable CATE estimation — too small at LaLonde's n=614
MetaLearners (T/S/X)✓✓YesX-Learner suited to the moderate group imbalance (5,908 vs 4,007)
DoWhy backdoor✓✓YesMakes unconfoundedness explicit via DAG; refutation-tested
Phase 8 diagnostics
Figure 19. Covariate balance and overlap. Left: SMD per covariate — income (0.620), two-earner status (0.340), education (0.314), and IRA participation (0.278) all exceed the 0.1 threshold. Right: propensity score overlap (AUC=0.699) — substantial common support, in contrast to LaLonde's AUC=0.916–0.977.

DoWhy: making the assumption explicit, and where it falls short

The DAG declares all seven covariates as confounders — each affects both eligibility and assets. The backdoor criterion identifies the estimand as conditioning on all seven. Three refutation tests were run on the resulting estimate: a placebo treatment (replacing eligibility with a random binary variable) collapsed the effect from $5,028 to $249 — the identification strategy is not picking up noise. A random common cause left the estimate at $5,026 — robust to irrelevant confounders. An 80% data subset reproduced $5,028 exactly — stable across resampling. All three passed.

And yet $5,028 is the lowest ATE estimate of all seven methods, recovering only 56% of the $9,000 benchmark — well below DML's 91%. The refutation tests validate the identification strategy (conditioning on these seven covariates blocks the relevant backdoor paths). They say nothing about the functional form. DoWhy's backdoor estimator here is linear regression — a single coefficient on treatment, assumed constant across the population. Income's relationship to both eligibility and assets is nonlinear; a linear model partially absorbs this nonlinearity into the treatment coefficient, biasing it toward zero. This is also why DoWhy reports identical ATE and ATT ($5,028 = $5,028): a single linear coefficient cannot represent two different population averages. The identification was sound. The estimator was too rigid for the data.

DML: replacing the linear core

LinearDML and NonParamDML use the same Robinson partialling-out structure as Phase 7, with GBM nuisance models and 5-fold cross-fitting — but applied to a dataset where overlap is healthy and N is large enough for the asymptotics to do real work.

LinearDML: ATE = $8,185, 95% CI [$6,235, $10,135], 90.9% recovery. ATT = $10,716, 95% CI [$8,801, $14,043]. NonParamDML: ATE = $8,052 (89.5% recovery), ATT = $10,312. Both land close to the $9,000 benchmark, both show ATT meaningfully exceeding ATE, and both have CIs that do not cross zero — a sharp contrast to Phase 7's LaLonde result, where the same machinery produced a CI crossing zero. The difference is not the method. It's the data: n=9,915 with AUC=0.699 versus n=614 with AUC=0.916.

New concept: CausalForest and heterogeneous effects (CATE)

Every method up to this point produces one number per estimand. CausalForest produces one number per person: tau(X_i), the conditional average treatment effect — how much net_tfa changes for someone with this specific age, income, education, and family situation.

CausalForest's ATE = $8,369 and ATT = $11,238 — both consistent with the DML estimates. But the underlying CATE distribution is the more interesting result: mean $8,369, median $5,662, standard deviation $9,605, with the 10th percentile at $642 and the 90th percentile at $20,831. The effect is heavily right-skewed — most workers see a modest boost from eligibility, while a smaller group sees a very large one. Feature importance attributes 77.5% of this heterogeneity to income alone, with age a distant second (12.3%) and every other covariate below 6%.

This matches intuition: a worker with little disposable income can't convert "eligibility" into "more savings" — there's nothing to redirect. A higher earner with slack in their budget can. The treatment effect isn't a constant to be estimated; it's a function of income, and CausalForest is the first method in this series built to recover that function rather than average it away.

One caveat: CausalForest's analytic ATE confidence interval is [−$8,550, $25,288] — extremely wide, crossing zero despite a point estimate of $8,369 close to every other method. This is a known property of forest-based analytic inference with high-variance leaves; it does not indicate the estimate itself is unreliable (CausalForest's ATT, using a bootstrap CI, is tight: [$9,053, $14,000]). It's a reminder that analytic and bootstrap CIs from the same model can disagree substantially, and both should be reported.

CATE distribution
Figure 20. CausalForest heterogeneous effects. Left: CATE distribution across all 9,915 workers — right-skewed, median ($5,662) well below mean ($8,369). Right: mean CATE by income decile — the effect rises sharply with income, consistent with income explaining 77.5% of feature importance for heterogeneity.

MetaLearners: S, T, and X

S-Learner (one model, treatment as a feature): ATE = $7,495, ATT = $8,183 — the smallest ATT–ATE gap ($688) of any method, consistent with S-Learner's known tendency to shrink heterogeneity toward zero when treatment has a weaker signal than covariates. T-Learner (separate models per group): ATE = $8,011, ATT = $9,132. X-Learner (cross-imputation, suited to the 5,908-vs-4,007 group imbalance): ATE = $8,015, ATT = $9,552 — the closest MetaLearner match to the DML and CausalForest cluster.

Comparative results: seven methods, two estimands

MethodATEATTATT − ATE
DoWhy backdoor$5,028$5,028$0 (forced equal — linear)
S-Learner$7,495$8,183$688
T-Learner$8,011$9,132$1,122
X-Learner$8,015$9,552$1,537
NonParamDML$8,052$10,312$2,260
LinearDML$8,185$10,716$2,531
CausalForest$8,369$11,238$2,869
Mean (all methods)$7,594$9,166$1,572
Benchmark (Chernozhukov 2018)$9,000——
Naive (unadjusted)$19,559——
Method comparison forest plot
Figure 21. All seven methods, both estimands, vs the $9,000 benchmark. Six of seven methods cluster between $7,495 and $8,369 for ATE — DoWhy's $5,028 is the outlier, explained by its linear functional form rather than a failure of identification. ATT estimates spread more widely ($5,028–$11,238), driven by genuine effect heterogeneity that flexible estimators capture and linear regression cannot.

Six of seven methods agree on ATE within a $874 band ($7,495–$8,369), all within 17% of the $9,000 benchmark. That convergence — across methods with genuinely different functional form assumptions — is the strongest evidence in this phase. DoWhy's outlier position is informative on its own: it isolates the cost of assuming a constant treatment effect on data where the effect is not constant.

"The naive estimate was $19,559 — more than double the truth. Confounding by income alone explained the entire gap. But fixing confounding wasn't enough: DoWhy's backdoor regression correctly identified the causal structure and passed every refutation test, yet still underestimated the effect by 44%, because it assumed the effect was the same for everyone. It isn't. CausalForest's CATE distribution — 10th percentile $642, 90th percentile $20,831 — is the real answer to 'what is the effect of 401(k) eligibility:' it depends who you ask."

Series retrospective

Eight phases, one underlying question — does an intervention change an outcome — answered with eight different identification strategies and an increasingly capable estimation toolkit. Three lessons recur across the series. First, identification precedes estimation: no estimator fixes a broken overlap assumption, as Phase 7's Full CPS precision trap demonstrated starkly. Second, the estimand is a choice: ATE and ATT are different questions with different answers whenever effects are heterogeneous, and this phase is the first to show that gap directly. Third, convergence across methods with different assumptions is stronger evidence than any single method's confidence interval — and divergence, as with DoWhy here, points to which assumption is being violated rather than which number is correct.

View full notebook on GitHub →    Read on Medium →