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:
- model
pm.Model The PyMC model configured for the optimization horizon. The model must contain a
pm.Datavariable namedchannel_data_var(default"channel_data") whose dims include the channel and, optionally, additional dimensions (e.g. geo).- idata
xarray.DataTreeorarviz.InferenceData Fitted posterior inference data from the model.
- num_periods
int Number of time units at the desired time granularity to allocate budget for.
- adstock_periods
int, optional Number of extra warm-up periods prepended for adstock carryover. Equivalent to
adstock.l_maxon the built-in MMM. Defaults to 0.- channel_scales
floator array_like, optional Per-channel scale factors used to convert monetary budgets into the model’s native units. A scalar
1.0means no scaling. Defaults to 1.0.- optimizable_vars
dict, optional Additional one-dimensional, non-date
pm.Datavariables to co-optimize alongside the media budgets, keyed by name, each mapped to its native(low, high)bounds per entry (orNonefor unbounded). Levers are optimized in their own units and stay out of the default budget-sum constraint. Defaults to no levers.mu_effectsare not a parameter: effects are baked into the model graph at build time.- frozen_deterministics
listofstr, optional Names of
Deterministicvariables to freeze at their posterior values instead of recomputing them from the graph. Required for models with HSGP or time-varying components. Defaults toNone.- response_variable
str, 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 aMuEffect– 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_function
UtilityFunctionType, optional The utility function to maximize. Default is the mean of the response distribution.
- budgets_to_optimize
xarray.DataArray, optional Mask defining a subset of budgets to optimize. Non-optimized budgets remain fixed at 0.
- constraints
Sequence[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_period
xarray.DataArray, optional Fixed temporal distribution of each budget cell across periods. Must have dims
("date", *budget_dims)where the"date"dim has lengthnum_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_periodsper period).- channel_data_var
str, optional Name of the
pm.Datavariable insidemodelthat holds channel spend / media inputs. Defaults to"channel_data".- channel_contribution_var
str, optional Name of the per-channel contribution variable in the posterior used to auto-detect non-zero channels. Defaults to
"channel_contribution".- date_dim
str, optional Name of the date dimension in the model. Defaults to
"date".- cost_per_unit
xarray.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 lengthnum_periods. IfNone, budgets are assumed to already be in the model’s native units.- compile_kwargs
dict, optional Extra keyword arguments forwarded to PyTensor’s
function()during compilation. Useful for settingmode.
- model
Notes
For backward compatibility, pass a legacy wrapper (implementing
OptimizerCompatibleModel) asmodel=, the optimizer will unpack it automatically via amodel_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, optionalbudget_bounds, and custom constraints.BudgetOptimizer.construct([_fields_set])BudgetOptimizer.copy(*[, include, exclude, ...])Returns a copy of the model.
BudgetOptimizer.dict(*[, include, exclude, ...])Extract the response distribution graph, conditioned on posterior parameters.
BudgetOptimizer.json(*[, include, exclude, ...])Compute the class name for parametrizations of generic classes.
BudgetOptimizer.parse_file(path, *[, ...])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_KWARGSmodel_computed_fieldsmodel_configConfiguration for the model, should be a dictionary conforming to [
ConfigDict][pydantic.config.ConfigDict].model_extraGet extra fields set during validation.
model_fieldsmodel_fields_setReturns the set of fields that have been explicitly set on this model instance.
optimization_variablesThe decision vector's variables: media, plus any
optimizable_vars.num_periodsmodelidataadstock_periodscarry_in_periodschannel_scalesspend_varsspend_var_scalesoptimizable_varsresponse_variableutility_functionbudgets_to_optimizeconstraintsbudget_distribution_over_periodcost_per_unitcompile_kwargsfrozen_deterministicschannel_data_varchannel_contribution_vardate_dim