Causal Inference 09: The Measurement Program
A year of learning, budgeted like the investment it is.
Notebook 08 chose one
experiment well. A measurement program is a different problem: seven
channels, finite testing capacity, cool-downs, seasons — and evidence that quietly
expires while you're busy elsewhere. This page mirrors
nbs/causal/causal_09_planning_the_measurement_series.ipynb: the framework
prices every candidate test in two currencies — EIG (expected
information gain, nats: what a feasible test would teach) and
EVOI (expected value of information, KPI units: what knowing is
worth to the budget decision) — under one ceiling, EVPI,
the value of perfect information about everything. A channel can be wildly uncertain
and still worth nothing to test — if no plausible answer would change the allocation.
1 — The priority grid
Inputs: the current posterior (the series' rung-2 fit on Veranda's seven-channel history) and the evidence ledger from notebook 07 — Radio's go-dark readout window ended 2022-11-28, Display's off-panel holdout ended 2024-04-22. Planning date: 2024-07-01. Per channel, the engine simulates a feasible national-pulse test, computes EIG against the channel's current ROI posterior (decayed where evidence exists), and EVOI by re-optimizing the budget across simulated readouts:
| channel | spend share | ROI posterior | EIG (nats) | EVOI (KPI) | quadrant | evidence |
|---|---|---|---|---|---|---|
| 5.2% | 0.82 ± 0.57 | 1.17 | 634 | test_now | — | |
| Radio | 8.1% | 0.66 ± 0.38 | 1.03 | 591 | test_now | 83 wk ago → retest due |
| Display | 12.6% | 0.76 ± 0.25 | 0.53 | 158 | test_now | 10 wk ago |
| Social | 15.5% | 0.76 ± 0.18 | 0.37 | 31 | learn_cheaply | — |
| Search | 19.6% | 0.55 ± 0.11 | 0.25 | 42 | monitor | — |
| TV | 28.2% | 0.66 ± 0.08 | 0.10 | 15 | deprioritize | — |
| Video | 10.7% | 2.12 ± 0.39 | 0.25 | 0.6 | deprioritize | — |
Measured — nbs/artifacts/causal_09_program.json (grid
order = priority order). Print — the channel whose split the Radio test resolved onto
shaky ground in notebook 07 — is the program's top priority, and the engine
found it independently of rung 7's narrative. Note Video: one of the widest
ROI posteriors on the board (2.12 ± 0.39), a respectable EIG of 0.25 nats — and an
EVOI of 0.6. Knowing more about Video changes nothing the budget
would do.
from mmm_framework.planning.priority import compute_experiment_priorities
from mmm_framework.planning.eig import channel_half_life, decayed_sigma, reexperiment_due
grid, portfolio = compute_experiment_priorities(
mmm,
evidence={"Radio": {"end_date": "2022-11-28"},
"Display": {"end_date": "2024-04-22"}},
as_of="2024-07-01", max_draws=150, random_seed=42,
)
# portfolio["evpi"] -> 1,624 KPI units (4.4% of the optimal-budget value)
due, fresh_eig = reexperiment_due(0.10, 84, channel_half_life("Radio"),
sigma_exp=0.10)
# -> a fresh Radio test would buy 0.70 nats: retest due
Measured — the measurement quadrant. Bubble size = spend share, color = the engine's verdict. The diagnostic corners: Print and Radio (high both — test now), Video (informative but worthless — deprioritize), TV (neither — the tight posterior of the biggest spend line). EIG says what a test would teach; EVOI says whether anyone should pay for the lesson.
2 — An honest asterisk the grid needs
⚠️ EVOI prices known unknowns
TV sits in deprioritize — its ROI posterior is tight (0.66 ± 0.08), so a
test teaches little and moves no budget. But
rung 2's sealed key showed TV
carries a residual bias the model doesn't know about (its
learning diagnostic flagged beta_TV as relocated). EVOI is
computed from the posterior, so it cannot price a bias the posterior doesn't
represent. A mature program runs two tracks: the EVOI track
above, and a validation track that occasionally tests confident
channels precisely because they're confident — triggered by diagnostics
(relocation flags, refutation failures, tension checks), not by uncertainty.
Notebook 10 shows a
validation-track test paying off.
3 — EVPI: the ceiling on the learning budget
Summing what perfect information about everything would be worth gives the program its budget ceiling: EVPI = 1,624 KPI units, against an optimal-budget value under current knowledge of 36,638 — the program's rational scale is 4.4% of the value it protects. Any measurement plan costing more than EVPI is, by construction, destroying value — no matter how scientific it feels. And any plan costing far less is probably leaving correctable bias in the allocation.
4 — Evidence decays
A readout is a photograph, not a covenant. Markets drift — creative wears out, auctions reprice, competitors move — so the information an experiment bought erodes on a half-life. The framework re-inflates the posterior sd as \( \sigma^2(t) = \sigma_0^2 \, e^{\lambda t} \) with \( \lambda = \ln 2 / h \), and re-flags a channel for testing when a new feasible test would again clear the EIG bar. Radio (half-life 52 weeks, tested 84 weeks before the planning date — its variance has roughly tripled since) has decayed enough that a fresh test would buy 0.70 nats — over the bar, retest due. Display (half-life 26 weeks, tested 10 weeks ago) is still fresh.
The framework's decay law, drawn exactly —
decayed_sigma from planning/eig.py with each channel's
default half-life (channel_half_life: Radio 52w, Display 26w) and the
notebook's post-experiment sds (Radio 0.10, Display 0.15). The dotted verticals mark
where each channel actually stands at the 2024-07-01 planning date. "We tested that
in 2022" is a date, not an excuse.
5 — The calendar
Scores in hand, the calendar is a constrained packing problem: a greedy EVOI-per-week schedule under the program's real constraints — one national test at a time, per-channel cool-downs (rung 8), a Q4 freeze (no experiments in the holiday quarter, program weeks 13–26), re-tests when decay triggers. The TV validation test is scheduled by policy, not EVOI — it's pinned to the last slot, using rung 8's 16-week design.
Measured — nbs/artifacts/causal_09_program.json
(solid = test, faint = cool-down, shaded band = Q4 freeze). The Print geo holdout
starts immediately; the freeze pushes the Radio re-test to week 26; Display and
Social follow. The EVOI-track tests finish by week 56; the policy-pinned TV
validation runs weeks 57–73, spilling into the next cycle — cool-downs and
a frozen quarter stretch five tests across substantially more calendar than the
naive sum of their durations. Calendar is the scarcest thing the program has.
6 — The program's memory
Every fitted model in the loop persists a per-run metrics snapshot — ROI posteriors,
response curves, the EIG/EVOI portfolio, allocation gaps — so next quarter's planning
starts from recorded state, not from whoever remembers the last deck.
compute_run_metrics is the same snapshot the platform stores per fit:
from mmm_framework.planning.history import compute_run_metrics
snapshot = compute_run_metrics(mmm, max_draws=100, random_seed=42)
# keys: approximate, channels, fit_method, n_draws, portfolio,
# response_curves, schema_version (7 channels tracked; schema v2;
# fit method nuts, approximate False)
7 — The program's operating rules
- Price tests in both currencies. EIG says what you'd learn; EVOI says whether learning changes any decision. Test where both are high.
- EVPI is the budget. The whole program should cost a fraction of the value of perfect information — if it doesn't, you're doing science for sport.
- Evidence expires. Half-lives and re-test triggers turn "we tested that in 2021" from an excuse into a date.
- Keep a validation track. EVOI can't see biases the posterior doesn't know it has. Diagnostics-triggered tests on confident channels are the program's insurance policy.
- Write the state down. Snapshots make the loop resumable by people who weren't in the room.
Check your understanding
Commit to an answer before opening each one.
Video has one of the widest ROI posteriors on the board (2.12 ± 0.39) and a respectable EIG (0.25 nats). Why is its EVOI only 0.6 KPI units?
Because EVOI doesn't price uncertainty — it prices decision change. The engine simulates plausible readouts from the current posterior and asks how much the re-optimized budget improves under each. For Video, essentially every plausible answer leaves the allocation where it already is, so knowing the true number is worth almost nothing this year. Uncertainty without decision leverage is epistemically interesting and economically worthless — which is exactly why the grid needs two axes. Test where both are high.
TV is the biggest line on the media plan (28% of spend) and the CFO doubts it. The grid says "deprioritize". Who's right?
Both — about different questions. On known unknowns the grid is right: TV's ROI posterior is the tightest on the board (0.66 ± 0.08), so a feasible test teaches little (EIG 0.10 nats) and moves almost no budget (EVOI 15.5). But rung 2's sealed key showed TV carries a bias the posterior doesn't represent, and EVOI cannot price what the posterior can't see. That is the validation track's job: test confident channels on a diagnostics trigger (relocation flags, refutation failures), by policy — which is why the calendar still ends with a 16-week TV validation test despite its EVOI.
Radio was properly tested with a well-designed go-dark in late 2022. Why won't the engine just reuse that readout?
Because the information is perishable even when the readout was perfect.
Radio's post-experiment sd (0.10) re-inflates on a 52-week half-life —
\( \sigma^2(t) = \sigma_0^2 e^{\lambda t} \) — and by the 2024-07-01
planning date the readout is 84 weeks old: about 1.6 half-lives, so the
variance has roughly tripled. A fresh feasible test would buy 0.70 nats,
above the re-test bar, so the engine flags retest_due. The
decay clock isn't cynicism about the old test; it's a model of a drifting
market. A program that never re-tests is spending this year's budget on a
2022 world.
💡 Run it yourself
This page mirrors
nbs/causal/causal_09_planning_the_measurement_series.ipynb
— notebook 9 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_09_program.json,
produced by nbs/causal/causal_09_planning_the_measurement_series.ipynb.
Previous: 08 · Designing the
Next Experiment. Next:
10 · The Closed Loop — the capstone:
three full cycles of fit → prioritize → design → measure → calibrate, graded
against the sealed key at every step. Source:
github.com/redam94/mmm-framework.