Causal Inference 05: Measuring One Experiment

Reading a lift test honestly is a skill, not a formality. Notebooks 00–04 pushed observational modeling as far as it goes and hit the same wall every time — a residual the data cannot settle, culminating in the latent-confounder wall of notebook 04. The cure is an experiment: randomization severs every back-door by construction. But an experiment only buys truth if it's read honestly — and the field is littered with lift tests that weren't. This page mirrors nbs/causal/causal_05_measuring_one_experiment.ipynb: Veranda Home, a national home & garden retailer, has ten test markets and wants to measure Search — the channel every observational rung kept over-crediting. Before a single dollar moves, three pieces of homework, all on pre-period data, all pure pandas — no MCMC, no MMM.

26%
naive false-positive rate of the "sophisticated" regression-adjusted estimator on null data (nominal: 5%)
5.2%
false-positive rate for all three estimators once the placebo-calibrated critical value is used
0.27
placebo-calibrated minimum detectable effect (ROAS), 5 matched pairs, 8-week holdout
100%
empirical power at the expected effect for both calibrated DiD estimators

The three failure modes this page is built to prevent: treatment markets picked by convenience (the big ones), not by matching; significance declared with a t-test whose assumptions the data violates; and estimators chosen after seeing the data, because one of them "found" lift. Every claim below is graded — the synthetic world's answer key stays sealed until the notebook's end.

1 — Ten markets, one question

The brand at DMA grain (the geo_heterogeneous world from src/mmm_framework/synth/): 10 markets × 130 weeks of weekly sales, each market with its own baseline, budget share, and — because this world is honest about geography — its own true regional effectiveness. The question: what is Search's incremental ROAS, really?

2 — Design: matched pairs, then a coin flip

geo_lift_design builds the treatment geometry a referee would accept:

The measured design: 5 matched randomized pairs (Boston–Atlanta, Dallas–Minneapolis, Denver–Chicago, Seattle–Portland, Miami–Phoenix), an 8-week holdout, design MDE ≈ 0.27 ROAS at a readout SE of 0.095.

from mmm_framework.planning.design import design_options, geo_lift_design
from mmm_framework.planning.simulation import (
    build_sim_panel, build_geo_assignment, run_aa_simulation,
    run_ab_simulation, fixed_lift_injector, methodology_leaderboard,
    pooled_did_estimator, per_pair_did_estimator, regadj_geo_estimator,
)

# 1. Design: matched randomized pairs + placebo-calibrated MDE
opts = design_options("veranda_geo.csv", "Sales", "Search")
design = geo_lift_design("veranda_geo.csv", "Sales", "Search",
                         design="holdout", duration=8, seed=42)

# 2. A/A: each estimator's REAL false-positive rate, measured on null windows
panel = build_sim_panel("veranda_geo.csv", "Sales", "Search")
assignment = build_geo_assignment(panel, seed=42)
aa = run_aa_simulation(panel, regadj_geo_estimator, assignment,
                       duration=8, seed=42, name="regression-adjusted")

# 3. A/B: inject known lifts into real history, measure empirical power
injector = fixed_lift_injector(panel, assignment, duration=8,
                               pct_of_baseline=0.10)
ab = run_ab_simulation(panel, pooled_did_estimator, assignment, injector,
                       duration=8, aa_result=aa, seed=42, name="pooled DiD")

# 4. One honest recommendation: validity first, then power, then cost
lb = methodology_leaderboard("veranda_geo.csv", "Sales", "Search",
                             duration=8, seed=42)

3 — The A/A discipline: test your test on nothing

Before trusting any estimator with a real experiment, run it on null data: 115 rolling windows in which no experiment happened, asking how often it cries "significant!" anyway. Weekly KPI series are autocorrelated — adjacent weeks share trend, season, and demand shocks — so the effective sample size is far below the nominal one, and naive standard errors are too small. Three candidate estimators, same frozen assignment. The DiD estimand for a treated–control pair:

\[ \hat{\tau} \;=\; \bigl(\bar{Y}_{T,\text{test}} - \bar{Y}_{T,\text{pre}}\bigr) \;-\; \bigl(\bar{Y}_{C,\text{test}} - \bar{Y}_{C,\text{pre}}\bigr) \]

Measurednbs/artifacts/causal_05_methodology.json, 115 null windows per estimator. Naive t-test false-positive rates: pooled DiD 0.9%, per-pair DiD 8.7%, regression-adjusted 26.1% — the most "sophisticated" of the three is the one that lies, at more than five times the nominal 5%. The design-calibrated critical value (the empirical 95th percentile of |placebo estimates|) restores 5.2% for every estimator, by construction.

⚠️ Sophistication is not validity

The regression-adjusted estimator is flagged inflated and invalid on this panel. Nothing about its extra covariates makes it wrong in general — but on this data, its naive decision rule false-positives ~26% of the time at nominal 5%. Calibrate on placebo history, pre-register the critical value, then run the test.

4 — Power against injected truth

The A/A test protects against false positives; the A/B simulation measures power against false negatives. Take real history, inject a known lift into the treated markets across a grid of effect sizes, and count how often each (calibrated) estimator detects it. Because the injected lift is known, this is the estimator graded against a sealed key — the same epistemics as the rest of the series, at simulation speed.

Measured — injected-truth power curves for the two calibrated DiD estimators (their curves coincide on this panel). At a quarter of the expected effect, power is 69%; from half the expected effect upward, both detect the planted lift every time. At the expected effect size — a 10%-of-baseline lift — power = 100% for both, comfortably past the 80% bar.

5 — The leaderboard: one honest recommendation

methodology_leaderboard runs the full A/A + A/B battery for every estimator the data supports, on one frozen assignment, and ranks by validity first (honest false-positive rate), then power, then cost. The data supports three designs (geo_lift, matched_market_did, national_flighting; recommended: geo_lift), and the estimator ranking lands:

estimator valid size? naive FPR (null data) power at expected effect verdict
pooled DiD 0.9% 100% recommended
per-pair DiD 8.7% 100% valid runner-up
regression-adjusted 26.1% disqualified on A/A size

Two caveats the leaderboard itself reports: sliding placebo windows overlap, so the rates are indicative rather than independent Bernoulli trials; and the false-positive rate is measured against the analytic decision rule — the calibrated critical value is what restores nominal size.

6 — What a pre-registration now says

The homework above compresses to five lines, written before the test:

Estimand: incremental Search ROAS, 8-week window, treated DMAs.

Design: 5 matched randomized pairs (holdout).

Estimator: pooled DiD.

Decision rule: effect declared iff |estimate| > the placebo-calibrated 95th-percentile critical value.

Power: >80% at the expected effect; MDE 0.27 ROAS as designed.

Every choice was made on pre-period data — nothing was picked because it "found lift". That discipline is what makes the number an experiment produces worth folding into a model, which is exactly what notebook 06 does next.

Check your understanding

Commit to an answer before opening each one.

Why does the most sophisticated estimator have the worst false-positive rate on null data?

Weekly KPI series are autocorrelated — adjacent weeks share trend, season, and demand shocks — so the effective sample size is far below the nominal one and naive standard errors come out too small. The regression-adjusted estimator compounds this: its extra structure gives it more ways to fit noise in any particular window, and its analytic decision rule doesn't know that. Measured on 115 null windows it declares a nonexistent effect 26.1% of the time at nominal 5%, versus 0.9% for pooled DiD. Sophistication is not validity — the A/A test is the only way to find out which is which on your panel.

What does the placebo-calibrated critical value do that a textbook variance formula cannot?

It replaces an assumption with a measurement. Instead of deriving the null distribution from independence assumptions the data violates, it re-runs the estimator on hundreds of pre-period windows where no experiment happened and takes the empirical 95th percentile of |placebo estimates| as the bar. That makes the test honest by construction, whatever the panel's autocorrelation structure — measured here, it restores a 5.2% false-positive rate for all three estimators, including the one whose naive rate was 26%.

Why must the estimator be chosen before the experiment runs?

If three estimators are available and you pick the one that "found lift" after the fact, your true false-positive rate is roughly the union of the three individual rates — even three honest 5% tests give you far more than 5%, and with an invalid 26% member in the menu the post-hoc pick is nearly guaranteed to find something. Pre-registering the design, estimator, and critical value on pre-period data is what makes the eventual readout an experiment rather than a story.

💡 Run it yourself

This page mirrors nbs/causal/causal_05_measuring_one_experiment.ipynb — notebook 5 of 11 in the Causal Inference in Practice series (brand: Veranda Home; synthetic worlds with sealed answer keys; every claim graded by an assert). All numbers from nbs/artifacts/causal_05_methodology.json, produced by nbs/causal/causal_05_measuring_one_experiment.ipynb. Previous: 04 · Latent Confounders. Next: 06 · Calibrating the Model, where the readout this design produces meets the confounded MMM. Source: github.com/redam94/mmm-framework.