EvaluationWindows.build_scenarios#

EvaluationWindows.build_scenarios(*, baseline_array, counterfactual_spend_factor, dtype, channel_axis, n_channels, estimand)[source]#

Build the perturbed spend arrays that have to be evaluated.

Two scenario layouts are produced, and which one applies is the whole difference between a plain MMM and a mediated one:

  • channel_axis is Noneseparable. One all-channels perturbation per period. Because \(v_{t,c}\) depends on channel c’s spend alone, column m of that single scenario already is channel m’s counterfactual, so every channel key points at the same row and the joint scenario costs nothing extra.

  • channel_axis given – per channel. One perturbation per (period, channel), because a mediated effect mixes channels before reaching the response and no per-channel column survives to be read off. Asked for the joint estimand this collapses back to one perturbation per period: the per-channel rows would otherwise be built, evaluated and never read.

Parameters:
baseline_arraynp.ndarray

Actual channel spend, shape (n_dates, *extra_shape).

counterfactual_spend_factorfloat

Multiplicative factor for counterfactual spend.

dtypestr

NumPy dtype for the output array.

channel_axisint or None

Axis of channel within baseline_array’s non-date axes, or None to perturb all channels at once. Panel models lay channel_data out as (date, *custom_dims, channel), so this is not always zero.

n_channelsint

Number of channels.

estimand{“per_channel”, “joint”}

Which scenarios are going to be read. Only those get built: the difference is a factor of n_channels in every downstream cost for a mediated model asked for the joint number.

Returns:
CounterfactualScenarios

Perturbed spend plus the bookkeeping needed to find the row for a given _ScenarioKey and to broadcast per-period arrays over scenarios.