Priors and Configuration

Abacus uses model_config to control priors on the underlying PyMC variables. Transform priors can be configured either on the transform objects themselves or through their prefixed variable names in model_config.

Where configuration lives

Surface Use it for
model_config Intercept, likelihood, controls, seasonality, Mundlak terms, time-varying config, and prefixed transform priors
adstock=... and saturation=... Transform choice plus direct transform-prior overrides
control_impacts and control_sign_policy Directional expectations for controls

Default model_config

PanelMMM.default_model_config is built from the current model state.

The default keys are:

Key Default
intercept Prior("Normal", mu=0, sigma=2, dims=dims)
likelihood Prior("Normal", sigma=Prior("HalfNormal", sigma=2, dims=dims), dims=("date", *dims))
gamma_control Prior("Normal", mu=0, sigma=2, dims=(*dims, "control"))
gamma_fourier Prior("Laplace", mu=0, b=1, dims=(*dims, "fourier_mode"))
gamma_channel_mundlak Added only when use_mundlak_cre=True
gamma_control_mundlak Added only when use_mundlak_cre=True
intercept_tvp_config Added when time_varying_intercept is enabled
media_tvp_config Added when time_varying_media is enabled

Abacus also merges in the transform-specific config exposed by the selected adstock and saturation objects.

Configure priors in Python

Use pymc_extras.prior.Prior objects when you want explicit control:

from pymc_extras.prior import Prior

from abacus.mmm import GeometricAdstock, LogisticSaturation
from abacus.mmm.panel import PanelMMM

model_config = {
    "intercept": Prior("Normal", mu=0, sigma=1, dims=("geo",)),
    "likelihood": Prior(
        "Normal",
        sigma=Prior("HalfNormal", sigma=1.5, dims=("geo",)),
        dims=("date", "geo"),
    ),
    "gamma_control": Prior("Normal", mu=0, sigma=1, dims=("geo", "control")),
    "saturation_lam": Prior("Gamma", alpha=3, beta=1, dims=("geo", "channel")),
}

mmm = PanelMMM(
    date_column="date",
    target_column="sales",
    channel_columns=["tv", "search"],
    control_columns=["price_index"],
    dims=("geo",),
    adstock=GeometricAdstock(l_max=8),
    saturation=LogisticSaturation(),
    model_config=model_config,
)

Configure priors in YAML

YAML config can express the same priors as serialised distribution mappings:

data:
  date_column: date

target:
  column: sales
  type: revenue

dimensions:
  panel: [geo]

media:
  channels: [tv, search]
  adstock:
    type: geometric
    l_max: 8
  saturation:
    type: logistic

priors:
  intercept:
    distribution: Normal
    mu: 0
    sigma: 1
    dims: ["geo"]
  likelihood:
    distribution: Normal
    sigma:
      distribution: HalfNormal
      sigma: 1.5
      dims: ["geo"]
    dims: ["date", "geo"]
  saturation_lam:
    distribution: Gamma
    alpha: 3
    beta: 1
    dims: ["geo", "channel"]

Abacus parses these mappings into runtime Prior or HSGPKwargs objects.

Transform priors and prefixed names

Transform parameters appear in the model under prefixed variable names.

Examples:

  • adstock alpha -> adstock_alpha
  • saturation lam -> saturation_lam
  • saturation beta -> saturation_beta

So you can override transform priors in either of these ways:

  1. pass priors={...} to the transform object
  2. override the prefixed variable in model_config

Use one style consistently within a project if you want the configuration to be easy to read.

Directional control priors

Controls are the right place for exogenous drivers whose effect may be negative, such as competitor spend, competitor price pressure, or supply-side disruptions. By default, control coefficients remain unrestricted.

You can declare expected control directions with:

  • control_impacts
  • control_sign_policy

Allowed impact values:

  • positive
  • negative
  • unrestricted

Allowed policies:

  • soft: bias the prior toward the expected sign
  • strict: use a sign-constrained prior

Python example

mmm = PanelMMM(
    date_column="date",
    channel_columns=["tv", "search"],
    control_columns=["competitor_spend", "price_index"],
    control_impacts={
        "competitor_spend": "negative",
        "price_index": "negative",
    },
    control_sign_policy="strict",
    adstock=GeometricAdstock(l_max=8),
    saturation=LogisticSaturation(),
)

YAML note

The current public YAML schema does not expose control_impacts or control_sign_policy. If you need directional control settings today, use the Python API for that part of the specification.

Constraints for directional controls

When control_impacts is configured, Abacus expects:

  • gamma_control and gamma_control_mundlak to be Normal or TruncatedNormal
  • scalar numeric mu and sigma values for those priors
  • the prior dims to include "control"

If you violate those assumptions, model build fails with a validation error.

Time-varying configuration keys

When you enable a boolean time-varying effect, Abacus uses these model_config keys:

  • intercept_tvp_config
  • media_tvp_config

Those keys can be:

  • an HSGPKwargs instance
  • a dict with HSGPKwargs fields
  • a dict in SoftPlusHSGP.parameterize_from_data(...) style, such as {"ls_lower": 1, "ls_upper": 10}

See Time-Varying Parameters.

Important scope note

Directional control priors apply to control_columns, not channel_columns. Media channels are modelled through the adstock and saturation path.

If you need full manual control over the control prior, override gamma_control and gamma_control_mundlak directly in model_config.

Common pitfalls

  • Putting control priors on media variables instead of using transform priors
  • Forgetting the prefixed transform variable names in model_config
  • Assuming dims automatically create hierarchical priors
  • Using directional control priors with incompatible gamma_control distributions

Next steps