Skip to content

Latest commit

Β 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ“Š Marketing Mix Modeling (MMM) with Robyn

R Robyn Status Domain

End-to-end Marketing Mix Modeling implementation using Meta's Robyn framework in R.
This project applies adstock transformations, saturation modeling, Pareto-optimal model selection, and budget allocation optimization across 5 paid media channels over 4 years of weekly FMCG data.


πŸ‘€ Author

Jhoan Sebastian Meza
Economist & Junior Data Scientist Β· Universidad Nacional de Colombia
GitHub


πŸ“‹ Table of Contents


🎯 About the Project

Marketing Mix Modeling (MMM) is a statistical technique used to quantify the impact of media investments on sales. Unlike digital attribution models, MMM works across all channels β€” including TV, OOH, and Print β€” and provides business-interpretable metrics such as ROI, elasticities, and channel contribution.

This project implements a full MMM pipeline using Meta's Robyn framework, covering:

  • Automated adstock and saturation transformation via Nevergrad optimization
  • Prophet-based decomposition of trend, seasonality, and holidays
  • Pareto-optimal model selection balancing NRMSE and DECOMP.RSSD
  • Budget reallocation recommendations to maximize media-attributed revenue

πŸ“¦ Dataset

The project uses dt_simulated_weekly β€” a synthetic FMCG dataset included in the Robyn package.

Variable Type Description
DATE Date Weekly time index (2015–2019)
revenue Dependent variable Weekly sales in $
tv_S Paid media spend TV investment
ooh_S Paid media spend Out-of-Home (billboards, transit)
print_S Paid media spend Print media
facebook_S Paid media spend Facebook/Meta investment
search_S Paid media spend Search/Google investment
competitor_sales_B Context variable Competitor sales β€” control
events Context variable Special brand events and promotions

208 weeks Β· 5 paid media channels Β· 2 context variables Β· 0 missing values


βš™οΈ Methodology

Pipeline

robyn_inputs() β†’ robyn_run() β†’ robyn_outputs() β†’ robyn_allocator()

Key design decisions

Parameter Value Rationale
Adstock type Weibull CDF Flexible decay β€” more realistic than geometric
Iterations 2,000 per trial Recommended minimum for stable Pareto front
Trials 5 Ensures convergence stability
Regression Ridge (L2) Handles multicollinearity between channels
Prophet trend + season + holiday Isolates structural effects from media effects

Hyperparameter ranges by channel

Channel Shapes Scales Business rationale
tv_S 0.1–1 0.3–0.9 Long brand memory β€” effect lasts weeks
ooh_S 0.1–1 0.3–0.8 Continuous exposure β€” moderate carryover
print_S 0.5–3 0.1–0.5 Medium memory β€” between TV and digital
facebook_S 2–8 0.1–0.4 Short digital effect β€” fast decay
search_S 3–10 0.0001–0.2 Near-immediate intent capture

πŸ“ˆ Results

Pareto Front β€” 10,000 Models Evaluated

Each dot is one model. Orange lines connect Pareto-optimal candidates β€” models where you cannot improve NRMSE without worsening DECOMP.RSSD. Dark blue dots were found in later iterations, showing Nevergrad's progressive optimization. The target zone is the bottom-left corner.

Pareto Front


Cluster Selection

Robyn automatically selected 3 clusters using the WSS (Within Sum of Squares) method. The red line marks the 6% variance threshold β€” adding more clusters beyond k=3 produces diminishing improvements.

Cluster WSS


Cluster Detail & Model Selection

Each cluster's winning model is shown in the Pareto space. The selection criterion balances prediction accuracy (NRMSE) and business plausibility (DECOMP.RSSD).

Cluster Detail


Prophet Decomposition

Before estimating media contributions, Prophet decomposes total sales into structural components β€” trend, seasonality, and holidays. This prevents the model from incorrectly attributing seasonal peaks to media channels.

Prophet Decomposition


Model Winner β€” Cluster 1: 5_830_1

Adj.RΒ² train = 0.853 | NRMSE val = 0.065 | DECOMP.RSSD = 0.338

Selected for best predictive performance on the validation set.

One-pager Model 5_830_1

Channel efficiency summary:

Channel Spend Share Effect Share Verdict
search_S 8.5% 24.1% βœ… Highly efficient
print_S 5.3% 15.8% βœ… Highly efficient
tv_S 21.3% 25.1% βœ… Balanced
ooh_S 61.9% 34.2% ❌ Over-invested
facebook_S 3.1% 0.9% ❌ Low efficiency

Immediate vs. Carryover highlights:

  • search_S & facebook_S: ~90% immediate β€” digital channels with near-instant response
  • tv_S: 42% immediate / 58% carryover β€” brand memory extends several weeks after campaign
  • ooh_S: 90% immediate / 10% carryover β€” driven by continuous physical exposure

Model Winner β€” Cluster 2: 3_906_2

Adj.RΒ² train = 0.806 | NRMSE val = 0.126 | DECOMP.RSSD = 0.074

Selected for the lowest DECOMP.RSSD β€” most business-plausible channel decomposition.

One-pager Model 3_906_2

Notable finding: print_S shows 0% immediate and 0% carryover response in this model β€” indicating that print's hyperparameter ranges may require refinement or that the channel lacks sufficient spend variation for reliable estimation in this specification.


πŸ’° Budget Allocation

Scenario: max_response β€” Model 2_994_1

Using robyn_allocator() with the max_response scenario on the DΓ­a 3 reference model:

Budget Allocation

Key result: By simply redistributing the existing $11.9M budget β€” without increasing total spend β€” the model projects a +27.8% increase in media-attributed revenue (from $17.4M to $22.2M), reducing overall CPA from $0.68 to $0.54.

Channel Current spend Optimal spend Change
ooh_S $57K/week $31K/week ⬇️ -46%
tv_S $15K/week $31K/week ⬆️ +107%
search_S $4.2K/week $8.5K/week ⬆️ +102%
print_S $4.3K/week $8.5K/week ⬆️ +98%
facebook_S $2.2K/week $4.3K/week ⬆️ +95%

πŸš€ How to Run

1. Clone the repository

git clone https://github.com/jmeza-data/Robyn_Marketing_Mix_Modeling.git
cd Robyn_Marketing_Mix_Modeling

2. Install dependencies in R

install.packages("remotes")
remotes::install_github("facebookexperimental/Robyn/R")
install.packages("reticulate")
reticulate::py_install("nevergrad", pip = TRUE)

3. Run the model

source("MMM.R")

⚠️ robyn_run() with 5 trials Γ— 2,000 iterations takes approximately 25–30 minutes depending on hardware.


πŸ› οΈ Requirements

Tool Version
R β‰₯ 4.4.1
Robyn 3.12.1
Python β‰₯ 3.9
nevergrad 1.0.12
reticulate β‰₯ 1.46

πŸ“Œ Key Takeaways

  • OOH is significantly over-invested β€” absorbing 61.9% of media budget while generating only 34.2% of effect
  • Search and Print show the highest efficiency β€” generating 3x and 2x their spend share respectively
  • TV shows healthy carryover β€” 58% of its impact persists beyond the week of investment
  • Budget reallocation from OOH toward TV and Search could increase media revenue by +27.8% with zero additional spend

Built as part of NIQ Analyst preparation Β· April 2026 Β· BogotΓ‘, Colombia

About

Marketing Mix Modeling (MMM) implementation using Meta's Robyn framework in R. Includes adstock, saturation modeling and budget allocation optimization for FMCG media channels.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages