src.core.opt

Provides functions for optimizing marketing budget allocation across channels.

This module includes utilities to calculate expected contributions based on different response curves (Michaelis-Menten, sigmoid) and to find the optimal budget distribution that maximizes total contribution given constraints.

Module Contents

src.core.opt.calculate_expected_contribution(method: str, parameters: Dict[str, Tuple[float, float]], budget: Dict[str, float]) Dict[str, float]

Calculate expected contributions using the specified model.

This function calculates the expected contributions for each channel based on the chosen model. The selected model can be either the Michaelis-Menten model or the sigmoid model, each described by specific parameters. As the allocated budget varies, the expected contribution is computed according to the chosen model.

Parameters:
  • method – The model to use for contribution estimation. Choose from ‘michaelis-menten’ or ‘sigmoid’.

  • parameters

    Model-specific parameters for each channel. For ‘michaelis-menten’, each entry is a tuple (L, k) where: - L is the maximum potential contribution. - k is the budget at which the contribution is half of its maximum.

    For ‘sigmoid’, each entry is a tuple (alpha, lam) where: - alpha controls the slope of the curve. - lam is the budget at which the curve transitions.

  • budget – A dictionary where keys are channel names and values are the allocated budgets for those channels.

Returns:

A dictionary with channels as keys and their respective contributions as values. The key ‘total’ contains the total expected contribution across all channels.

Raises:

ValueError – If the specified method is not recognized.

src.core.opt.objective_distribution(x: List[float], method: str, channels: List[str], parameters: Dict[str, Tuple[float, float]]) float

Compute the total contribution for a given budget distribution.

This function calculates the negative sum of contributions for a proposed budget distribution using the Michaelis-Menten model. This value will be minimized in the optimization process to maximize the total expected contribution.

Parameters:
  • x – The proposed budget distribution across channels.

  • method – The response curve method (‘michaelis-menten’ or ‘sigmoid’).

  • channels – The list of channels for which the budget is being optimized.

  • parameters – Model-specific parameters for each channel, as described in calculate_expected_contribution.

Returns:

Negative of the total expected contribution for the given budget distribution.

src.core.opt.optimize_budget_distribution(method: str, total_budget: int | float, budget_ranges: Dict[str, Tuple[float, float]] | None, parameters: Dict[str, Tuple[float, float]], channels: List[str]) Dict[str, float]

Optimize the budget allocation across channels to maximize total contribution.

Using the Michaelis-Menten or Sigmoid function, this function seeks the best budget distribution across channels that maximizes the total expected contribution.

This function leverages the Sequential Least Squares Quadratic Programming (SLSQP) optimization algorithm to find the best budget distribution across channels that maximizes the total expected contribution based on the Michaelis-Menten or Sigmoid functions.

The optimization is constrained such that: 1. The sum of budgets across all channels equals the total available budget. 2. The budget allocated to each individual channel lies within its specified range.

The SLSQP method is particularly suited for this kind of problem as it can handle both equality and inequality constraints.

Parameters:
  • method – The response curve method (‘michaelis-menten’ or ‘sigmoid’).

  • total_budget – The total budget to be distributed across channels.

  • budget_ranges – An optional dictionary defining the minimum and maximum budget for each channel. If None, ranges are inferred (0 to min(total_budget, L_value) for Michaelis-Menten).

  • parameters – Model-specific parameters for each channel, as described in calculate_expected_contribution.

  • channels – The list of channels for which the budget is being optimized.

Returns:

A dictionary with channels as keys and the optimal budget for each channel as values.

src.core.opt.budget_allocator(method: str, total_budget: int | float, channels: List[str], parameters: Dict[str, Tuple[float, float]], budget_ranges: Dict[str, Tuple[float, float]] | None) pandas.DataFrame

Allocate budget based on the specified method and constraints.

Parameters:
  • method – The method used for budget allocation (‘michaelis-menten’ or ‘sigmoid’).

  • total_budget – The total budget available for allocation.

  • channels – The list of channels to allocate the budget to.

  • parameters – Model-specific parameters for each channel.

  • budget_ranges – The budget ranges for each channel (min, max bounds).

Returns:

A DataFrame containing the estimated contribution and optimal budget allocation.

src.core.opt.calculate_seasonal_effectiveness(periods: List[int], seasonality_patterns: Dict[str, numpy.ndarray], channels: List[str], baseline_effectiveness: float = 1.0) Dict[int, Dict[str, float]]

Calculate channel effectiveness multipliers for each period based on seasonality.

Parameters:
  • periods – List of time period indices (e.g., week numbers, 0-indexed).

  • seasonality_patterns – Dictionary mapping channel names to arrays of seasonal multipliers. Each array should have length >= max(periods) + 1.

  • channels – List of channel names to calculate effectiveness for.

  • baseline_effectiveness – Base effectiveness value (default 1.0 = no adjustment).

Returns:

Dictionary mapping period index to channel effectiveness multipliers. Format: {period_idx: {channel: effectiveness_multiplier}}

Example

>>> seasonality = {
...     'google': np.array([0.9, 0.95, 1.05, 1.1]),
...     'facebook': np.array([0.85, 0.9, 1.1, 1.15])
... }
>>> result = calculate_seasonal_effectiveness(
...     periods=[0, 1, 2],
...     seasonality_patterns=seasonality,
...     channels=['google', 'facebook']
... )
>>> result[0]['google']  # Period 0, Google effectiveness
0.9
src.core.opt.objective_multiperiod_distribution(x: numpy.ndarray, method: str, channels: List[str], parameters: Dict[str, Tuple[float, float]], n_periods: int, seasonal_effects: Dict[int, Dict[str, float]] | None = None) float

Compute total contribution across multiple periods (negative for minimization).

This function calculates the negative sum of contributions for a proposed budget distribution across multiple periods. The budget array x is structured as a flat array: [period0_channel0, period0_channel1, …, period1_channel0, …].

Parameters:
  • x – Flat array of budget allocations across all periods and channels. Length = n_periods * len(channels).

  • method – Response curve method (‘michaelis-menten’ or ‘sigmoid’).

  • channels – List of channel names.

  • parameters – Model-specific parameters for each channel.

  • n_periods – Number of time periods to optimize over.

  • seasonal_effects – Optional seasonal effectiveness multipliers. Format: {period_idx: {channel: multiplier}}. If None, no seasonal adjustment is applied (multiplier = 1.0).

Returns:

Negative of total expected contribution across all periods (for minimization).

src.core.opt.optimize_multiperiod_budget_distribution(method: str, total_budget: int | float, budget_ranges: Dict[str, Tuple[float, float]], parameters: Dict[str, Tuple[float, float]], channels: List[str], n_periods: int, seasonal_effects: Dict[int, Dict[str, float]] | None = None, period_budget_limits: Tuple[float, float] | None = None, optimization_method: str = 'SLSQP', max_iterations: int = 1000) Dict[int, Dict[str, float]]

Optimize budget allocation across multiple periods and channels.

This function finds the optimal distribution of a total budget across multiple time periods and marketing channels to maximize total expected contribution. It can optionally account for seasonal variations in channel effectiveness and impose per-period budget constraints.

Parameters:
  • method – Response curve method (‘michaelis-menten’ or ‘sigmoid’).

  • total_budget – Total budget to distribute across all periods and channels.

  • budget_ranges – Budget ranges (min, max) for each channel per period. Format: {channel: (min_budget, max_budget)}.

  • parameters – Model-specific parameters for each channel.

  • channels – List of channel names.

  • n_periods – Number of time periods to optimize over.

  • seasonal_effects – Optional seasonal effectiveness multipliers. Format: {period_idx: {channel: multiplier}}. Defaults to None.

  • period_budget_limits – Optional (min, max) budget limits per period. If specified, each period’s total budget must fall within these limits. Defaults to None (no per-period limits).

  • optimization_method – Scipy optimization method to use. Defaults to ‘SLSQP’.

  • max_iterations – Maximum number of optimization iterations. Defaults to 1000.

Returns:

Dictionary mapping period index to channel budgets. Format: {period_idx: {channel: budget}}.

Example

>>> result = optimize_multiperiod_budget_distribution(
...     method='sigmoid',
...     total_budget=1000000,
...     budget_ranges={'google': (0, 50000), 'facebook': (0, 80000)},
...     parameters={'google': (0.5, 10000), 'facebook': (0.6, 15000)},
...     channels=['google', 'facebook'],
...     n_periods=4
... )
>>> result[0]['google']  # Budget for Google in period 0
25000.0