This document describes fixed and flexible budget scenarios and gives example code to help you understand how to customize your budget optimization.
Fixed budget: Maximize ROI or incremental KPI
In this scenario for a given budget, you can find the optimal allocation across
channels and tactics to maximize the return on investment (ROI). If kpi_type
is set to non-revenue and revenue_per_kpi
is unknown, the fixed budget
scenario finds the optimal allocation to maximize the incremental KPI.
This scenario represents the default settings and runs if you call the
optimize()
method from the BudgetOptimizer
class without any additional
arguments. There is also the option to modify the fixed budget scenario by
altering the optimization time window, inputting distinct budget and
pre-optimized media spend allocations, and indicating the lower and upper limits
for media expenditures.
Example code
The following code example shows a customized fixed budget scenario:
budget_optimizer = optimizer.BudgetOptimizer(meridian)
pct_of_spend = {
'Channel0': 0.2,
'Channel1': 0.2,
'Channel2': 0.2,
'Channel3': 0.1,
'Channel4': 0.2,
'Channel5': 0.1,
}
spend_constraint = {
'Channel0': 0.3,
'Channel1': 0.2,
'Channel2': 0.3,
'Channel3': 0.3,
'Channel4': 0.3,
'Channel5': 0.2,
}
build_channel_args = meridian.input_data.get_paid_channels_argument_builder()
optimization_results = budget_optimizer.optimize(
selected_times=('2023-01-16', '2024-01-15'),
budget=70_000_000,
pct_of_spend=build_channel_args(**pct_of_spend),
spend_constraint_lower=build_channel_args(**spend_constraint),
spend_constraint_upper=build_channel_args(**spend_constraint),
)
Key parameters
selected_times
: Tuple containing the start and end time dimensions for the duration to run the optimization on. Time dimensions should align with the Meridian time dimensions. By default, all time periods are used.Example
To modify the date range:
budget_optimizer = optimizer.BudgetOptimizer(meridian) opt = budget_optimizer.optimize(selected_times=('2023-01-16','2024-01-15')) # date range from week 100 to 200
budget
: Number indicating the total budget for the fixed budget scenario. Defaults to the historical budget.Example
To change the budget to
70_000_000
:budget_optimizer = optimizer.BudgetOptimizer(meridian) opt = budget_optimizer.optimize(budget=70_000_000)
pct_of_spend
: Numeric list of sizen_paid_channels
containing the percentage allocations for channel spend. The order must match(InputData.media + InputData.reach)
with values between 0-1, summing to1
. By default, the historical allocation is used. Budget and allocation are used in conjunction to determine the non-optimized media-level spend, which is used to calculate the non-optimized performance metrics (for example, ROI) and construct the feasible range of media-level spend with the spend constraints.Example
To specify the allocation:
budget_optimizer = optimizer.BudgetOptimizer(meridian) opt = budget_optimizer.optimize( pct_of_spend=build_channel_args( Channel0=0.2, Channel1=0.2, Channel2=0.2, Channel4=0.1, Channel5=0.2, Channel6=0.1, ), # non-optimized allocation is 20% to Channel0, 20% to Channel1 etc )
spend_constraint_lower
: Numeric list of lengthn_paid_channels
to use different spend constraints for different channels, or a singlefloat
value as the same spend constraint for all media channels. If given as a channel-indexed array, the order must match(InputData.media + InputData.reach)
. Indicates the lower bound of media-level spend. The lower bound of media-level spend is((1 - spend_constraint_lower) * budget * allocation)
. The value entered must be between 0-1. The default value is 0.3 (meaning 70% of media spend) for a fixed budget and 1 (meaning 0% of media spend) for a flexible budget.Example
To change the lower spend constraint:
budget_optimizer = optimizer.BudgetOptimizer(meridian) build_channel_args = build_channel_args.with_default_value(0.3) opt = budget_optimizer.optimize( spend_constraint_lower=build_channel_args( Channel1=0.2, Channel5=0.2, ), # change the lower bound to 70%, 80%, 70%, 70%, 70% and 80% of media spends )
spend_constraint_upper
: Numeric list of lengthn_paid_channels
to use different spend constraints for different channels, or a singlefloat
value as the same spend constraint for all media channels. If given as a channel-indexed array, the order must match(InputData.media + InputData.reach)
. Indicates the upper bound of media-level spend. The upper bound of media-level spend is(1 + spend_constraint_upper) * budget * allocation)
. The default value is 0.3 (meaning 130% of media spend) for a fixed budget and 1 (meaning 200% of media spend) for a flexible budget.Example
To change the upper spend constraint:
budget_optimizer = optimizer.BudgetOptimizer(meridian) build_channel_args = build_channel_args.with_default_value(0.3) opt = budget_optimizer.optimize( spend_constraint_upper=build_channel_args( Channel1=0.2, Channel5=0.2, ), # change the upper bound to 130%, 120%, 130%, 130%, 130% and 120% of media spends )
Flexible budget: Target minimum ROI
In this scenario for a flexible budget, you input a specific minimum ROI target. This option lets you find out what is the maximum budget you can spend without any budget limit until the overall ROI hits X at the total marketing level. Meridian provides a recommended maximum budget, as well as an optimal allocation of the budget across media channels, to achieve that ROI target. Notably, the target ROI constraint is applied at the total marketing ROI level and not at channel level.
Example code
The following code example shows a customized flexible budget scenario with a target minimum ROI:
budget_optimizer = optimizer.BudgetOptimizer(meridian)
optimization_results = budget_optimizer.optimize(
selected_times=('2023-01-16','2024-01-15'),
fixed_budget=False,
spend_constraint_lower=0.5,
spend_constraint_upper=0.5,
target_roi=1,
)
Key parameters
fixed_budget
: Boolean indicating whether it is a fixed budget optimization or flexible budget optimization. Defaults toTrue
, indicating a fixed budget. IfFalse
, you must also specify eithertarget_roi
ortarget_mroi
.target_roi
: Float indicating the target ROI constraint. Only used for flexible budget scenarios. The budget is constrained to when the ROI of the total media spend hitstarget_roi
.Example
To switch to flexible budget scenario and set the target ROI to
1
:budget_optimizer = optimizer.BudgetOptimizer(meridian) opt = budget_optimizer.optimize(fixed_budget=False, target_roi=1)
selected_times
: Tuple containing the start and end time dimensions for the duration to run the optimization on. Time dimensions should align with the Meridian time dimensions. By default, all time periods are used.pct_of_spend
: Numeric list of sizen_paid_channels
containing the percentage allocation for the media spend. The order must match(InputData.media + InputData.reach)
with values between 0-1, summing to1
. By default, the historical allocation is used. Budget and allocation are used in conjunction to determine the non-optimized media-level spend, which is used to calculate the non-optimized performance metrics (for example, ROI) and construct the feasible range of media-level spend with the spend constraints.spend_constraint_lower
: Numeric list of lengthn_paid_channels
to use different spend constraints for different channels, or a singlefloat
value as the same spend constraint for all media channels. If given as a channel-indexed array, the order must match(InputData.media + InputData.reach)
. Indicates the lower bound of media-level spend. The lower bound of media-level spend is((1 - spend_constraint_lower) * budget * allocation)
. The value entered must be between 0-1. The default value is 0.3 (meaning 70% of media spend) for a fixed budget and 1 (meaning 0% of media spend) for a flexible budget.spend_constraint_upper
: Numeric list of lengthn_paid_channels
to use different spend constraints for different channels, or a singlefloat
value as the same spend constraint for all media channels. If given as a channel-indexed array, the order must match(InputData.media + InputData.reach)
. Indicates the upper bound of media-level spend. The upper bound of media-level spend is(1 + spend_constraint_upper) * budget * allocation)
. The default value is 0.3 (meaning 130% of media spend) for a fixed budget and 1 (meaning 200% of media spend) for a flexible budget.
Flexible budget: Target marginal ROI
In this scenario for a flexible budget, you input a marginal ROI target for incremental spend. This option tells what is the maximum budget you can spend without any budget limit until the marginal ROI of each media channel hits the target marginal ROI. It's still possible that the marginal ROI of some channels won't be equal to the target marginal ROI due to the feasible range of media spend. However, the marginal ROI will effectively shrink toward the target marginal ROI. Notably, the target marginal ROI is applied at channel level and not at the total marketing level.
Example code
The following code examples shows a customized flexible budget scenario with a target marginal ROI:
budget_optimizer = optimizer.BudgetOptimizer(meridian)
optimization_results = budget_optimizer.optimize(
selected_times=('2023-01-16','2024-01-15'),
fixed_budget=False,
spend_constraint_lower=0.5,
spend_constraint_upper=0.5,
target_mroi=1,
)
Key parameters
fixed_budget
: Boolean indicating whether it is a fixed budget optimization or flexible budget optimization. Defaults toTrue
, indicating a fixed budget. IfFalse
, you must specify eithertarget_roi
ortarget_mroi
.target_mroi
: Float indicating the target marginal ROI constraint. Only used for flexible budget scenarios. The budget is constrained to when the marginal ROI of the total media spend hitstarget_mroi
.Example
To switch to flexible budget scenario and set the target marginal ROI to
1
:budget_optimizer = optimizer.BudgetOptimizer(meridian) opt = budget_optimizer.optimize(fixed_budget=False, target_mroi=1)
selected_times
: Tuple containing the start and end time dimensions for the duration to run the optimization on. Time dimensions should align with the Meridian time dimensions. By default, all time periods are used.pct_of_spend
: Numeric list of sizen_paid_channels
containing the percentage allocation for the media spend. The order must match(InputData.media + InputData.reach)
with values between 0-1, summing to1
. By default, the historical allocation is used. Budget and allocation are used in conjunction to determine the non-optimized media-level spend, which is used to calculate the non-optimized performance metrics (for example, ROI) and construct the feasible range of media-level spend with the spend constraints.spend_constraint_lower
: Numeric list of lengthn_paid_channels
to use different spend constraints for different channels, or a singlefloat
value as the same spend constraint for all media channels. If given as a channel-indexed array, the order must match(InputData.media + InputData.reach)
. Indicates the lower bound of media-level spend. The lower bound of media-level spend is((1 - spend_constraint_lower) * budget * allocation)
. The value entered must be between 0-1. The default value is 0.3 (meaning 70% of media spend) for a fixed budget and 1 (meaning 0% of media spend) for a flexible budget.spend_constraint_upper
: Numeric list of lengthn_paid_channels
to use different spend constraints for different channels, or a singlefloat
value as the same spend constraint for all media channels. If given as a channel-indexed array, the order must match(InputData.media + InputData.reach)
. Indicates the upper bound of media-level spend. The upper bound of media-level spend is(1 + spend_constraint_upper) * budget * allocation)
. The default value is 0.3 (meaning 130% of media spend) for a fixed budget and 1 (meaning 200% of media spend) for a flexible budget.