Techno Blender
Digitally Yours.

Convenient Bayesian Marketing Mix Modeling with PyMC Marketing | by Dr. Robert Kübler | Apr, 2023

0 41


A new and shiny library from the PyMC team worth trying out

Photo by Nathan Fertig on Unsplash

You can tell the importance of a topic by how many big companies are releasing software packages on it. In the field of marketing mix modeling, you can see that

Even better than marketing mix modeling is Bayesian marketing mix modeling, which Google’s and PyMC Labs’ libraries provide. While LMMM is certainly interesting as well, today we will focus on PyMC Marketing.

In this article, you will learn how easy it is to build a state-of-the-art Bayesian marketing mix model nowadays!

In case you need a refresher, please check out my old article that tells you what Bayesian marketing mix modeling is all about.

In my old article (see above), I was coding a Bayesian marketing mix model myself. In order to do this, I needed to define a function for the carryover effect of the media spendings, which was a bit cumbersome. Still using the older PyMC3, it looked like this:

import theano.tensor as tt

def carryover(x, strength, length):
w = tt.as_tensor_variable(
[tt.power(strength, i) for i in range(length)]
)

x_lags = tt.stack(
[tt.concatenate([
tt.zeros(i),
x[:x.shape[0]-i]
]) for i in range(length)]
)

return tt.dot(w, x_lags)

This one works, but it is not easy to parse and may not be efficient as well. Also, using Theano in PyMC is outdated, as I would have to use PyTensor now, a fork of Aesara based on Theano. A complicated history, it seems.

So I am happily relying on more professional and general code now to achieve my goals. I learned a lot by checking out how they implemented the carryover effect.

Before we continue, make sure you have the packages pymc and pymc-marketing installed. I installed PyMC using mamba as described in their Github and then installed pymc-marketing via

pip install pymc-marketing

Let us revisit our old example from my Bayesian marketing mix modeling article. We start by importing a dataset that I synthetically created.

import pandas as pd

data = pd.read_csv(
'https://raw.githubusercontent.com/Garve/datasets/4576d323bf2b66c906d5130d686245ad205505cf/mmm.csv',
parse_dates=['Date']
)

The data looks like this:

Image by the author.

Model Definition

Now, let’s get our star on stage and define the model:

from pymc_marketing.mmm import DelayedSaturatedMMM

mmm = DelayedSaturatedMMM(
data=data,
target_column="Sales",
date_column="Date",
channel_columns=["TV", "Radio", "Banners"],
)

This creates a model with saturations and carryover effects per channel, similar to what I did manually before. That’s why I will not go into detail about how this model works from a mathematical perspective.

We can now visualize what we have created:

import pymc as pm

pm.model_to_graphviz(model=mmm.model)

Image by the author.

Here, we can see that first the adstock (carryover) is applied, and then the saturation. We have three parameters alpha , beta_channel and lam per channel, where

  • alpha is the carryover rate that is between 0 and 1,
  • lam is the saturation rate, and
  • beta_channel is the actual linear regression coefficient.

To give a bit more context, the abridged model formula is

Image by the author.

where c runs over all different channels.

Model Fit

Fitting the model is as easy as in scikit-learn:

mmm.fit()

Model Inference

After the model is trained, we can check the parameters as follows:

import arviz as az

az.summary(
data=mmm.fit_result,
var_names=["intercept", "beta_channel", "alpha", "lam", "sigma"]
)

I got something like this:

Image by the author.

The first thing we can see is that the chains seem to have converged nicely as the r_hat in the rightmost columns is 1.0 everywhere.

From an inference standpoint, we can check what the model believes are the correct values for all of the parameters. As an example, the carryover of the channel TV alpha[TV] is between 0.465 and 0.515 with a 94% probability.

Note: For creating this dataset, I used saturation values of 0.5 for TV, 0.2 for radio and 0 for banners. Our PyMC model was able to pick this up quite decently!

For the visual folks:

mmm.plot_channel_parameter(param_name="alpha", figsize=(9, 5))
Image by the author.

We can even check out the channel contributions using the convenient method

mmm.plot_channel_contribution_share_hdi()
Image by the author.

Looks like TV is responsible for about 40% of the additional sales (additional to the base), radio for about 26%, and banners for about 34%.

Posterior Predictive Check

We can do a posterior predictive check, i.e. sampling predictions (blue), and see how well they follow the model (black).

Image by the author.

Looks like a fine fit! We can even decompose the signal into a baseline and the channel contributions via

mmm.plot_components_contributions()
Image by the author.

Insightful, but in addition, it might be useful to add the following to the library as well:

Image by the author.

Bayesian marketing mix modeling is the current best way to find out which of your marketing channels perform well and which don’t. Building such a model is not too complicated, but still by far not as straightforward as clicking together a scikit-learn model.

Luckily, the new PyMC Marketing makes Bayesian marketing mix modeling a breeze, compared to what we had to manually code before.

Don’t get me wrong, I like coding and I think it is important that you know how to code it as well. But still, it is nice to have a well-maintained package that probably gets even more common marketing mix model functionalities. Let’s see what the future brings!

And I did not even cover all of the functionalities. PyMC Marketing can even:

  • deal with control variables in an easy way by passing a list of columns via the control_columns into the DelayedSaturatedMMM class
  • plot saturation curves via mmm.plot_contribution_curves()
  • calculate the ROAS, although it is still manual work.

For more information, also check out this great notebook by the PyMC people.

I hope that you learned something new, interesting, and useful today. Thanks for reading!

As the last point, if you

  1. want to support me in writing more about machine learning and
  2. plan to get a Medium subscription anyway,

why not do it via this link? This would help me a lot! 😊

To be transparent, the price for you does not change, but about half of the subscription fees go directly to me.

Thanks a lot, if you consider supporting me!

If you have any questions, write me on LinkedIn!


A new and shiny library from the PyMC team worth trying out

Photo by Nathan Fertig on Unsplash

You can tell the importance of a topic by how many big companies are releasing software packages on it. In the field of marketing mix modeling, you can see that

Even better than marketing mix modeling is Bayesian marketing mix modeling, which Google’s and PyMC Labs’ libraries provide. While LMMM is certainly interesting as well, today we will focus on PyMC Marketing.

In this article, you will learn how easy it is to build a state-of-the-art Bayesian marketing mix model nowadays!

In case you need a refresher, please check out my old article that tells you what Bayesian marketing mix modeling is all about.

In my old article (see above), I was coding a Bayesian marketing mix model myself. In order to do this, I needed to define a function for the carryover effect of the media spendings, which was a bit cumbersome. Still using the older PyMC3, it looked like this:

import theano.tensor as tt

def carryover(x, strength, length):
w = tt.as_tensor_variable(
[tt.power(strength, i) for i in range(length)]
)

x_lags = tt.stack(
[tt.concatenate([
tt.zeros(i),
x[:x.shape[0]-i]
]) for i in range(length)]
)

return tt.dot(w, x_lags)

This one works, but it is not easy to parse and may not be efficient as well. Also, using Theano in PyMC is outdated, as I would have to use PyTensor now, a fork of Aesara based on Theano. A complicated history, it seems.

So I am happily relying on more professional and general code now to achieve my goals. I learned a lot by checking out how they implemented the carryover effect.

Before we continue, make sure you have the packages pymc and pymc-marketing installed. I installed PyMC using mamba as described in their Github and then installed pymc-marketing via

pip install pymc-marketing

Let us revisit our old example from my Bayesian marketing mix modeling article. We start by importing a dataset that I synthetically created.

import pandas as pd

data = pd.read_csv(
'https://raw.githubusercontent.com/Garve/datasets/4576d323bf2b66c906d5130d686245ad205505cf/mmm.csv',
parse_dates=['Date']
)

The data looks like this:

Image by the author.

Model Definition

Now, let’s get our star on stage and define the model:

from pymc_marketing.mmm import DelayedSaturatedMMM

mmm = DelayedSaturatedMMM(
data=data,
target_column="Sales",
date_column="Date",
channel_columns=["TV", "Radio", "Banners"],
)

This creates a model with saturations and carryover effects per channel, similar to what I did manually before. That’s why I will not go into detail about how this model works from a mathematical perspective.

We can now visualize what we have created:

import pymc as pm

pm.model_to_graphviz(model=mmm.model)

Image by the author.

Here, we can see that first the adstock (carryover) is applied, and then the saturation. We have three parameters alpha , beta_channel and lam per channel, where

  • alpha is the carryover rate that is between 0 and 1,
  • lam is the saturation rate, and
  • beta_channel is the actual linear regression coefficient.

To give a bit more context, the abridged model formula is

Image by the author.

where c runs over all different channels.

Model Fit

Fitting the model is as easy as in scikit-learn:

mmm.fit()

Model Inference

After the model is trained, we can check the parameters as follows:

import arviz as az

az.summary(
data=mmm.fit_result,
var_names=["intercept", "beta_channel", "alpha", "lam", "sigma"]
)

I got something like this:

Image by the author.

The first thing we can see is that the chains seem to have converged nicely as the r_hat in the rightmost columns is 1.0 everywhere.

From an inference standpoint, we can check what the model believes are the correct values for all of the parameters. As an example, the carryover of the channel TV alpha[TV] is between 0.465 and 0.515 with a 94% probability.

Note: For creating this dataset, I used saturation values of 0.5 for TV, 0.2 for radio and 0 for banners. Our PyMC model was able to pick this up quite decently!

For the visual folks:

mmm.plot_channel_parameter(param_name="alpha", figsize=(9, 5))
Image by the author.

We can even check out the channel contributions using the convenient method

mmm.plot_channel_contribution_share_hdi()
Image by the author.

Looks like TV is responsible for about 40% of the additional sales (additional to the base), radio for about 26%, and banners for about 34%.

Posterior Predictive Check

We can do a posterior predictive check, i.e. sampling predictions (blue), and see how well they follow the model (black).

Image by the author.

Looks like a fine fit! We can even decompose the signal into a baseline and the channel contributions via

mmm.plot_components_contributions()
Image by the author.

Insightful, but in addition, it might be useful to add the following to the library as well:

Image by the author.

Bayesian marketing mix modeling is the current best way to find out which of your marketing channels perform well and which don’t. Building such a model is not too complicated, but still by far not as straightforward as clicking together a scikit-learn model.

Luckily, the new PyMC Marketing makes Bayesian marketing mix modeling a breeze, compared to what we had to manually code before.

Don’t get me wrong, I like coding and I think it is important that you know how to code it as well. But still, it is nice to have a well-maintained package that probably gets even more common marketing mix model functionalities. Let’s see what the future brings!

And I did not even cover all of the functionalities. PyMC Marketing can even:

  • deal with control variables in an easy way by passing a list of columns via the control_columns into the DelayedSaturatedMMM class
  • plot saturation curves via mmm.plot_contribution_curves()
  • calculate the ROAS, although it is still manual work.

For more information, also check out this great notebook by the PyMC people.

I hope that you learned something new, interesting, and useful today. Thanks for reading!

As the last point, if you

  1. want to support me in writing more about machine learning and
  2. plan to get a Medium subscription anyway,

why not do it via this link? This would help me a lot! 😊

To be transparent, the price for you does not change, but about half of the subscription fees go directly to me.

Thanks a lot, if you consider supporting me!

If you have any questions, write me on LinkedIn!

FOLLOW US ON GOOGLE NEWS

Read original article here

Denial of responsibility! Techno Blender is an automatic aggregator of the all world’s media. In each content, the hyperlink to the primary source is specified. All trademarks belong to their rightful owners, all materials to their authors. If you are the owner of the content and do not want us to publish your materials, please contact us by email – [email protected]. The content will be deleted within 24 hours.
Leave a comment