add_saturation_observations#

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

Add saturation observations to the likelihood of the model.

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

Not to be used directly for general use. Use MMM.add_lift_test_measurements() or add_lift_measurements_to_likelihood_from_saturation() instead.

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”

get_indicesCallable[[pd.DataFrame, pm.Model], Indices], optional

Function to get the indices of the DataFrame in the model, by default exact_row_indices which assumes that the columns map exactly to the model coordinates.

variable_indexer_factoryCallable[[pm.Model, Indices], Callable[[str], TensorVariable]], optional

Function to create a variable indexer, by default create_variable_indexer which creates a function to index variables in the model. This is used determine the values of the parameters to evaluate the saturation function.

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_saturation_observations

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_saturation_observations(
        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_saturation_observations

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_saturation_observations(
        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_saturation_observations

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_saturation_observations(
        df_lift_test,
        variable_mapping=saturation.variable_mapping,
        saturation_function=saturation.function,
    )