Seasonality and Trends
AMMM3 supports one built-in seasonality switch on PanelMMM and a broader
additive-effect mechanism for custom seasonality, trend, and event terms.
Built-in yearly seasonality
Set yearly_seasonality=<int> to add a yearly Fourier term directly to the
main model specification.
mmm = PanelMMM(
date_column="date",
target_column="sales",
channel_columns=["tv", "search"],
yearly_seasonality=3,
adstock=GeometricAdstock(l_max=8),
saturation=LogisticSaturation(),
)
This creates:
fourier_contributionas the unsummed Fourier basis contributionyearly_seasonality_contributionas the additive contribution tomu
The prior for this built-in seasonality comes from model_config["gamma_fourier"].
What yearly_seasonality means
yearly_seasonality is the Fourier order passed to YearlyFourier.
It must be a positive integer. AMMM3 validates this at construction time.
Custom additive effects
For anything beyond built-in yearly seasonality, use mu_effects.
Each effect must add a tensor with dims:
("date", *dims)
AMMM3 ships three retained additive-effect types:
| Effect | Use it for |
|---|---|
FourierEffect | Custom seasonal structure such as weekly or monthly Fourier terms |
LinearTrendEffect | Piecewise linear trend with changepoints |
EventAdditiveEffect | Dated events such as launches, promotions, or holidays |
FourierEffect
FourierEffect wraps a FourierBase implementation such as:
YearlyFourierMonthlyFourierWeeklyFourier
Example:
from abacus.mmm.additive_effect import FourierEffect
from abacus.mmm.fourier import WeeklyFourier
mmm.mu_effects.append(
FourierEffect(
fourier=WeeklyFourier(n_order=3, prefix="weekly_fourier")
)
)
LinearTrendEffect
LinearTrendEffect wraps LinearTrend, which models piecewise linear trend
changes through changepoints.
Example:
from abacus.mmm import LinearTrend
from abacus.mmm.additive_effect import LinearTrendEffect
mmm.mu_effects.append(
LinearTrendEffect(
trend=LinearTrend(
n_changepoints=8,
include_intercept=False,
dims=("geo",),
),
prefix="trend",
)
)
Events
For events, the retained public surface on PanelMMM is add_events(...).
Example:
import pandas as pd
from pymc_extras.prior import Prior
from abacus.mmm.events import EventEffect, GaussianBasis
df_events = pd.DataFrame(
{
"name": ["promo", "launch"],
"start_date": pd.to_datetime(["2025-02-01", "2025-03-10"]),
"end_date": pd.to_datetime(["2025-02-07", "2025-03-14"]),
}
)
effect = EventEffect(
basis=GaussianBasis(
priors={"sigma": Prior("Gamma", mu=7, sigma=1, dims="event")}
),
effect_size=Prior("Normal", mu=0, sigma=1, dims="event"),
dims=("event",),
)
mmm.add_events(
df_events=df_events,
prefix="event",
effect=effect,
)
The event effect dims must include the event prefix plus the model dims.
When to register effects
Add custom effects before you build or fit the model.
That applies to:
mmm.mu_effects.append(...)mmm.add_events(...)
If you build the model first and only then append effects, those new terms are not part of the existing graph.
YAML effects
The YAML builder supports top-level effects: entries. Example:
effects:
- type: linear_trend
prefix: trend
n_changepoints: 8
include_intercept: false
- type: weekly_fourier
order: 3
prefix: weekly_fourier
The builder appends these effects before calling build_model(...).
Choosing between built-in and custom seasonality
Use yearly_seasonality when you need a compact built-in annual effect.
Use FourierEffect when you need:
- weekly seasonality
- monthly seasonality
- multiple seasonal effects together
- custom Fourier prefixes or priors
Common pitfalls
- Adding effects after the model has already been built
- Using event effect dims that do not include the required prefix
- Treating
yearly_seasonalityand a custom yearly Fourier effect as if they were separate concepts when they are both additive seasonal terms
Next steps
- Read Time-Varying Parameters if you want trend or media behaviour to vary smoothly over time.
- Read Calibration if you want to constrain the specification with external measurements.