BudgetOptimizer#

class pymc_marketing.mmm.budget_optimizer.BudgetOptimizer(**data)[source]#

A class for optimizing budget allocation in a marketing mix model.

The goal of this optimization is to maximize the total expected response by allocating the given budget across different marketing channels. The optimization is performed using the Sequential Least Squares Quadratic Programming (SLSQP) method, which is a gradient-based optimization algorithm suitable for solving constrained optimization problems.

For more information on the SLSQP algorithm, refer to the documentation: https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html

Parameters:
modelpm.Model

The PyMC model configured for the optimization horizon. The model must contain a pm.Data variable named channel_data_var (default "channel_data") whose dims include the channel and, optionally, additional dimensions (e.g. geo).

idataxarray.DataTree or arviz.InferenceData

Fitted posterior inference data from the model.

num_periodsint

Number of time units at the desired time granularity to allocate budget for.

adstock_periodsint, optional

Number of extra warm-up periods prepended for adstock carryover. Equivalent to adstock.l_max on the built-in MMM. Defaults to 0.

channel_scalesfloat or array_like, optional

Per-channel scale factors used to convert monetary budgets into the model’s native units. A scalar 1.0 means no scaling. Defaults to 1.0.

optimizable_varsdict, optional

Additional one-dimensional, non-date pm.Data variables to co-optimize alongside the media budgets, keyed by name, each mapped to its native (low, high) bounds per entry (or None for unbounded). Levers are optimized in their own units and stay out of the default budget-sum constraint. Defaults to no levers. mu_effects are not a parameter: effects are baked into the model graph at build time.

frozen_deterministicslist of str, optional

Names of Deterministic variables to freeze at their posterior values instead of recomputing them from the graph. Required for models with HSGP or time-varying components. Defaults to None.

response_variablestr, optional

The response variable to optimize. Default is "total_media_contribution_original_scale", which is built from the channel contribution alone. A model whose response partly travels through a MuEffect – a funnel mediator, or an effect carrying an optimizable lever – should pass "total_response_original_scale" instead, since the default cannot see those contributions and a budget optimized against it undervalues whatever drives them. budget_optimizer() warns when it detects that case, but constructing this class directly cannot – it has no view of the model’s effects – so silence here is not evidence that the default is the right objective.

utility_functionUtilityFunctionType, optional

The utility function to maximize. Default is the mean of the response distribution.

budgets_to_optimizexarray.DataArray, optional

Mask defining a subset of budgets to optimize. Non-optimized budgets remain fixed at 0.

constraintsSequence[Constraint], optional

Constraints for the optimizer. If empty, a default sum-equals-total-budget constraint is added automatically. If non-empty, the caller is in charge: no default is added. Pass build_default_sum_constraint() explicitly to keep the sum constraint alongside custom ones.

budget_distribution_over_periodxarray.DataArray, optional

Fixed temporal distribution of each budget cell across periods. Must have dims ("date", *budget_dims) where the "date" dim has length num_periods. Values must sum to 1 along the "date" dim for every combination of the remaining dims (i.e., budget_distribution_over_period.sum(dim="date") must be all ones). Each value is the fraction of that cell’s total budget assigned to the corresponding period, e.g. fractions [0.4, 0.3, 0.2, 0.1] along "date" mean 40 % of the budget in period 0, 30 % in period 1, and so on. If None, budget is distributed uniformly (1 / num_periods per period).

channel_data_varstr, optional

Name of the pm.Data variable inside model that holds channel spend / media inputs. Defaults to "channel_data".

channel_contribution_varstr, optional

Name of the per-channel contribution variable in the posterior used to auto-detect non-zero channels. Defaults to "channel_contribution".

date_dimstr, optional

Name of the date dimension in the model. Defaults to "date".

cost_per_unitxarray.DataArray, optional

Cost-per-unit conversion factors for translating monetary budgets into the model’s native units. Must have dims ("date", *budget_dims) where "date" has length num_periods. If None, budgets are assumed to already be in the model’s native units.

compile_kwargsdict, optional

Extra keyword arguments forwarded to PyTensor’s function() during compilation. Useful for setting mode.

Notes

For backward compatibility, pass a legacy wrapper (implementing OptimizerCompatibleModel) as model=, the optimizer will unpack it automatically via a model_validator.

Examples

Basic usage, pass a PyMC model and its posterior inference data directly:

import pymc_marketing as pmm

# mmm is a fitted multidimensional MMM
pymc_model = mmm.create_optimization_model(
    start_date="2025-01-01",
    end_date="2025-03-31",
)
optimizer = pmm.mmm.BudgetOptimizer(
    model=pymc_model,
    idata=mmm.idata,
    num_periods=13,
    # The model's date axis is carry-in + decisions + carry-over, each
    # flank effective_carryover_lags() wide; the three must add up to it.
    carry_in_periods=mmm.effective_carryover_lags(),
    adstock_periods=mmm.effective_carryover_lags(),
    response_variable="total_media_contribution_original_scale",
)
optimal, result = optimizer.allocate_budget(total_budget=100_000)

Methods

BudgetOptimizer.__init__(**data)

Create a new model by parsing and validating input data from keyword arguments.

BudgetOptimizer.allocate_budget(total_budget)

Allocate the budget based on total_budget, optional budget_bounds, and custom constraints.

BudgetOptimizer.construct([_fields_set])

BudgetOptimizer.copy(*[, include, exclude, ...])

Returns a copy of the model.

BudgetOptimizer.dict(*[, include, exclude, ...])

BudgetOptimizer.extract_response_distribution(...)

Extract the response distribution graph, conditioned on posterior parameters.

BudgetOptimizer.from_orm(obj)

BudgetOptimizer.json(*[, include, exclude, ...])

BudgetOptimizer.model_parametrized_name(params)

Compute the class name for parametrizations of generic classes.

BudgetOptimizer.parse_file(path, *[, ...])

BudgetOptimizer.parse_obj(obj)

BudgetOptimizer.parse_raw(b, *[, ...])

BudgetOptimizer.schema([by_alias, ref_template])

BudgetOptimizer.schema_json(*[, by_alias, ...])

BudgetOptimizer.set_constraints(constraints)

Set constraints for the optimizer.

BudgetOptimizer.update_forward_refs(**localns)

BudgetOptimizer.validate(value)

Attributes

DEFAULT_MINIMIZE_KWARGS

model_computed_fields

model_config

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_extra

Get extra fields set during validation.

model_fields

model_fields_set

Returns the set of fields that have been explicitly set on this model instance.

optimization_variables

The decision vector's variables: media, plus any optimizable_vars.

num_periods

model

idata

adstock_periods

carry_in_periods

channel_scales

spend_vars

spend_var_scales

optimizable_vars

response_variable

utility_function

budgets_to_optimize

constraints

budget_distribution_over_period

cost_per_unit

compile_kwargs

frozen_deterministics

channel_data_var

channel_contribution_var

date_dim