Seasonality and Trends

Abacus 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_contribution as the unsummed Fourier basis contribution
  • yearly_seasonality_contribution as the additive contribution to mu

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. Abacus 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)

Abacus 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:

  • YearlyFourier
  • MonthlyFourier
  • WeeklyFourier

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_seasonality and 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.