create_zero_dataset#
- pymc_marketing.mmm.utils.create_zero_dataset(model, start_date, end_date, channel_xr=None, include_carryover=True, preserve_observed=False, carry_in_periods=0, carryover_periods=None)[source]#
Create an
xr.Datasetfor future prediction, with zero fills.Creates a dataset with dates from start_date to end_date and all model dimensions, filling channel and control variables with zeros (or with values from channel_xr if provided), under the canonical underscore names (
_channel,_control). Date-varying variables that the model’smu_effectsread are zero-filled too, under their own names, so thatMuEffect.set_datahas something to set for a window other than the training one.- Parameters:
- model
Fitted MMM instance. Must have
xarray_dataset,date_column,channel_columns,control_columns,dimsandadstockattributes.mu_effectsis read when present.- start_date, end_date
Date range for the prediction period.
- channel_xr
Optional per-dimension channel values. Data variables must be a subset of
model.channel_columns. Dimensions must be a subset ofmodel.dimsand must not include the date dimension. Values are broadcast across every date in the generated range.- include_carryover
Whether to extend the date range past
end_datebyadstock.l_maxperiods, so that spend inside the window is scored with the carry-over it produces after it. The extension is trailing; nothing is prepended, and the window therefore starts from a cold adstock state.- carry_in_periods
Number of leading dates to prepend, taken from the training index so they are real observed dates.
_channelholds its observed spend on them, so the adstock does not start cold. Clips itself when the window starts near the beginning of training. The history has to run up to the window at the training frequency: when it does not (a window opening long after training ends), aUserWarningis issued and the window starts cold, because year-old spend is not last period’s.- carryover_periods
Periods to extend past end_date when include_carryover, defaulting to
model.adstock.l_max. Pass the effective carryover when an effect chains a further adstock behind the model’s own, or its tail is truncated.- preserve_observed
Whether every non-decision variable – controls, and the variables the model’s
mu_effectsread – takes its observed value on each date the training data covers, falling back to zero only on dates it does not._channelis unaffected: it is the decision variable and stays at zero (or at channel_xr). The defaultFalsezero-fills everything, which is the function’s contract (a window with no committed activity) and keeps_controlexactly as existing callers get it.create_optimization_model()opts in explicitly; the deprecatedsample_response_distribution()relies on the default, since it scores an allocation against a zeroed baseline.
- Returns:
xr.DatasetDataset with
_channel(and optionally_control) variables, indexed by("date", *dims, "channel"), plus one variable per date-varying name the model’smu_effectsread: zero-filled by default, observed wherever the training data reaches when preserve_observed is set.
Notes
By default the effect variables are zeros, which is what a future window with no committed activity means. In-sample that is a change of scenario rather than a reconstruction of history: an exogenous series the effect reads – a category-demand index, a committed budget – comes back as zero rather than at its fitted value, so the response no longer matches the posterior it was fitted to.
preserve_observed=Trueis the fix, and needs no knowledge of which window it was handed: taking the observed value wherever the training data reaches reproduces history in-sample and decays to zeros on genuinely future dates. This is not adstock carry-in, which is a leading block of real spend before the window; that isinclude_last_observations.For a scenario that is neither – a planned promotional calendar, a committed lower-funnel budget – build the model with
create_optimization_model(),pm.set_datathose variables on it, and hand that model toBudgetOptimizerdirectly. That model’s date axis is three blocks,carry_in + decisions + carry_over, each flankeffective_carryover_lags()wide, so passcarry_in_periods=mmm.effective_carryover_lags()andadstock_periods=mmm.effective_carryover_lags()along withnum_periods(BudgetOptimizerchecks that the three add up to the axis and says so if they do not).An effect variable whose coordinate labels do not cover the shared index (a
channel-dimensioned variable carrying a subset of the channels, say) is NaN-filled the moment xarray aligns it, and is refused here by name rather than written into the model as NaN.