add_lift_measurements_to_likelihood#

pymc_marketing.mmm.lift_test.add_lift_measurements_to_likelihood(df_lift_test, variable_mapping, saturation_function, model=None, dist=<class 'pymc.distributions.continuous.Gamma'>, name='lift_measurements')[source]#

Add lift measurements to the likelihood of the model.

General function to add lift measurements to the likelihood of the model.

Parameters:
df_lift_testpd.DataFrame
DataFrame with lift test results with at least the following columns:
  • x: x axis value of the lift test.

  • delta_x: change in x axis value of the lift test.

  • delta_y: change in y axis value of the lift test.

  • sigma: standard deviation of the lift test.

Any additional columns are assumed to be coordinates in the model.

variable_mappingdict[str, str]

Dictionary of variable names to dimensions.

saturation_functionCallable[[np.ndarray], np.ndarray]

Function that takes spend and returns saturation.

modelOptional[pm.Model], optional

PyMC model with arbitrary number of coordinates, by default None

distpm.Distribution class, optional

PyMC distribution to use for the likelihood, by default pm.Gamma

namestr, optional

Name of the likelihood, by default “lift_measurements”

Examples

Add lift tests for time-varying saturation to a model:

import pymc as pm
import pandas as pd
from pymc_marketing.mmm.lift_test import add_lift_measurements_to_likelihood

df_base_lift_test = pd.DataFrame({
    "x": [1, 2, 3],
    "delta_x": [1, 2, 3],
    "delta_y": [1, 2, 3],
    "sigma": [0.1, 0.2, 0.3],
})

def saturation_function(x, alpha, lam):
    return alpha * x / (x + lam)

# These are required since alpha and lam
# have both channel and date dimensions
df_lift_test = df_base_lift_test.assign(
    channel="channel_1",
    date=["2019-01-01", "2019-01-02", "2019-01-03"],
)

coords = {
    "channel": ["channel_1", "channel_2"],
    "date": ["2019-01-01", "2019-01-02", "2019-01-03", "2019-01-04"],
}
with pm.Model(coords=coords) as model:
    # Usually defined in a larger model.
    # Distributions dont matter here, just the shape
    alpha = pm.HalfNormal("alpha_in_model", dims=("channel", "date"))
    lam = pm.HalfNormal("lam_in_model", dims="channel")

    add_lift_measurements_to_likelihood(
        df_lift_test,
        variable_mapping={
            "alpha": "alpha_in_model",
            "lam": "lam_in_model",
        },
        saturation_function=saturation_function,
    )

Use the saturation classes to add lift tests to a model. NOTE: This is what happens internally of MMM.

import pymc as pm
import pandas as pd

from pymc_marketing.mmm import LogisticSaturation
from pymc_marketing.mmm.lift_test import add_lift_measurements_to_likelihood

saturation = LogisticSaturation()

df_base_lift_test = pd.DataFrame({
    "x": [1, 2, 3],
    "delta_x": [1, 2, 3],
    "delta_y": [1, 2, 3],
    "sigma": [0.1, 0.2, 0.3],
})

df_lift_test = df_base_lift_test.assign(
    channel="channel_1",
)

coords = {
    "channel": ["channel_1", "channel_2"],
}
with pm.Model(coords=coords) as model:
    # Usually defined in a larger model.
    # Distributions dont matter here, just the shape
    lam = pm.HalfNormal("saturation_lam", dims="channel")
    beta = pm.HalfNormal("saturation_beta", dims="channel")

    add_lift_measurements_to_likelihood(
        df_lift_test,
        variable_mapping=saturation.variable_mapping,
        saturation_function=saturation.function,
    )

Add lift tests for channel, geo saturation functions.

import pymc as pm
import pandas as pd

from pymc_marketing.mmm import LogisticSaturation
from pymc_marketing.mmm.lift_test import add_lift_measurements_to_likelihood

saturation = LogisticSaturation()

df_base_lift_test = pd.DataFrame({
    "x": [1, 2, 3],
    "delta_x": [1, 2, 3],
    "delta_y": [1, 2, 3],
    "sigma": [0.1, 0.2, 0.3],
})

df_lift_test = df_base_lift_test.assign(
    channel="channel_1",
    geo=["G1", "G2", "G2"],
)

coords = {
    "channel": ["channel_1", "channel_2"],
    "geo": ["G1", "G2", "G3"],
}
with pm.Model(coords=coords) as model:
    # Usually defined in a larger model.
    # Distributions dont matter here, just the shape
    lam = pm.HalfNormal("saturation_lam", dims=("channel", "geo"))
    beta = pm.HalfNormal("saturation_beta", dims=("channel", "geo"))

    add_lift_measurements_to_likelihood(
        df_lift_test,
        variable_mapping=saturation.variable_mapping,
        saturation_function=saturation.function,
    )