← Back to Curriculum
Module 04

The Memory Effect

Feature Engineering Part I: Modeling how consumer memory decays over time using Adstock transformations.

If I show you a TV commercial today, you don't instantly buy the product and then forget about it tomorrow. The ad lingers in your memory. You might buy the product three days later, or next week. This is called the Carry-Over Effect.

Raw media spend data does not account for this. If you spend $100 on Monday and $0 on Tuesday, your raw data says Tuesday has 0 marketing pressure. But reality says Tuesday still has "leftover" pressure from Monday.

In MMM, we model this using a transformation called Adstock.

1. Geometric Adstock (Simple Decay)

The simplest way to model memory is to assume it fades at a constant rate every day (or week). This is the "Geometric" decay.

It uses a single parameter: Alpha (α), also known as the decay rate.
- If α = 0.9, you retain 90% of the ad's effect next week. (Long memory, like TV).
- If α = 0.1, you retain only 10% of the effect. (Short memory, like Direct Response FB ads).

Adstockt = Spendt + (α × Adstockt-1)

Python Implementation

def geometric_adstock(x, alpha):
    """
    x: Array of media spend
    alpha: Decay rate (0 to 1)
    """
    x_decayed = [x[0]]
    for i in range(1, len(x)):
        x_decayed.append(x[i] + alpha * x_decayed[i-1])
    return x_decayed

# Example Usage
# TV usually has high retention (0.8), Social has low (0.3)
df['tv_adstock'] = geometric_adstock(df['tv_spend'], 0.8)

2. Weibull Adstock (Advanced)

Geometric decay is limited because it assumes the peak impact always happens on Day 1. But what if you see an ad today, but it takes 3 days for it to "sink in"?

Imagine a complex B2B product or a movie trailer. The buzz might build up before it decays. Geometric adstock cannot model this "delayed peak." Weibull Adstock can.

Geometric [Image of Geometric Decay Curve]

Starts high, drops immediately. Good for CPG/Retail sales.

Weibull [Image of Weibull Decay Curve]

Can start low, peak later (Day 3), then drop. Good for complex purchases.

Python Implementation

Weibull uses two parameters: Shape (k) and Scale (lambda). It essentially creates a distribution of weights over time.

import numpy as np
from scipy import stats

def weibull_adstock(x, shape, scale):
    """
    Weibull PDF transformation for flexible decay
    """
    # Create a window of lag weights (e.g., 52 weeks)
    lag_weights = stats.weibull_min.pdf(np.arange(52), shape, scale=scale)
    
    # Normalize weights so they sum to 1
    lag_weights = lag_weights / np.sum(lag_weights)
    
    # Convolve raw spend with weights
    return np.convolve(x, lag_weights)[:len(x)]

3. Which one should you use?

In a modern MMM pipeline, we don't guess. We treat Alpha (for Geometric) or Shape/Scale (for Weibull) as hyperparameters.

When we get to Module 9 (Optimization), we will let the model test thousands of different Alpha values (0.1, 0.2, ... 0.9) to see which one creates the best fit with Sales. We let the data tell us how long the memory of a TV ad lasts.

Previous Module ← Visualizing the Pulse