Abacus Core Mixins: Optimization (optimization.py)¶
This module provides the OptimizationMixin class, designed to be inherited by Marketing Mix Model (MMM) classes in Abacus. It offers experimental methods for analysing channel response curves and optimising budget allocation across channels to maximise expected contribution, based on the fitted model parameters and estimated saturation functions.
OptimizationMixin Class
This mixin assumes the inheriting class provides attributes and methods like:
X: The original input DataFrame used for training.channel_columns: List of channel names.compute_channel_contribution_original_scale(): A method (likely fromContributionMixin) that returns channel contributions in the original target scale.
Methods
compute_channel_curve_optimization_parameters_original_scale
def compute_channel_curve_optimization_parameters_original_scale(
self, method: str = "sigmoid"
) -> dict[str, tuple[float, float]]:
(Experimental) Estimates the parameters of a specified saturating function (Sigmoid or Michaelis-Menten) for each channel’s contribution curve.
This method fits either a Sigmoid or Michaelis-Menten function to the relationship between the historical spend (self.X) and the mean posterior channel contribution (obtained via compute_channel_contribution_original_scale) for each channel. The estimated parameters represent the saturation characteristics of each channel.
Parameters:
method(str, optional): The type of saturation function to fit. Options are"sigmoid"(default) or"michaelis-menten".
Returns:
dict[str, tuple[float, float]]: A dictionary where keys are channel names. Values are tuples containing the estimated parameters(alpha, lam)for the chosen saturation function:For Sigmoid:
alphais the limit (max contribution),lamis the shape parameter.For Michaelis-Menten:
alphais the limit (max contribution),lamis the spend level at which contribution is half ofalpha.
Raises:
ValueError: Ifmethodis not"sigmoid"or"michaelis-menten".RuntimeError: If the model hasn’t been fitted withXdata yet (required for estimating parameters).
Notes:
This method is marked as experimental. The accuracy of the estimated parameters depends on how well the chosen function fits the actual spend-contribution relationship derived from the model.
It uses helper functions (
ut.estimate_sigmoid_parameters,ut.estimate_menten_parameters) internally.
optimize_channel_budget_for_maximum_contribution
def optimize_channel_budget_for_maximum_contribution(
self,
method: str,
total_budget: int | float,
budget_bounds: Optional[dict[str, tuple[float, float]]] = None,
*,
parameters: dict[str, tuple[float, float]],
) -> pd.DataFrame:
(Experimental) Optimises the allocation of a total budget across channels to maximise the total expected contribution, based on pre-estimated saturation parameters.
This method uses a numerical optimisation routine (abacus.core.opt.budget_allocator) to find the distribution of total_budget among the specified channels that yields the highest sum of contributions, given that each channel’s contribution follows the saturation function defined by method and its corresponding parameters. Optional bounds can be set for individual channel budgets.
Parameters:
method(str): The saturation function assumed for the channels. Must match the method used to generateparameters. Options:"sigmoid"or"michaelis-menten".total_budget(int | float): The total budget available for allocation.budget_bounds(dict[str, tuple[float, float]], optional): A dictionary specifying minimum and maximum allowed budget for individual channels. Keys are channel names, values are(min_budget, max_budget)tuples. IfNone, bounds are effectively [0, infinity).parameters(dict[str, tuple[float, float]], keyword-only): Required. A dictionary providing the saturation parameters(alpha, lam)for each channel, typically obtained fromcompute_channel_curve_optimization_parameters_original_scale.
Returns:
pd.DataFrame: A DataFrame detailing the optimal budget allocation per channel and the corresponding expected contribution.
Raises:
TypeError: Ifbudget_boundsis provided but is not a dictionary.ValueError: Iftotal_budgetis not numeric, or if the required keyword-only argumentparametersis missing or empty.
Notes:
This method is marked as experimental. Its effectiveness depends on the accuracy of the
parametersprovided.It relies on the external function
abacus.core.opt.budget_allocatorto perform the optimisation.
(Private helper method _estimate_budget_contribution_fit is used internally for estimating contribution bounds, likely for plotting purposes not directly exposed in this mixin.)