sensitivity_analysis#
Counterfactual sweeps for Marketing Mix Models (MMM).
Quick start#
SensitivityAnalysis can work with any PyMC model whose response depends on an
input pm.Data tensor. The functional relationship between inputs and the
response can be arbitrary (e.g., adstock, saturation, splines, custom
PyTensor ops). You only need to provide:
the name of the input data variable (
var_input, e.g.,"channel_data"),the name of the deterministic/response variable you want to analyze (
var_names, e.g.,"channel_contribution"),a grid of
sweep_values, and the sweep type.
Example#
The example below uses an arbitrary saturation transformation, but any PyTensor-compatible transformation will work the same way.
import numpy as np
import pymc as pm
from pymc_marketing.mmm.sensitivity_analysis import SensitivityAnalysis
def saturation(x, alpha, lam):
return (alpha * x) / (x + lam)
coords = {"date": np.arange(52), "channel": list("abcde")}
with pm.Model(coords=coords) as m:
X = pm.Data(
"channel_data",
np.random.Gamma(13, 12, size=(52, 5)),
dims=("date", "channel"),
)
alpha = pm.Gamma("alpha", 1, 1, dims="channel")
lam = pm.Gamma("lam", 1, 1, dims="channel")
contrib = pm.Deterministic(
"channel_contribution", saturation(X, alpha, lam), dims=("date", "channel")
)
mu = pm.Normal("intercept", 0.0, 1.0) + contrib.sum(axis=-1)
pm.Normal("likelihood", mu=mu, sigma=1.0, dims=("date",))
idata = pm.sample(1000, tune=500, chains=2, target_accept=0.95, random_seed=42)
sa = SensitivityAnalysis(m, idata)
sweeps = np.linspace(0.2, 3.0, 8)
# Jacobian-based marginal effects with respect to the input; shape: (sample, sweep, channel)
result = sa.run_sweep(
sweep_values=sweeps,
var_input="channel_data",
var_names="channel_contribution",
sweep_type="multiplicative",
)
# Optional (backwards-compatibility): returns `result` unchanged because `run_sweep`
# already yields marginal effects. Kept to avoid breaking older code.
me = SensitivityAnalysis.compute_marginal_effects(result, sweeps)
Notes#
Arbitrary models: As long as the response graph depends (directly or indirectly) on the
pm.Dataprovided viavar_input, and you pass the name of the deterministic/response viavar_names, the class builds the Jacobian and evaluates it across sweeps automatically.Multi-dimensional inputs: If
var_inputhas dims like(date, country, channel), the output shape is(sample, sweep, country, channel). You can subset withvar_names_filter={"country": ["usa"], "channel": ["a", "b"]}.Sweep types:
"multiplicative","additive", and"absolute"are supported.To persist results, pass
extend_idata=Trueto store them underidata.sensitivity_analysis.
Classes
|
SensitivityAnalysis class is used to perform counterfactual analysis on MMM's. |