pymc-labs / pymc-marketing

Bayesian marketing toolbox in PyMC. Media Mix (MMM), customer lifetime value (CLV), buy-till-you-die (BTYD) models and more.
https://www.pymc-marketing.io/
Apache License 2.0
717 stars 201 forks source link

R2D2M2 prior for Saturated MMM #381

Open ferrine opened 1 year ago

ferrine commented 1 year ago

The existing MMM can be improved with variance decomposition framework, r2d2m2, which is plug and play into the existing code

r2 = pm.Beta("r2", mu=0.8, sigma=0.5*0.8)
total_sigma = pm.LogNormal("total_sigma", np.log(np.std(data.y)), 0.1)
model_sigma = r2 ** .5 * total_sigma
error_sigma = (1-r2) ** .5 * total_sigma
control_fourier_features_split = pm.Dirichlet("control_features_split", np.ones(K), dims="control_fourier")
control_features_split = model_sigma * control_fourier_features_split[:-1] ** .5
fourier_split = model_sigma * control_fourier_features_split[-1] ** .5

Reference https://arxiv.org/abs/2208.07132

juanitorduz commented 1 year ago

Thanks! yo you recommend this for the seasonality (Fourier modes) components? Or more generally, on the whole model?

wd60622 commented 5 months ago

Are the coefficients suppose to be for all betas in the model or just for a subset like the control / or fourier? @ferrine

ferrine commented 5 months ago

For control and Fourier. Each Fourier component is normalised the same way as control.

For marketing variables it would be another treatment, ideally via interactive prior predictive analysis

wd60622 commented 5 months ago

Gotcha. So in this example, the control_fourier dim is the combination of fourier and controls? i.e. [controls_dims, fourier_dims]

And then the error_sigma would be used as the prior of sigma of likelihood, right?

Think this could fit into the generalization of the Prior class I linked. I.e

gamma_control, gamma_fourier, sigma = create_r2d2_priors(
    r2=Prior("Beta", mu=0.8, sigma=0.8 * 0.5), 
    total_sigma=Prior("LogNormal", mu=np.log(np.std(y)), sigma=0.1),
    # These are the dim names in the model that will be combined
    dims=["control", "fourier_mode"], 
)

model_config = {
    "likelihood": Prior("Normal", sigma=sigma), 
    "gamma_control": gamma_control, 
    "gamma_fourier": gamma_fourier,
}
mmm = MMM(..., model_config=model_config, ...)

gamma_control, gamma_fourier, and sigma would have to work like our priors class.

Also, can you expand on the "interactive prior predictive analysis"?

wd60622 commented 5 months ago

Also, do people tend to put priors on K as well?

ferrine commented 4 months ago

What is k

ferrine commented 4 months ago

Ah, I see, k is better set manually, is is problematic to infer

AlfredoJF commented 3 months ago

Hey @wd60622 , @ferrine

This R2D2M2 prior will enable extra dims like geo for geo-hierarchical modelling? https://github.com/pymc-labs/pymc-marketing/discussions/648#discussioncomment-10394912

wd60622 commented 3 months ago

Hi @AlfredoJF, Good question. The first step might not include geo, but it might be possible to extend. Maybe @ferrine knows better about this in practice.

In your mind, @AlfredoJF, would the user specify the r2 by geo? Or would it be global r2? Or better yet, what prior information would you have? Do you have an example API specifying the input and output so we can understand what the user would provide?

In my mind, the function just has to return sigma and various betas but adding geo becomes complex. Where does (geo, ) dim get included? All variables? sigmas? all betas? some betas?

Let me know your thoughts!