Marketing Mix Modeling
Checkout how to fit, backtest and calibrate your MMM model with lift tests and attribution models.
Checkout how to optimize your budget to arbitrary constraints, objectives and parametrizations!
Marketing Mix Modeling (MMM) is a statistical analysis technique that helps in obtaining insights and planning marketing strategies. It is tightly related to Time Series Analysis โ we can think of MMM as a special case of Time Series forecasting, where the goal is to understand the incrementality of different exogenous variables on the target variable.
When Prophetverse was created, the objective was to provide a more up-to-date implementation of Facebookโs Prophet model and to add features and customization options that were not available in the original implementation. However, as the library evolved, it became clear that it could be used for more than just forecasting and that it could be a powerful tool for MMM.
Prophetverse has the following features that make it a great choice for MMM:
Modularity: Prophetverse allows users to create additive Bayesian models in a modular fashion. Users can easily include different effects to account for various relationships between the exogenous variables and the target variable, and even create their own effects.
Versatility: The effects API can be used not only for adding new components but also for adding new likelihood terms, such as those used for lift tests.
Particularly, Prophetverse has a practical interface, based on initialization, fit and predict, that allows users to quickly build and evaluate custom MMM models.
A typical Prophetverse model workflow is as follows:
1. Define the baseline components
Typical components of a MMM model are trend and seasonality. We have builtin components for these:
from prophetverse import (
LinearFourierSeasonality,
PiecewiseLinearTrend,
)
# Trend
= PiecewiseLinearTrend(
trend =365, # One changepoint every 365 timeunits
changepoint_interval=-120, # The last changepoint should be 120 days before the end of the training data,
changepoint_range=1e-3,
changepoint_prior_scale
)
# Seasonality
= LinearFourierSeasonality(
seasonality_effect =[365.25, 7],
sp_list=[10, 3],
fourier_terms_list=0.1,
prior_scale="D",
freq="multiplicative",
effect_mode )
/opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
from .autonotebook import tqdm as notebook_tqdm
2. Define custom exogenous effects
Now, it is time to define how the investment variables affect the target variable. In MMM, it is common to use adstock and saturation effects to model the impact of advertising spend on sales.
from prophetverse import (
MichaelisMentenEffect,
ChainedEffects,
GeometricAdstockEffect,
PiecewiseLinearTrend,
)import numpyro.distributions as dist
= MichaelisMentenEffect(
saturation ="additive",
effect_mode=dist.HalfNormal(0.5),
max_effect_prior=dist.HalfNormal(0.5),
half_saturation_prior
)
# Chained effect: saturation + adstock (after)
# Depending on your use case, you might want to use the saturation before or after the adstock.
= ChainedEffects(
saturation_with_adstock =[
steps"saturation", saturation),
(
("adstock",
GeometricAdstockEffect(=dist.Beta(2, 2),
decay_prior
),
),
] )
3. Create the Prophetverse model
Now, we can create the Prophetverse model by combining the components defined above. The exogenous_effects
argument accepts a list of tuples with three elements:
- A name for the effect. This will be the name that the output of this effect will have in the dataframe obtained from
predict_components
method. - The effect instance.
- A regex to select the columns from the input dataframe
X
that will be used for this effect. You can use the utility functions fromprophetverse.utils.regex
, or define your own regex (which is easy nowadays with LLMs!).
from prophetverse import Prophetverse
from prophetverse.utils.regex import starts_with, no_input_columns
= Prophetverse(
model =trend,
trend=[
exogenous_effects"channelA", saturation_with_adstock, starts_with("channelA")),
("channelB", saturation, starts_with("channelB")),
("seasonality", seasonality_effect, no_input_columns),
(
], )
4. Fit and predict
Then, with your data ready, you can fit and predict with the model:
=y, X=X)
model.fit(y# Dates to predict
= pd.period_range(start="2023-01-01", end="2023-06-30", freq="D")
fh = model.predict_components(fh=fh, X=X) y_pred_components
The predict_components
method returns a dataframe where the columns represent components of the model. The โmeanโ column is the sum of all components, which is the prediction of the model.
Note that some columns might be latent variables and not necessarily are used to compute the final prediction (it depends on how you defined your model).
Available Effects
You can get a list of all available effects in Prophetverse by running the following code:
from skbase.lookup import all_objects
from prophetverse.effects import BaseEffect
all_objects(=[BaseEffect], package_name="prophetverse", as_dataframe=True
object_types )
name | object | |
---|---|---|
0 | BetaTargetLikelihood | <class 'prophetverse.effects.target.univariate... |
1 | ChainedEffects | <class 'prophetverse.effects.chain.ChainedEffe... |
2 | Constant | <class 'prophetverse.effects.constant.Constant'> |
3 | ExactLikelihood | <class 'prophetverse.effects.exact_likelihood.... |
4 | FlatTrend | <class 'prophetverse.effects.trend.flat.FlatTr... |
5 | GammaTargetLikelihood | <class 'prophetverse.effects.target.univariate... |
6 | GeometricAdstockEffect | <class 'prophetverse.effects.adstock.Geometric... |
7 | HillEffect | <class 'prophetverse.effects.hill.HillEffect'> |
8 | HurdleTargetLikelihood | <class 'prophetverse.effects.target.hurdle.Hur... |
9 | IgnoreInput | <class 'prophetverse.effects.ignore_input.Igno... |
10 | LiftExperimentLikelihood | <class 'prophetverse.effects.lift_likelihood.L... |
11 | LinearEffect | <class 'prophetverse.effects.linear.LinearEffe... |
12 | LinearFourierSeasonality | <class 'prophetverse.effects.fourier.LinearFou... |
13 | LogEffect | <class 'prophetverse.effects.log.LogEffect'> |
14 | MichaelisMentenEffect | <class 'prophetverse.effects.michaelis_menten.... |
15 | MultiplyEffects | <class 'prophetverse.effects.multiply.Multiply... |
16 | MultivariateNormal | <class 'prophetverse.effects.target.multivaria... |
17 | NegativeBinomialTargetLikelihood | <class 'prophetverse.effects.target.univariate... |
18 | NormalTargetLikelihood | <class 'prophetverse.effects.target.univariate... |
19 | PanelBHLinearEffect | <class 'prophetverse.effects.linear.PanelBHLin... |
20 | PiecewiseLinearTrend | <class 'prophetverse.effects.trend.piecewise.P... |
21 | PiecewiseLogisticTrend | <class 'prophetverse.effects.trend.piecewise.P... |
22 | TargetLikelihood | <class 'prophetverse.effects.target.univariate... |
23 | WeibullAdstockEffect | <class 'prophetverse.effects.adstock.WeibullAd... |
The following effects may be of interest if you are working on MMM:
GeometricAdstockEffect: The geometric adstock effect is a widely used technique in MMM to account for the lagged effect of advertising on sales. It is based on the idea that the effect of an ad on sales decays over time and that the decay follows a geometric progression.
HillEffect: The Hill curve accounts for diminishing returns in the effect of an exogenous variable on the target variable.
ChainedEffects: The chained effect is a way to combine multiple effects into a single one. For example, you can use adstock and Hill together.
LiftExperimentLikelihood: The lift experiment likelihood is a likelihood term that can be used to account for the effect of a lift test on the target variable. It is useful if you want to understand the incrementality of a variable and have already run a lift test to analyze how variations in the input affect the output.
ExactLikelihood: The exact likelihood is a likelihood term that can be used to incorporate a reference value as the incrementality of an exogenous variable. It is useful if another team in your company has already calculated the incrementality of a variable and you want to use it in your MMM model.