![]() |
Runs and outputs budget optimization scenarios on your model.
meridian.analysis.optimizer.BudgetOptimizer(
meridian: meridian.model.model.Meridian
)
Finds the optimal budget allocation that maximizes outcome based on various scenarios where the budget, data, and constraints can be customized. The results can be viewed as plots and as an HTML summary output page.
Methods
create_optimization_grid
create_optimization_grid(
new_data: (xr.Dataset | None) = None,
use_posterior: bool = True,
selected_times: (tuple[str | None, str | None] | None) = None,
start_date: meridian.data.time_coordinates.Date
= None,
end_date: meridian.data.time_coordinates.Date
= None,
budget: (float | None) = None,
pct_of_spend: (Sequence[float] | None) = None,
spend_constraint_lower: _SpendConstraint = c.SPEND_CONSTRAINT_DEFAULT,
spend_constraint_upper: _SpendConstraint = c.SPEND_CONSTRAINT_DEFAULT,
gtol: float = 0.0001,
use_optimal_frequency: bool = True,
use_kpi: bool = False,
batch_size: int = c.DEFAULT_BATCH_SIZE
) -> meridian.analysis.optimizer.OptimizationGrid
Creates a OptimizationGrid for optimization.
If start_date
or end_date
is specified, then the default values are
inferred based on the subset of time periods specified. Both start and end
time selectors should align with the Meridian time dimension coordinates in
the underlying model if optimizing the original data. If new_data
is
provided with a different number of time periods than in InputData
, then
the start and end time coordinates must match the time dimensions in
new_data.time
. By default, all times periods are used. Either start or
end time component can be None
to represent the first or the last time
coordinate, respectively.
Args | |
---|---|
new_data
|
An optional DataTensors container with optional tensors:
media , reach , frequency , media_spend , rf_spend ,
revenue_per_kpi , and time . If None , the original tensors from the
Meridian object are used. If new_data is provided, the grid is created
using the versions of the tensors in new_data and the original
versions of all the remaining tensors. If any of the tensors in
new_data is provided with a different number of time periods than in
InputData , then all tensors must be provided with the same number of
time periods and the time tensor must be provided.
|
use_posterior
|
Boolean. If True , then the incremental outcome is derived
from the posterior distribution of the model. Otherwise, the prior
distribution is used.
|
selected_times
|
Deprecated. Tuple containing the start and end time
dimension coordinates. Please Use start_date and end_date instead.
|
start_date
|
Optional start date selector, inclusive, in yyyy-mm-dd
format. Default is None , i.e. the first time period.
|
end_date
|
Optional end date selector, inclusive in yyyy-mm-dd format.
Default is None , i.e. the last time period.
|
budget
|
Number indicating the total budget for the fixed budget scenario. Defaults to the historical budget. |
pct_of_spend
|
Numeric list of size n_paid_channels containing the
percentage allocation for spend for all media and RF channels. The order
must match (InputData.media + InputData.reach) with values between
0-1, summing to 1. 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. Consider using
InputData.get_paid_channels_argument_builder() to construct this
argument.
|
spend_constraint_lower
|
Numeric list of size n_paid_channels or float
(same constraint for all channels) indicating the lower bound of
media-level spend. If given as a channel-indexed array, the order must
match (InputData.media + InputData.reach) . The lower bound of
media-level spend is (1 - spend_constraint_lower) * budget *
allocation) . The value must be between 0-1. Defaults to 0.3 for fixed
budget and 1 for flexible. Consider using
InputData.get_paid_channels_argument_builder() to construct this
argument.
|
spend_constraint_upper
|
Numeric list of size n_paid_channels or float
(same constraint for all channels) indicating the upper bound of
media-level spend. If given as a channel-indexed array, the order must
match (InputData.media + InputData.reach) . The upper bound of
media-level spend is (1 + spend_constraint_upper) * budget *
allocation) . Defaults to 0.3 for fixed budget and 1 for flexible.
Consider using InputData.get_paid_channels_argument_builder() to
construct this argument.
|
gtol
|
Float indicating the acceptable relative error for the budget used
in the grid setup. The budget will be rounded by 10*n , where n is
the smallest integer such that (budget - rounded_budget) is less than
or equal to (budget * gtol) . gtol must be less than 1.
|
use_optimal_frequency
|
Boolean. Whether optimal frequency was used. |
use_kpi
|
Boolean. If True , then the incremental outcome is derived from
the KPI impact. Otherwise, the incremental outcome is derived from the
revenue impact.
|
batch_size
|
Max draws per chain in each batch. The calculation is run in
batches to avoid memory exhaustion. If a memory error occurs, try
reducing batch_size . The calculation will generally be faster with
larger batch_size values.
|
Returns | |
---|---|
An OptimizationGrid object containing the grid data for optimization. |
create_optimization_tensors
create_optimization_tensors(
time: (Sequence[str] | meridian.backend.Tensor
),
cpmu: (meridian.backend.Tensor
| None) = None,
media: (meridian.backend.Tensor
| None) = None,
media_spend: (meridian.backend.Tensor
| None) = None,
cprf: (meridian.backend.Tensor
| None) = None,
rf_impressions: (meridian.backend.Tensor
| None) = None,
frequency: (meridian.backend.Tensor
| None) = None,
rf_spend: (meridian.backend.Tensor
| None) = None,
revenue_per_kpi: (meridian.backend.Tensor
| None) = None,
use_optimal_frequency: bool = True
) -> meridian.analysis.analyzer.DataTensors
Creates a DataTensors
for optimizations from CPM and flighting data.
CPM is broken down into cost per media unit, cpmu
, for the media channels
and cost per impression (reach * frequency), cprf
, for the reach and
frequency channels.
The flighting pattern can be specified as the spend flighting or the media units flighting pattern at the time or geo and time granularity. If data is passed without a geo dimension, then the values are interpreted as national-level totals. If the model is a geo-level model, then the values are allocated across geos based on the population used in the model.
Below are the different combinations of tensors that can be provided:
For media:
1) media
, cpmu
(media units flighting pattern)
2) media_spend
, cpmu
(spend flighting pattern)
For R&F:
If use_optimal_frequency=True
, frequency
should not be provided.
Frequency input is not required for the optimization, so the new
DataTensors
object will be created with frequuency
arbitrarily set to
1 and reach=rf_impressions
.
1) rf_impressions
, cprf
(impressions flighting pattern)
2) rf_spend
, cprf
(spend flighting pattern)
If use_optimal_frequency=False
:
1) rf_impressions
, frequency
, cprf
(impressions flighting pattern)
2) rf_spend
, frequency
, cprf
(spend flighting pattern)
Args | |
---|---|
time
|
A sequence or tensor of time coordinates in the "YYYY-mm-dd" string format. |
cpmu
|
A tensor of cost per media unit with dimensions (n_media_channels), (T, n_media_channels)or (n_geos, T, n_media_channels)for any time
dimension T.
</td>
</tr><tr>
<td> media</td>
<td>
An optional tensor of media unit values with dimensions (T,
n_media_channels)or (n_geos, T, n_media_channels)for any time
dimension T.
</td>
</tr><tr>
<td> media_spend</td>
<td>
A tensor of media spend values with dimensions (T,
n_media_channels)or (n_geos, T, n_media_channels)for any time
dimension T.
</td>
</tr><tr>
<td> cprf</td>
<td>
A tensor of cost per impression (reach * frequency) with dimensions (n_rf_channels), (T, n_rf_channels) or (n_geos, T, n_rf_channels)
for any time dimension T .
|
rf_impressions
|
A tensor of impressions (reach * frequency) values with
dimensions (T, n_rf_channels) or (n_geos, T, n_rf_channels) for any
time dimension T .
|
frequency
|
A tensor of frequency values with dimensions (n_rf_channels) ,
(T, n_rf_channels) or (n_geos, T, n_rf_channels) for any time
dimension T . If use_optimal_frequency=True , then this tensor should
not be provided and the optimal frequency will be calculated and used.
|
rf_spend
|
A tensor of rf spend values with dimensions (T, n_rf_channels)
or (n_geos, T, n_rf_channels) for any time dimension T .
|
revenue_per_kpi
|
A tensor of revenue per KPI values with dimensions () ,
(T) , or (n_geos, T) for any time dimension T .
|
use_optimal_frequency
|
Boolean. If True , the optiaml frequency will be
used in the optimization and a frequency value should not be provided.
In this case, reach=rf_impressions and frequency=1 (by arbitrary
convention) in the new data. If False , the frequency value must be
provided.
|
Returns | |
---|---|
A DataTensors object with optional tensors media , reach ,
frequency , media_spend , rf_spend , revenue_per_kpi , and time .
|
optimize
optimize(
new_data: (meridian.analysis.analyzer.DataTensors
| None) = None,
use_posterior: bool = True,
selected_times: (tuple[str | None, str | None] | None) = None,
start_date: meridian.data.time_coordinates.Date
= None,
end_date: meridian.data.time_coordinates.Date
= None,
fixed_budget: bool = True,
budget: (float | None) = None,
pct_of_spend: (Sequence[float] | None) = None,
spend_constraint_lower: (_SpendConstraint | None) = None,
spend_constraint_upper: (_SpendConstraint | None) = None,
target_roi: (float | None) = None,
target_mroi: (float | None) = None,
gtol: float = 0.0001,
use_optimal_frequency: bool = True,
use_kpi: bool = False,
confidence_level: float = c.DEFAULT_CONFIDENCE_LEVEL,
batch_size: int = c.DEFAULT_BATCH_SIZE,
optimization_grid: (meridian.analysis.optimizer.OptimizationGrid
| None) = None
) -> meridian.analysis.optimizer.OptimizationResults
Finds the optimal budget allocation that maximizes outcome.
Define B to be the historical spend of a channel within selected_geos
and
between start_date
and end_date
. When the optimization assigns a new
budget N to this channel, the historical media units for each geo and time
period are assumed to scale by the ratio N / B. Media units prior to
selected_times
are also scaled by N / B. The incremental outcome of each
channel is aggregated over selected_geos
and between start_date
and
end_date
.
The incremental outcome includes the (lagged) amount generated between
start_date
and end_date
by media executed prior to start_date
, but it
excludes the (lagged) amount generated after end_date
by media executed
between start_date
and end_date
. This definition does not require any
assumptions about media execution levels, media costs, or revenue per kpi
for time periods after end_date
.
These assumptions are equivalent to assuming that for each channel, neither the flighting pattern nor the cost per media unit depend on the overall budget assigned to that channel.
The following optimization parameters are assigned default values based on
the model input data:
1. Flighting pattern. This is the relative allocation of a channel's media
units across geos and time periods. By default, the historical flighting
pattern is used. The default can be overridden by passing
new_data.media
. The flighting pattern is held constant during
optimization and does not depend on the overall budget assigned to the
channel.
2. Cost per media unit. By default, the historical spend divided by
historical media units is used. This can optionally vary by geo or time
period or both depending on whether the spend data has geo and time
dimensions. The default can be overridden by passing new_data.spend
.
The cost per media unit is held constant during optimization and does not
depend on the overall budget assigned to the channel.
3. Center of the spend box constraint for each channel. By default, the
historical percentage of spend within selected_geos
and between
start_date
and end_date
is used. This can be overridden by passing
pct_of_spend
.
4. Total budget to be allocated (for fixed budget scenarios only). By
default, the historical spend within selected_geos
and between
start_date
and end_date
is used. This can be overridden by passing
budget
.
Passing new_data.media
(or new_data.reach
or new_data.frequency
) will
override both the flighting pattern and cost per media unit. Passing
new_data.spend
(or `new_data.rf_spend) will only override the cost per
media unit.
If start_date
or end_date
is specified, these values must be selected
from new_data.time
(if provided) or from Meridian.n_times
(if
new_data.time
is not provided). The start_date
and end_date
default to
the first and last time periods, respectively.
Args | |
---|---|
new_data
|
An optional DataTensors container with optional tensors:
media , reach , frequency , media_spend , rf_spend ,
revenue_per_kpi , and time . If None , the original tensors from the
Meridian object are used. If new_data is provided, the optimization is
run on the versions of the tensors in new_data and the original
versions of all the remaining tensors. If any of the tensors in
new_data is provided with a different number of time periods than in
InputData , then all tensors must be provided with the same number of
time periods and the time tensor must be provided. In this case, spend
tensors must be provided with geo and time granularity. If
use_optimal_frequency is True , new_data.frequency does not need to
be provided and is ignored. The optimal frequency is used instead.
|
use_posterior
|
Boolean. If True , then the budget is optimized based on
the posterior distribution of the model. Otherwise, the prior
distribution is used.
|
selected_times
|
Deprecated. Tuple containing the start and end time
dimension coordinates for the duration to run the optimization on.
Please Use start_date and end_date instead.
|
start_date
|
Optional start date selector, inclusive, in yyyy-mm-dd
format. Default is the first time period of Meridian.InputData.time if
new_data is not provided; otherwise it is the first time period of
new_data.time .
|
end_date
|
Optional end date selector, inclusive in yyyy-mm-dd format.
Default is the last time period of Meridian.InputData.time if
new_data is not provided; otherwise it is the last time period of
new_data.time .
|
fixed_budget
|
Boolean indicating whether it's a fixed budget optimization
or flexible budget optimization. Defaults to True . If False , must
specify either target_roi or target_mroi .
|
budget
|
Number indicating the total budget for the fixed budget scenario. Defaults to the historical budget. |
pct_of_spend
|
Numeric list of size n_paid_channels containing the
percentage allocation for spend for all media and RF channels. The order
must match (InputData.media + InputData.reach) with values between
0-1, summing to 1. 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. Consider using
InputData.get_paid_channels_argument_builder() to construct this
argument.
|
spend_constraint_lower
|
Numeric list of size n_paid_channels or float
(same constraint for all channels) indicating the lower bound of
media-level spend. If given as a channel-indexed array, the order must
match (InputData.media + InputData.reach) . The lower bound of
media-level spend is (1 - spend_constraint_lower) * budget *
allocation) . The value must be between 0-1. Defaults to 0.3 for fixed
budget and 1 for flexible. Consider using
InputData.get_paid_channels_argument_builder() to construct this
argument.
|
spend_constraint_upper
|
Numeric list of size n_paid_channels or float
(same constraint for all channels) indicating the upper bound of
media-level spend. If given as a channel-indexed array, the order must
match (InputData.media + InputData.reach) . The upper bound of
media-level spend is (1 + spend_constraint_upper) * budget *
allocation) . Defaults to 0.3 for fixed budget and 1 for flexible.
Consider using InputData.get_paid_channels_argument_builder() to
construct this argument.
|
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 spend hits target_roi .
|
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 spend hits target_mroi .
|
gtol
|
Float indicating the acceptable relative error for the budget used
in the grid setup. The budget will be rounded by 10*n , where n is
the smallest integer such that (budget - rounded_budget) is less than
or equal to (budget * gtol) . gtol must be less than 1.
|
use_optimal_frequency
|
If True , uses optimal_frequency calculated by
trained Meridian model for optimization. If False , uses historical
frequency or new_data.frequency if provided.
|
use_kpi
|
If True , runs the optimization on KPI. Defaults to revenue.
|
confidence_level
|
The threshold for computing the confidence intervals. |
batch_size
|
Maximum draws per chain in each batch. The calculation is run
in batches to avoid memory exhaustion. If a memory error occurs, try
reducing batch_size . The calculation will generally be faster with
larger batch_size values.
|
optimization_grid
|
An OptimizationGrid object containing the grid
information. Grid creating is a time consuming part of optimization.
Creating one grid and running various optimizations on it can save time.
If None or grid doesn't match the optimization arguments, a new grid
will be created.
|
Returns | |
---|---|
An OptimizationResults object containing optimized budget allocation
datasets, along with some of the intermediate values used to derive them.
|