resolve_channel_dependent_effects#

pymc_marketing.mmm.spend_reach.resolve_channel_dependent_effects(model)[source]#

Find the mu_effects a spend counterfactual reaches.

The counterfactual perturbs channel_data, so any effect with channel_data among its ancestors carries part of the resulting change in the linear predictor and has to be evaluated alongside channel_contribution. A funnel mediator is the motivating case: upper-funnel spend moves latent demand, demand moves lower-funnel spend, and only then does the target respond.

Effects that do not depend on channel_data – a linear trend, an event window, seasonality – are part of the baseline. They cancel in the difference and are skipped without consulting their spec.

An effect whose contribution cannot be located at all is not an error here. Duck-typed effects are a documented pattern (see the module docstring of additive_effect) and need not carry a contribution_var_name; a MuEffect built without a prefix raises NotImplementedError rather than returning one. Neither says anything about whether spend reaches the effect, so the failure is deferred: such an effect is left unaccounted, and SpendProbe.assert_increment_is_complete() raises only if a spend path really does escape through it. Raising eagerly instead would break every model that merely owns such an effect. This is distinct from an AttributeError raised inside a present contribution_var_name (for example a property that touches a missing self attribute): that is a bug in the effect, not an absent attribute, and propagates instead of being swallowed.

Parameters:
modelMMM

The fitted model whose mu_effects are being resolved.

Returns:
tuple of ChannelDependentEffect

One entry per effect to include, in mu_effects order. Empty for a model with no channel-dependent effects, which is the separable case the incrementality module was originally written for.

Raises:
NotImplementedError

If an effect is known to depend on channel_data but has not opted in via incrementality_spec(). A refusal to guess: the alternative is dropping a real part of the increment and reporting the remainder as if it were the whole.

ValueError

If an included effect’s contribution carries dimensions outside ("date", *model.dims).

AttributeError

Propagated unchanged if an effect’s contribution_var_name property is present but raises while computing its value, rather than being mistaken for an absent attribute.