Skip to content

Guide: Performing Budget Optimisation

This guide explains how to use the budget optimisation features within the ammm library.

Budget optimisation aims to find the allocation of a total marketing budget across different channels that is predicted to maximise the overall contribution (e.g., sales, conversions), based on the fitted MMM and the estimated response curves for each channel. The core principle behind this is to allocate spend to channels where the marginal ROI (mROI)—the return from the next dollar spent—is highest, until the mROIs equalize across channels or budget constraints are met.

Under a fixed total budget, AMMM’s optimiser maximises total expected contribution:

\max_{\{S_i\}} \sum_i C_i(S_i) \quad \text{subject to} \quad \sum_i S_i = B

This is equivalent to maximising overall ROI for that fixed budget (total_contribution / total_spend).

  1. A fitted MMM model
  2. Response curve parameters for each channel (e.g. (alpha, lam) for the sigmoid curve)

AMMM estimates per-channel response curves via a two-step approximation:

  1. Compute per-channel contributions from the fitted Bayesian MMM (often using posterior means).
  2. Fit a simple saturating curve (sigmoid or Michaelis–Menten) to the (spend, contribution) relationship using scipy.optimize.curve_fit.

In code, the typical entrypoint is the model mixin method:

sigmoid_params = driver.model.compute_channel_curve_optimization_parameters_original_scale(method="sigmoid")

Then optimisation uses these parameters to allocate a fixed total budget.

This example demonstrates how to run the budget optimiser in a self-contained way.

In practice, you estimate the response curve parameters from a fitted MMM (for example by using the optimisation helper methods on the model).

import core.opt as opt
print("Running a self-contained optimisation example...")
# Channels to allocate budget across
channels = ["channel_1", "channel_2", "channel_3"]
# Example sigmoid response parameters for each channel: (alpha, lam)
# In practice, you estimate these from a fitted MMM.
parameters = {
"channel_1": (50_000.0, 1.0e-5),
"channel_2": (60_000.0, 8.0e-6),
"channel_3": (40_000.0, 1.2e-5),
}
total_budget = 100_000.0
# Optional per-channel min/max bounds
budget_ranges = {
"channel_1": (0.0, 60_000.0),
"channel_2": (0.0, 70_000.0),
"channel_3": (0.0, 50_000.0),
}
results = opt.budget_allocator(
method="sigmoid",
total_budget=total_budget,
channels=channels,
parameters=parameters,
budget_ranges=budget_ranges,
)
print("Optimisation results:")
print(results)
# The output DataFrame shows the estimated contribution and the optimal budget
# for each channel, as well as the total.

The output of the example script will be a DataFrame that looks something like this (values will vary):

estimated_contribution optimal_budget

channel_1 25000.00 30000.00 channel_2 35000.00 40000.00 … total 150000.00 160000.00

  • optimal_budget: This column shows the suggested budget allocation after optimisation. Compare this to the historical spend to see the recommended shifts.
  • estimated_contribution: This column shows the estimated contribution from each channel based on the optimal budget.
  • Approximation: The optimisation relies on the accuracy of the fitted parametric response curves (e.g., sigmoid). These are approximations of the true, non-parametric response curves from the Bayesian model.
  • Total Budget: The optimisation allocates a fixed total budget. It suggests how to best spend that amount, not whether to increase or decrease the total budget.
  • Constraints: If you provide budget_ranges, the optimizer will respect them. This is useful for incorporating business constraints.
  • Model Accuracy: The optimisation is only as good as the underlying MMM fit. Ensure your main model diagnostics are satisfactory before trusting the optimization results.

Single-period optimisation uses SciPy’s constrained optimiser:

  • scipy.optimize.minimize(..., method="SLSQP")
  • equality constraint: Σ S_i = B
  • bounds: per-channel min/max

For multi-period planning, see the dedicated guide: Multi-Period Optimization.