Model Overview
PanelMMM is an additive Bayesian marketing mix model built in PyMC. This page
describes the model structure that AMMM3 actually builds.
For input layout, see Data Preparation. For individual configuration surfaces, see the other pages in this section. Named FE and CRE presets use specialised likelihoods and restrictions; read Choose an Estimator before applying this general component description to them.
Core structure
At fit time, AMMM3 builds the model mean in scaled target space as:
mu =
intercept_contribution
+ sum(channel_contribution over channel)
+ sum(control_contribution over control), if control_columns are configured
+ mundlak_contribution, if use_mundlak_cre=True
+ yearly_seasonality_contribution, if yearly_seasonality is enabled
+ any additional mu_effects
The observed target is then attached through the configured likelihood
distribution with mu=mu.
What is scaled and what is not
Before the PyMC graph is built:
- channel data is scaled according to
Scaling.channel - the target is scaled according to
Scaling.target - controls are not scaled automatically
That means media and target priors operate on the model scale, not directly on the original business units. For the scaling surface, see Scaling and Preprocessing.
Model components
| Component | Built when | Shape |
|---|---|---|
intercept_contribution | Always | effectively ("date", *dims) in the model mean |
channel_contribution | Always | ("date", *dims, "channel") |
control_contribution | control_columns is set | ("date", *dims, "control") |
mundlak_contribution | use_mundlak_cre=True | dims |
yearly_seasonality_contribution | yearly_seasonality is set | ("date", *dims) |
| Additional additive effects | You add entries to mu_effects | ("date", *dims) |
AMMM3 also adds total_media_contribution_original_scale automatically as a
deterministic on the original target scale.
Media path
Each channel column goes through the configured media transform path:
- scale channel input
- apply adstock and saturation through
forward_pass(...) - optionally apply a time-varying media multiplier
- contribute the result through
channel_contribution
See Adstock and Saturation and Time-Varying Parameters.
Controls
Controls enter the model as a separate additive term:
control_contribution = control_data * gamma_control
Use controls for non-media regressors such as price, macro indicators, or
competitor measures. Controls are configured with control_columns and use
gamma_control priors from model_config.
Panel dimensions
dims adds extra indexing axes such as geo, brand, or market.
With dims=("geo",), the model is indexed over date and geo. With
dims=("geo", "brand"), it is indexed over date, geo, and brand.
AMMM3 does not automatically add hierarchical pooling just because dims is
set. By default, parameters are indexed over the configured panel coordinates.
If you want hierarchical shrinkage across those coordinates, encode it in the
priors you pass to transforms or model_config.
See Panel Dimensions.
Optional components
| Need | Main setting |
|---|---|
| Extra non-media regressors | control_columns |
| Legacy low-level Mundlak adjustment | use_mundlak_cre=True |
| Built-in yearly seasonality | yearly_seasonality=<int> |
| Time-varying intercept | time_varying_intercept=True or custom HSGPBase |
| Time-varying media | time_varying_media=True or custom HSGPBase |
| Additional additive effects | append to mmm.mu_effects or use YAML effects |
| Calibration | add_lift_test_measurements(...), add_cost_per_target_calibration(...) |
This table describes the ordinary PanelMMM component surface. The released
FE and CRE presets deliberately reject several optional components and
downstream operations. Their estimator pages are authoritative for those
boundaries.
What target_type changes
target_type is semantic metadata, not a different likelihood family.
It affects downstream reporting such as the default efficiency metric label:
"revenue"->ROAS"conversion"->CPA
It does not change the fitted functional form on its own.
Python example
from abacus.mmm import GeometricAdstock, LogisticSaturation
from abacus.mmm.panel import PanelMMM
mmm = PanelMMM(
date_column="date",
target_column="sales",
channel_columns=["tv", "search"],
control_columns=["price_index"],
dims=("geo",),
yearly_seasonality=2,
adstock=GeometricAdstock(l_max=8),
saturation=LogisticSaturation(),
)
This specification gives you:
- an intercept
- transformed media contributions for
tvandsearch - a control contribution for
price_index - yearly Fourier seasonality
- a panel axis over
geo
Next steps
- Read Adstock and Saturation for the media transform choices.
- Read Priors and Configuration for the prior surface.
- Read Choose an Estimator before choosing an aggregate time-series, FE, or CRE contract.