Pymc-marketing (adstock and saturation)

I am new in pymc-markeing and I after having replicated the “MMM Example Notebook” on my VScode, I was trying to do it again with different adstock model (in particular, I tried with Weibull PDF). I do not know how to do that, so I tried to introduce, as custom priors, the priors related to the scale and shape paramters of the WieibullPDF in these 2 ways:

WAY 1:
‘’’
‘scale’: {‘dist’: ‘Beta’, ‘kwargs’: {‘alpha’: 1, ‘beta’: 5}}, # prior for the weibullPDF adstock’s scale(lam) parameter

‘shape’: {‘dist’: ‘Gamma’, ‘kwargs’: {‘alpha’: 5, ‘beta’: 1}}, # prior for the weibullPDF adstock’s shape(k) parameter
‘’’

WAY 2:
‘’’
‘lam’: {‘dist’: ‘Beta’, ‘kwargs’: {‘alpha’: 1, ‘beta’: 5}}, # prior for the weibullPDF adstock’s scale(lam) parameter

‘k’: {‘dist’: ‘Gamma’, ‘kwargs’: {‘alpha’: 5, ‘beta’: 1}}, # prior for the weibullPDF adstock’s shape(k) parameter
‘’’

because I saw them called as lam/k or shape/scale in the “under the hood” of the library. Anyway, in both the cases, after fitting the model and get its graphical representation, nothing changed compared to the original “MMM Example Notebook” (the adstock still results to be modelled according to the alpha parameter of the geometric adstock).

So, I also tried again the same two ways, this time deleting from the custom priors the prior related to the alpha of the geometric adstock. The results is that it returns me an error cause the alpha’s prior is missing.

So, how can I implement an adstock model which is not the geometric adstock?

I know that maybe for the experts with this library it could be not such a clever question, but as I said I am new with this library and even a suggestion is very appreciated

1 Like

Welcome!

In the DelayedSaturated class/model, the adstock and saturation transformations are currently fixed to be geometric and logistic respectively. Use of alternative transformations requires a slightly more custom model in which you inherit from BaseDelayedSaturatedMMM. Work on the API and the model config in particular is still underway and we hope to permit more flexible specifications soon.

1 Like

Thank you very much for the clarification.
By the way, can you tell me some sources where I can find some examples of code to build this kind of models?

One place to look would be the code for the DelayedSaturatedMMM class (source code here). You could begin to play around with copying this, renaming it, and changing whatever pieces (e.g., the adstock function) you wanted. This blog post by @Niall_Oulton may also provide some pointers.

1 Like

Hi!

I had some success by inheriting from DelayedSaturatedMMM and overriding the build_model method.

Based on the original method I essentially added this in the prior specification to use delayed adstock if theta is specified in the model config:

    if self.model_config.get("theta"):
        self.theta_dist =  self._get_distribution(dist=self.model_config["theta"])                        
        self._adstock_function = 'delayed_adstock'
    else:
        self.theta_dist = None
        self._adstock_function = 'geometric_adstock'

And this for specifying the actual transform function:

    if self._adstock_function == 'geometric_adstock':
        adstock_transform = geometric_adstock(
            x=channel_data_,
            alpha=alpha,
            l_max=self.adstock_max_lag,
            normalize=True,
            axis=0,
        )
    elif self._adstock_function == 'delayed_adstock':
        adstock_transform = delayed_adstock(
            x=channel_data_,
            alpha=alpha,
            theta=theta,
            l_max=self.adstock_max_lag,
            normalize=True,
            axis=0,
        )

Finally, the adstock_transform must be used to replace the direct specification of the geometric_adstock in the deterministic channel_adstock:

    channel_adstock = pm.Deterministic(
        name="channel_adstock",
        var=adstock_transform,
        dims=("date", "channel"),
    )

This appears to work, as indicated by the model graph (and it runs), but I have not tested in depth yet. I believe the class (or rather its parents) may have some other methods for which it must be ensured that the correct adstock transform is used, such as those for out of sample plotting, but I have not checked that yet.

Best Regards
Jonas

1 Like

PyMC-Marketing allows for custom adstock and saturation transformations in the MMM class since version 0.7.0

from pymc_marketing.mmm import (
    MMM, 
    GeometricAdstock,
    MichaelisMentenSaturation,
)

mmm = MMM(
    adstock=GeometricAdstock(l_max=4), 
    saturation=MichaelisMentenSaturation(), 
    ...,
)

The full list of out-of-box transformation are found:

These include WeibullCDF and WeilbullPDF

Custom transformations can also be implemented easily by inheriting from either AdstockTransformation or SaturationTransformation and defining both function and default_priors. See some examples in the documentation

2 Likes