Fixed-effects MMM

Use FixedEffectsMMM when shared media and control slopes should be estimated from temporal variation within observed units, with time-invariant unit levels removed from the fitting likelihood. Ordinary MMM(dims=("geo",)) does not implement this likelihood.

from ammm.mmm import GeometricAdstock, LogisticSaturation
from ammm.mmm.fixed_effects import FixedEffectsMMM

model = FixedEffectsMMM(
    unit="geo", date_column="date", target_column="revenue",
    channel_columns=["tv", "social"],
    adstock=GeometricAdstock(l_max=4), saturation=LogisticSaturation(),
)

Supply a balanced unit-date panel with unique, complete cells. The estimator uses orthonormal within-unit Helmert contrasts. Shared media parameters and control slopes are learned without sampling unit intercepts in that likelihood; level prediction reconstructs unit effects from factual training residuals. The target scale is derived from within-unit contrasts and is not configurable.

Adstock, saturation and control prior dimensions must express shared slopes. The design screens reject absent transformed within-unit variation and deficient joint slope rank at the reference design. Passing them does not establish nonlinear identification or freedom from time-varying confounding.

Prediction requires every fitted unit and rejects missing or unseen units. The current contract excludes log link, time-varying parameters, annual seasonality, custom mean effects, holidays, calibration, causal-graph options, cost-per-unit configuration and fixed-budget optimisation. The geo_fe demo shows the supported graph configuration. The retained runner plots prior predictions against observed within-unit contrasts, labels the axis accordingly and retains one panel per unit; posterior predictive plots use reconstructed outcome levels (src/ammm/mmm/plotting/diagnostics.py:206, working tree after 7cb7f20). A reduced-draw geo_fe run and its bundled retained scenarios completed on 1 October 2026. That run failed diagnostic gates, so this check establishes workflow execution only. Inspect diagnostics before interpreting a fitted model.

Unit effects do not absorb common time shocks. A regressor shared across units but varying by date survives the within transformation; its causal interpretation still needs an adjustment or design argument. Do not describe this estimator as two-way fixed effects.

The previously cited historical PC-FE-01 posterior parity result has not been verified against a retrievable report in this documentation review. Do not use that statement as qualification evidence without the retained report, frozen profile, data and source commit. The implementation tests include deterministic oracles (tests/mmm/test_fixed_effects.py:98); these do not reproduce a cross-library posterior qualification study. Review diagnostics on every fit.

Implementation reference at 7cb7f20: src/ammm/mmm/fixed_effects.py:79.