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

ComponentBuilt whenShape
intercept_contributionAlwayseffectively ("date", *dims) in the model mean
channel_contributionAlways("date", *dims, "channel")
control_contributioncontrol_columns is set("date", *dims, "control")
mundlak_contributionuse_mundlak_cre=Truedims
yearly_seasonality_contributionyearly_seasonality is set("date", *dims)
Additional additive effectsYou 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:

  1. scale channel input
  2. apply adstock and saturation through forward_pass(...)
  3. optionally apply a time-varying media multiplier
  4. 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

NeedMain setting
Extra non-media regressorscontrol_columns
Legacy low-level Mundlak adjustmentuse_mundlak_cre=True
Built-in yearly seasonalityyearly_seasonality=<int>
Time-varying intercepttime_varying_intercept=True or custom HSGPBase
Time-varying mediatime_varying_media=True or custom HSGPBase
Additional additive effectsappend to mmm.mu_effects or use YAML effects
Calibrationadd_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 tv and search
  • a control contribution for price_index
  • yearly Fourier seasonality
  • a panel axis over geo

Next steps