Creating a Marketing Mix Model with LightweightMMM: A Step-by-Step Guide

Marketing Mix Models (MMM) are powerful tools for understanding the impact of various marketing channels on business outcomes. In this guide, we’ll walk through the process of creating a Marketing Mix Model using LightweightMMM, a Python library developed by Google. This guide assumes you have a basic understanding of marketing analytics and Python.

Step 1: Installation and Importing Libraries

To get started, install the LightweightMMM library:

Next, import the necessary libraries:

!pip install --upgrade git+https://github.com/google/lightweight_mmm.git
import jax.numpy as jnp
from lightweight_mmm import lightweight_mmm, optimize_media, plot, preprocessing, utils

Step 2: Organizing Data for Modeling

Generate or import your data for modeling. In this example, we simulate dummy data:

SEED = 105
data_size = 104 + 13
n_media_channels = 3
n_extra_features = 1

media_data, extra_features, target, costs = utils.simulate_dummy_data(
    data_size=data_size,
    n_media_channels=n_media_channels,
    n_extra_features=n_extra_features)

Split the dataset into training and testing sets:

split_point = data_size - 13
media_data_train = media_data[:split_point, ...]
media_data_test = media_data[split_point:, ...]
extra_features_train = extra_features[:split_point, ...]
extra_features_test = extra_features[split_point:, ...]
target_train = target[:split_point]

Step 3: Scaling the Data

Scaling is crucial for modeling. Use the CustomScaler class provided by LightweightMMM:

media_scaler = preprocessing.CustomScaler(divide_operation=jnp.mean)
extra_features_scaler = preprocessing.CustomScaler(divide_operation=jnp.mean)
target_scaler = preprocessing.CustomScaler(divide_operation=jnp.mean)
cost_scaler = preprocessing.CustomScaler(divide_operation=jnp.mean, multiply_by=0.15)

media_data_train = media_scaler.fit_transform(media_data_train)
extra_features_train = extra_features_scaler.fit_transform(extra_features_train)
target_train = target_scaler.fit_transform(target_train)
costs = cost_scaler.fit_transform(costs)

Step 4: Training the Model

Choose a model type (e.g., “carryover”) and train the model:

mmm = lightweight_mmm.LightweightMMM(model_name="carryover")

number_warmup = 1000
number_samples = 1000

mmm.fit(
    media=media_data_train,
    media_prior=costs,
    target=target_train,
    extra_features=extra_features_train,
    number_warmup=number_warmup,
    number_samples=number_samples,
    seed=SEED
)

Print a summary of the trace:

mmm.print_summary()

Visualize posterior distributions of media effects:

plot.plot_media_channel_posteriors(media_mix_model=mmm)
Christos Visvardis image-1 Creating a Marketing Mix Model with LightweightMMM: A Step-by-Step Guide
Posterior distributions of the media effects

Step 5: Model Evaluation and Prediction

Check the model’s fit to the training data:

plot.plot_model_fit(mmm, target_scaler=target_scaler)
Christos Visvardis image-2 Creating a Marketing Mix Model with LightweightMMM: A Step-by-Step Guide
Our model’s fit to the training data

Make predictions on unseen data:

new_predictions = mmm.predict(
    media=media_scaler.transform(media_data_test),
    extra_features=extra_features_scaler.transform(extra_features_test),
    seed=SEED
)
plot.plot_out_of_sample_model_fit(out_of_sample_predictions=new_predictions,
                                 out_of_sample_target=target_scaler.transform(target[split_point:]))
Christos Visvardis image-3 Creating a Marketing Mix Model with LightweightMMM: A Step-by-Step Guide
Model predictions on unseen data

Step 6: Media Insights

Extract media contribution and ROI estimates:

media_contribution, roi_hat = mmm.get_posterior_metrics(target_scaler=target_scaler, cost_scaler=cost_scaler)

Visualize media contributions over time:

plot.plot_media_baseline_contribution_area_plot(media_mix_model=mmm, target_scaler=target_scaler, fig_size=(30,10))
Christos Visvardis image-4-1024x370 Creating a Marketing Mix Model with LightweightMMM: A Step-by-Step Guide
Estimated media & baseline contribution over time

Visualize media contributions with credibility intervals:

plot.plot_bars_media_metrics(metric=media_contribution, metric_name="Media Contribution Percentage")
plot.plot_bars_media_metrics(metric=roi_hat, metric_name="ROI hat")
Christos Visvardis image-5 Creating a Marketing Mix Model with LightweightMMM: A Step-by-Step Guide
Estimated media contributions with their respective credibility intervals

Step 7: Optimization

Optimize budget allocation based on the model:

n_time_periods = 10
budget = jnp.sum(jnp.dot(prices, media_data.mean(axis=0))) * n_time_periods

solution, kpi_without_optim, previous_media_allocation = optimize_media.find_optimal_budgets(
    n_time_periods=n_time_periods,
    media_mix_model=mmm,
    extra_features=extra_features_scaler.transform(extra_features_test)[:n_time_periods],
    budget=budget,
    prices=prices,
    media_scaler=media_scaler,
    target_scaler=target_scaler,
    seed=SEED
)

Check budget constraint and visualize results:

plot.plot_pre_post_budget_allocation_comparison(
    media_mix_model=mmm,
    kpi_with_optim=solution['fun'],
    kpi_without_optim=kpi_without_optim,
    optimal_buget_allocation=optimal_buget_allocation,
    previous_budget_allocation=previous_budget_allocation,
    figure_size=(10,10)
)
Christos Visvardis image-6 Creating a Marketing Mix Model with LightweightMMM: A Step-by-Step Guide
Pre/post optimization budget allocation comparison for each channel and pre/post optimization predicted target variable comparison

Step 8: Saving and Loading the Model

Save the trained model to disk:

file_path = "media_mix_model.pkl"
utils.save_model(media_mix_model=mmm, file_path=file_path)

Load the saved model:

loaded_mmm = utils.load_model(file_path=file_path)
loaded_mmm.trace["coef_media"].shape  # Example of accessing any of the model values.

Congratulations! You’ve successfully created a Marketing Mix Model using LightweightMMM. Feel free to customize and iterate on this framework based on your specific business needs.