Comments (9)
@pabloduque0 @steven-struglia @MuhammedTech and @hawkinsp I've created a collab book showing examples of how you can build functions to export these curves as well as channel tuning
https://colab.research.google.com/drive/1zKHmT_CR6AmVbH-4PdsmUJdumMadcmrO#scrollTo=WcYeesq4w3jT
from lightweight_mmm.
Hello @xijianlim ! Thanks for reporting this one!
There are a few small nuances that could lead to some difference in response curves vs contribution calculation. Although the difference that you report here seem bigger than I would expect.
I see that you are currently running a geo model. Could you confirm if you see this same issue on a national model? Just so I can rule some things out.
Did you use extra features for this model? If so, what are the coefficients of it?
Thanks
from lightweight_mmm.
Hello again @pabloduque0 . Yes the same thing happens at the national model, and yes there were extra features in the model.
you can clearly see that channel_0's ROI profile is well below $1:
If I may offer an idea for the Response Curves:
instead of using the media ranges and constructing them using the mmm.predict function, would it be better if you feed them through the adstock-hillfunction equation but using the coefficients from the model?
something like this:
def media_transform_hill_adstock(media_mix_model,
media_data,
lag_weight,
half_max_effective_concentration,
slope, apply_adstock, normalise):
ransforms the input data with the adstock and hill functions.
Args:
media_data: Media data to be transformed. It is expected to have 2 dims for
national models and 3 for geo models.
normalise: Whether to normalise the output values.
Returns:
The transformed media data.
"""
if media_mix_model.n_geos > 1:
lag_weight=jnp.repeat(lag_weight,media_mix_model.n_geos).reshape(half_max_effective_concentration.shape)
slope = jnp.squeeze(jnp.repeat(slope,media_mix_model.n_geos).reshape(half_max_effective_concentration.shape))
if apply_adstock:
return media_transforms.hill(
data=media_transforms.adstock(
data=media_data, lag_weight=lag_weight, normalise=normalise),
half_max_effective_concentration=half_max_effective_concentration,
slope=slope)
else:
return media_transforms.hill(
data=media_data,
half_max_effective_concentration=half_max_effective_concentration,
slope=slope)
percentage_add=2
media_mix_model=mmm
steps=25
prices=average_cost_per_media
media = media_mix_model.media
media_maxes = media.max(axis=0) * (1 + percentage_add)
half_max_effective_concentration=media_mix_model._mcmc.get_samples()['half_max_effective_concentration']#.mean(axis=0)
lag_weight=media_mix_model._mcmc.get_samples()['lag_weight']#.mean(axis=0)
slope=media_mix_model._mcmc.get_samples()['slope']#.mean(axis=0)
beta_media=media_mix_model.trace['beta_media'].mean(axis=0)
media_ranges = jnp.expand_dims(
jnp.linspace(start=0, stop=media_maxes, num=steps), axis=0)
media_ranges=jnp.repeat(media_ranges,len(beta_media)).reshape(steps,len(beta_media),media_mix_model.n_media_channels, media_mix_model.n_geos)
media_response=beta_media*media_transform_hill_adstock(media_mix_model,
media_ranges,
lag_weight,
half_max_effective_concentration=half_max_effective_concentration,
slope=slope, normalise=True)
from lightweight_mmm.
I can confirm that constructing the response curves using the trace parameters (beta_media, lag_weight, half_max_effective_concentration and slop) as per above has resolved the issue. I've modified this in my version of the code base. I thought I'd share this with you as this has closer alignment with the media contributions. I suggest amending the response_curve plots with this method.
from lightweight_mmm.
Hello @xijianlim !
Thanks for your response.
There are a couple reasons why those two are designed differently. Mainly the response curves are a forward looking and the other approach is strictly backward looking. However for that we need to make a couple assumptions about lagging and extra features that might not be what users want in some scenarios. I agree that we should offer the flexibility to not take into account those assumptions, or make them optional or similar.
Let me looks into it a little bit and get back on this one.
from lightweight_mmm.
@xijianlim How did you go about plotting the response curves on the spend vs. KPI axis? I can't seem to make the dimensions or values work for my use case using your function above.
from lightweight_mmm.
were you be able to plot it?
from lightweight_mmm.
Hi, sorry for the delay in replying. To be clear, this is only for ADSTOCK-BETAHILL modelling. Unfortunately I can't share the exact code because it is now my company's PI but i'll demonstrate how you can plot this.
- you have import this function from media_transforms.py
media_transforms.hill( data=media_transforms.adstock( data=media_data, lag_weight=lag_weight, normalise=normalise), half_max_effective_concentration=half_max_effective_concentration, slope=slope)
This is in effect is the "response curves" function. All that is needed is to use the trained models's "trace" functions to get the right parameters, namely the lagweight, slope, beta_media and half_effective concentration.
percentage_add=2
media_mix_model=mmm
steps=25
prices=average_cost_per_media
media = media_mix_model.media
media_maxes = media.max(axis=0) * (1 + percentage_add)
half_max_effective_concentration=media_mix_model._mcmc.get_samples()['half_max_effective_concentration'].mean(axis=0)
lag_weight=media_mix_model._mcmc.get_samples()['lag_weight'].mean(axis=0)
slope=media_mix_model._mcmc.get_samples()['slope'].mean(axis=0)
beta_media=media_mix_model.trace['beta_media'].mean(axis=0)
media_ranges = jnp.expand_dims(
jnp.linspace(start=0, stop=media_maxes, num=steps), axis=0)
media_ranges=jnp.repeat(media_ranges,len(beta_media)).reshape(steps,len(beta_media),media_mix_model.n_media_channels, media_mix_model.n_geos)
media_response=beta_media*media_transform_hill_adstock(media_mix_model,
media_ranges,
lag_weight,
half_max_effective_concentration=half_max_effective_concentration,
slope=slope, normalise=True)
You'll then have to plot an XY scatter plot where Y=media response and X = media spend (which is media*prices)
I hope this helps you all
from lightweight_mmm.
from lightweight_mmm.
Related Issues (20)
- how to treat zero cost channels and attribution hints HOT 5
- cost and media data is not clear from the documentation HOT 1
- Single-channel use issue HOT 15
- Why Pre and Post Budget Allocation do not change? HOT 6
- Nested modeling HOT 2
- Multivariate input for media data HOT 1
- Response curve questions
- Loading saved model
- Saturation + Carryover transformation HOT 2
- Baseline Contribution Area Plot colours are non-unique HOT 1
- Feature request: Extend to time-varying coefficients (uber's orbit model)
- Question: How to model time dependent features in the fit and predict method? HOT 2
- how to understand the media contribution percentage? HOT 2
- Media contribution percentage sums up to 105% HOT 1
- Have issues with plot.plot_media_channel_posteriors(media_mix_model=mmm) HOT 2
- Budget Allocator - Solution X returns incorrect allocation HOT 1
- limitations in the use of extra features HOT 4
- Anyway to save mmm.print_summary()? HOT 1
- Hierarchical Partially Pooled Media
- media_priors HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from lightweight_mmm.