CounterfactualEvaluator#

class pymc_marketing.mmm.counterfactual.CounterfactualEvaluator(*, pymc_model, posterior, response_vars, frozen_deterministics, dates, intervention_target='channel_data', intervention_mode='replace', expected_aux_values=None)[source]#

Compiled batched evaluator for the nodes a counterfactual intervention reaches.

Applies the intervention with pymc.do(), conditions the intervened model’s graph on posterior draws, swaps every date-indexed pm.Data the evaluation needs for a batched input, and compiles one function returning all requested nodes. Extracting the nodes together matters: channel_contribution and a mediated effect read the same spend data through the same adstock, and a single extraction keeps that subgraph shared instead of computing it once per node.

The intervention is a single (target, mode) pair for now. The direct-effect estimand – holding a mediator at its factual value while spend moves – needs simultaneous interventions and will generalize this to a mapping; the pair is threaded through the private helpers as one unit so that change stays local.

The batched inputs are what make a window evaluation possible. Every date-indexed input in the graph has to be cut to the same window in lockstep, or the graph is handed a max_window-long spend array and an n_dates-long mediator array. This class discovers those inputs from the graph and cuts them itself.

Every result is transposed to (sample, date, *non_date_dims) before it is returned. A node’s own axis order is whatever the operations that built it happened to produce – a panel model’s linear predictor comes out (country, date) while its channel_contribution comes out (date, country, channel) – and callers that add those two together cannot each rediscover that.

Parameters:
pymc_modelpm.Model

The fitted model whose graph is evaluated.

posteriorxr.Dataset

Posterior samples (already subsampled). Draws are flattened into a single sample axis in chain-major order.

response_varssequence of str or Variable

Nodes to evaluate, in the order the results are keyed by. A node is accepted directly for a quantity the model does not register, such as the linear predictor under an identity link.

frozen_deterministicslist of str

Deterministics to hold at their posterior values instead of recomputing.

datespd.DatetimeIndex

Dates of the fitted data, used to validate the discovered inputs.

intervention_targetstr, default "channel_data"

Name of the model variable the counterfactual intervenes on: a data variable or a deterministic carrying a leading date dimension. Random variables are refused – observed ones because intervening would silently delete the likelihood, free ones because a parameter is conditioned on, not intervened on.

intervention_modeInterventionMode, default "replace"

How the intervention grafts onto the target; see InterventionMode. Under "scale", asking for the target itself as a response variable returns the intervened value, symmetric with "replace" where the evaluator’s input is that value.

expected_aux_valuesmapping of str to xr.DataArray, optional

Fit-time values of date-indexed inputs, keyed by variable name – typically idata.constant_data. Every auxiliary input discovered in the graph whose name appears here has its live value, read off the model’s own shared variable, checked against the stored one instead of trusted outright. A mismatch means the model was mutated after fitting – by MMM.sample_posterior_predictive(..., clone_model=False) or a direct pm.set_data call – and is refused rather than silently evaluated on a hybrid of fitted and mutated state. A name absent from the mapping falls back to the live snapshot, unchecked, which keeps this optional: an evaluator built without fit-time values behaves as before. time_index is checked the same way when present, but against the fabricated np.arange(n_dates) rather than a live value, since the evaluator never reads a live time_index.

Attributes:
non_date_dimsdict

Per response variable, the dimensions of its result after sample and date, which is the node’s own dimension order with date removed.

windowed_data_varstuple of str

Names of the auxiliary date-indexed inputs discovered in the graph.

target_dtypedtype

Dtype the intervention values are cast to; channel_dtype is its alias for the default spend target.

Raises:
ValueError

If the intervention target does not exist, is a random variable, is frozen, is not of a floating dtype, or lacks a leading date dimension; if no response variable depends on the target; if a discovered date-indexed input does not span the fitted date axis; if a response variable has no name (an anonymous node such as a raw arithmetic expression, unless .name was set on it); if two response variables share a name; or if a value in expected_aux_values – an auxiliary input, or the fabricated time_index – disagrees with what the live model or the fabrication would produce, meaning the model was mutated after fitting.

Methods

CounterfactualEvaluator.__init__(*, ...[, ...])

CounterfactualEvaluator.evaluate_baseline(...)

Evaluate every node on one set of intervention values, over the full date axis.

CounterfactualEvaluator.evaluate_counterfactual(...)

Evaluate every node on all counterfactual scenarios.

Attributes

BATCH_DIM

Dimension the scenario axis is carried on through the vectorized graph.

CHANNEL_DATA

MAX_BATCH_ELEMENTS

Output elements one evaluation may produce before it is split in two.

TIME_INDEX

channel_dtype

Alias of target_dtype under the default spend target.

windowed_data_vars

Names of the auxiliary date-indexed inputs discovered in the graph.