Analysis

Counterfactual and marginal analysis over fitted models.

Analysis utilities for BayesianMMM.

This module provides helper classes for analyzing fitted Bayesian Marketing Mix Models, including counterfactual analysis, marginal contributions, and what-if scenarios.

class mmm_framework.analysis.MarginalAnalysisResult(channel, current_spend, spend_increase, spend_increase_pct, marginal_contribution, marginal_roas, marginal_contribution_hdi_low=None, marginal_contribution_hdi_high=None, marginal_roas_hdi_low=None, marginal_roas_hdi_high=None, hdi_prob=None)[source]

Bases: object

Result of marginal contribution analysis.

Attributes

channelstr

Channel name.

current_spendfloat

Current total spend in the period.

spend_increasefloat

Absolute spend increase.

spend_increase_pctfloat

Percentage spend increase.

marginal_contributionfloat

Additional outcome from the spend increase (posterior mean).

marginal_roasfloat

Return on additional spend (posterior mean).

marginal_contribution_hdi_low, marginal_contribution_hdi_highfloat | None

Credible-interval bounds on the marginal contribution, propagated from the posterior. None when uncertainty was not computed.

marginal_roas_hdi_low, marginal_roas_hdi_highfloat | None

Credible-interval bounds on the marginal ROAS. None when uncertainty was not computed. The headline efficiency number should always be read with this interval – a marginal ROAS point estimate with no uncertainty is the §3.9 problem the framework set out to fix.

hdi_probfloat | None

Probability mass of the reported HDI (e.g. 0.94).

channel: str
current_spend: float
spend_increase: float
spend_increase_pct: float
marginal_contribution: float
marginal_roas: float
marginal_contribution_hdi_low: float | None = None
marginal_contribution_hdi_high: float | None = None
marginal_roas_hdi_low: float | None = None
marginal_roas_hdi_high: float | None = None
hdi_prob: float | None = None
__init__(channel, current_spend, spend_increase, spend_increase_pct, marginal_contribution, marginal_roas, marginal_contribution_hdi_low=None, marginal_contribution_hdi_high=None, marginal_roas_hdi_low=None, marginal_roas_hdi_high=None, hdi_prob=None)
class mmm_framework.analysis.ScenarioResult(baseline_outcome, scenario_outcome, outcome_change, outcome_change_pct, spend_changes, baseline_prediction, scenario_prediction)[source]

Bases: object

Result of a what-if scenario analysis.

Attributes

baseline_outcomefloat

Total outcome under baseline scenario.

scenario_outcomefloat

Total outcome under modified scenario.

outcome_changefloat

Absolute change in outcome.

outcome_change_pctfloat

Percentage change in outcome.

spend_changesdict[str, dict]

Spend change details by channel.

baseline_predictionNDArray

Full baseline prediction array.

scenario_predictionNDArray

Full scenario prediction array.

baseline_outcome: float
scenario_outcome: float
outcome_change: float
outcome_change_pct: float
spend_changes: dict[str, dict]
baseline_prediction: NDArray
scenario_prediction: NDArray
__init__(baseline_outcome, scenario_outcome, outcome_change, outcome_change_pct, spend_changes, baseline_prediction, scenario_prediction)
class mmm_framework.analysis.MMMAnalyzer(model)[source]

Bases: object

Analyzer for fitted BayesianMMM models.

Provides methods for: - Counterfactual contribution analysis - Marginal contribution analysis - What-if scenario modeling

Parameters

modelBayesianMMM

A fitted BayesianMMM model.

Examples

>>> from mmm_framework.analysis import MMMAnalyzer
>>> analyzer = MMMAnalyzer(fitted_model)
>>> contributions = analyzer.compute_counterfactual_contributions()
>>> print(contributions.summary())
>>> marginal = analyzer.compute_marginal_contributions(spend_increase_pct=10)
>>> print(marginal)
__init__(model)[source]
property channel_names: list[str]

Get channel names from the model.

property n_obs: int

Get number of observations.

get_time_mask(time_period)[source]

Get time mask for filtering observations.

Parameters

time_periodtuple[int, int] | None

(start_idx, end_idx) inclusive, or None for all.

Returns

NDArray[np.bool_]

Boolean mask array.

compute_counterfactual_contributions(time_period=None, channels=None, compute_uncertainty=True, hdi_prob=0.94, random_seed=None)[source]

Compute channel contributions using counterfactual analysis.

This is a convenience wrapper around the model’s method.

Return type:

ContributionResults

Parameters

time_periodtuple[int, int], optional

Time period (start_idx, end_idx) for calculation.

channelslist[str], optional

Channels to analyze. If None, uses all.

compute_uncertaintybool

Whether to compute HDI for contributions.

hdi_probfloat

HDI probability mass.

random_seedint, optional

Random seed for reproducibility.

Returns

ContributionResults

Contribution results container.

compute_marginal_contributions(spend_increase_pct=10.0, time_period=None, channels=None, compute_uncertainty=True, hdi_prob=0.94, random_seed=None)[source]

Compute marginal contributions for a given spend increase.

This is a convenience wrapper around the model’s method.

Return type:

DataFrame

Parameters

spend_increase_pctfloat

Percentage increase in spend to simulate.

time_periodtuple[int, int], optional

Time period for calculation.

channelslist[str], optional

Channels to analyze. If None, uses all.

compute_uncertaintybool

If True (default), propagate posterior uncertainty and include HDI bounds on marginal contribution and marginal ROAS.

hdi_probfloat

Probability mass for the HDI.

random_seedint, optional

Random seed for reproducibility.

Returns

pd.DataFrame

Marginal contribution analysis (with HDI columns when compute_uncertainty is True).

what_if_scenario(spend_changes, time_period=None, random_seed=None)[source]

Run a what-if scenario with custom spend changes.

This is a convenience wrapper around the model’s method.

Return type:

dict

Parameters

spend_changesdict[str, float]

Mapping of channel names to spend multipliers.

time_periodtuple[int, int], optional

Time period for calculation.

random_seedint, optional

Random seed for reproducibility.

Returns

dict

Scenario analysis results.

compute_channel_roi(time_period=None, random_seed=None)[source]

Compute return on investment for each channel.

ROI = Total Contribution / Total Spend

Return type:

DataFrame

Parameters

time_periodtuple[int, int], optional

Time period for calculation.

random_seedint, optional

Random seed for reproducibility.

Returns

pd.DataFrame

ROI analysis by channel.

compute_saturation_curves(channel, spend_range=None, n_points=50, random_seed=None)[source]

Compute saturation curve for a channel.

Shows how outcome changes across different spend levels.

Return type:

DataFrame

Parameters

channelstr

Channel to analyze.

spend_rangetuple[float, float], optional

(min, max) spend range. If None, uses 0 to 2x current max.

n_pointsint

Number of points on the curve.

random_seedint, optional

Random seed.

Returns

pd.DataFrame

Saturation curve data.

mmm_framework.analysis.compute_contribution_summary(contributions)[source]

Create a summary DataFrame from contribution results.

Return type:

DataFrame

Parameters

contributionsContributionResults

Contribution analysis results.

Returns

pd.DataFrame

Summary table.

mmm_framework.analysis.compute_period_contributions(contributions, periods, period_names=None)[source]

Compute contributions for multiple time periods.

Return type:

DataFrame

Parameters

contributionsContributionResults

Base contribution results.

periodslist[tuple[int, int]]

List of (start, end) period tuples.

period_nameslist[str], optional

Names for each period.

Returns

pd.DataFrame

Contributions by period.