Media Mix Optimization
Why MMM Exists Alongside User-Level Attribution
Marketing Mix Modeling (MMM) is a statistical, aggregate-level approach to estimating each channel's contribution to business outcomes (sales, revenue, signups) using time-series regression against weekly or daily spend and outcome data — no individual-level user tracking required. This makes it uniquely valuable for two growing problems user-level attribution can't solve: measuring channels with no click-level tracking at all (TV, out-of-home, radio, podcast sponsorships), and remaining fully functional as third-party cookies and cross-device identity resolution continue to erode the data user-level attribution depends on.
The Core Regression and Its Two Key Transformations
At its core, MMM regresses a dependent variable (sales) against independent variables (spend per channel, plus controls like seasonality, price changes, promotions, and macroeconomic factors) over time. Two transformations are essential to make this regression meaningful rather than naive:
- Adstock/carryover: a channel's effect doesn't end the moment spend stops — a TV ad or a brand campaign has lingering effect over subsequent weeks, modeled as an exponential or geometric decay applied to historical spend.
- Saturation/diminishing returns: each channel's response curve is non-linear — doubling spend rarely doubles output, and most channels show diminishing marginal returns past some point, typically modeled with a Hill function or similar S-curve.
import numpy as np
def apply_adstock(spend: np.ndarray, decay_rate: float) -> np.ndarray:
"""Geometric adstock: each week's effective spend includes a decayed
carryover from prior weeks' spend, modeling lingering channel effect."""
adstocked = np.zeros_like(spend, dtype=float)
adstocked[0] = spend[0]
for t in range(1, len(spend)):
adstocked[t] = spend[t] + decay_rate * adstocked[t - 1]
return adstocked
def hill_saturation(adstocked_spend: np.ndarray, half_saturation: float, slope: float) -> np.ndarray:
"""Hill function: models diminishing returns, approaching an asymptote
as spend increases well beyond the half-saturation point."""
return adstocked_spend ** slope / (adstocked_spend ** slope + half_saturation ** slope)MMM Output Is a Response Curve, Not Just a Contribution Number
Data Requirements and Practical Limitations
MMM needs substantial historical data — typically 2+ years of weekly data across enough spend variation per channel to statistically separate each channel's effect, which is a real constraint for newer brands or channels that have only ever run at a flat, unvaried budget (no variation means no signal to estimate a response curve from). MMM also struggles with high collinearity between channels that historically move together (if paid search and paid social budgets have always scaled up and down in lockstep, the model can't cleanly separate their individual effects) — a problem best mitigated by deliberately varying channel spend independently when possible, specifically to generate the variation MMM needs.
Modern, Bayesian Approaches: Robyn, LightweightMMM, Meridian
Open-source tooling has made MMM far more accessible than the historically expensive, agency-run, black-box versions of a decade ago. Meta's Robyn and Google's LightweightMMM/Meridian both implement Bayesian MMM frameworks that let you incorporate prior beliefs (e.g., from a previous incrementality test) into the model, express uncertainty as credible intervals rather than a single point estimate, and run reasonably on standard cloud infrastructure rather than requiring specialized enterprise software.
MMM and Incrementality Testing Should Validate Each Other
What's Next?
That calibration step depends on actually running a rigorous incrementality test — the next lesson covers how to design one properly.
I build these systems professionally.
Whether it's a RAG pipeline, analytics migration, or AI workflow — let's talk.