Media budgets¶
Marketing-mix budget scheduling: which channel to spend on, and when, from confounded logs. Media spend is planned against demand — a marketer raises budget in the weeks a product sells anyway — so a model fitted on the log credits the channel with the season. Optimise against that model and the plan under-invests: crediting every channel with the season, it believes it needs less spend to reach its sales target than it does.
The plant is control-affine by construction, so identification and safety read the same object:
d(sales)/dt = -decay*(sales - base) + sum_c beta_c * hill(adstock_c) + sum_c gamma_c * spend_c
d(adstock_c)/dt = -theta_c * adstock_c + spend_c
Each channel acts twice: gamma_c is the immediate incremental return and is the control
channel; beta_c is the carried-over return through a saturating adstock and is part of the
drift. Under a policy that chases seasonality it is gamma_c that is confounded, and gamma_c
is exactly what cross-fit Robinson partialling-out identifies. The adstock rows are mechanical and
go to prescribe as known=, so the fit has only the sales row to learn.
uv run python scripts/mmm_demo.py
What it printed when this site was built:
== weekly media log, planner chased the season; true incremental returns {'search': 0.5, 'social': 0.2, 'video': 0.35} ==
| arm | total spend | cumulative sales | lift | lift / extra spend |
|---|---|---|---|---|
| adjusted | 41.389 | 83.757 | +42.693 | +1.0784 |
| confounded | 35.499 | 78.206 | +37.142 | +1.1022 |
| flat | 41.389 | 82.032 | +40.968 | +1.0348 |
| myopic | 41.389 | 85.033 | +43.969 | +1.1106 |
| none | 1.800 | 41.064 | +0.000 | +nan |
what each arm believes each channel is worth (channel x box width):
channel adjusted confounded inflation
----------------------------------------------------
spend_search 1.002 2.468 2.46x
spend_social 0.122 1.880 15.42x
spend_video 0.703 2.173 3.09x
At the same total budget (41.4) the prescribed schedule buys +4.2% more lift than an equal split (cumulative sales over the do-nothing arm), and the myopic rule on the same fit buys +7.3%. The myopic rule differs from the equal split only in how it splits each week's budget across the channels, so that gap is what identification buys; the gap between the prescribed schedule and the myopic rule is what the horizon buys, and its sign is a property of this plant.
The confounded arm credits every channel with the season, so it believes it needs less: it spends 35.5 and buys 87% of the lift.
Read at return-per-unit-spend it looks BETTER (1.102 against 1.078), because the response saturates and it under-invests. That is why the arms are compared at matched budget.
The arms are the same optimiser reading the same log through different causal claims, every one audited by rolling its schedule out on the true plant:
adjusted— the graph, so the season is adjusted for and the incremental returns are identified;confounded— an empty adjustment set asserted, which is what fitting the log directly amounts to;flat— an equal split held constant at theadjustedarm's total spend, so the head-to-head is at matched budget and differs only in allocation;myopic— the identified fit spent on each week's return alone, at the same budget, which isolates what the plan's horizon buys from what identification buys;none— spend held at the floor, the do-nothing counterfactual every lift is measured against.
Scope, and it bounds what the numbers mean:
- The saturating plant is fitted with a polynomial drift, so the fitted plant is a local surrogate of the truth. That is why every arm is audited on the true plant, and the sales reported are the audited ones rather than the planner's own forecast.
- Spend is priced through
Lever.unit_costrather than capped.prescribetakes a budget (budgets=), but the arms here are compared at matched spend instead: theflatandmyopicarms are held at theadjustedarm's total spend. - The carryover rates
theta_care taken as known. In practice they are fitted (Robyn, Meridian); holding them fixed isolates the incremental return, which is what this case study is about. - What the whole-horizon plan buys over the myopic one is a property of the plant's parameters,
not of the method. The
myopicarm is there to measure it rather than assume it.