trama#

Clase de trazado relacionada con MMM.

Ejemplos#

Inicio rápido con MMM:

from pymc_marketing.mmm import GeometricAdstock, LogisticSaturation
from pymc_marketing.mmm.multidimensional import MMM
import pandas as pd

# Minimal dataset
X = pd.DataFrame(
    {
        "date": pd.date_range("2025-01-01", periods=12, freq="W-MON"),
        "C1": [100, 120, 90, 110, 105, 115, 98, 102, 108, 111, 97, 109],
        "C2": [80, 70, 95, 85, 90, 88, 92, 94, 91, 89, 93, 87],
    }
)
y = pd.Series(
    [230, 260, 220, 240, 245, 255, 235, 238, 242, 246, 233, 249], name="y"
)

mmm = MMM(
    date_column="date",
    channel_columns=["C1", "C2"],
    target_column="y",
    adstock=GeometricAdstock(l_max=10),
    saturation=LogisticSaturation(),
)
mmm.fit(X, y)
mmm.sample_posterior_predictive(X)

# Posterior predictive time series
_ = mmm.plot.posterior_predictive(var=["y"], hdi_prob=0.9)

# Residuals over time (true - predicted)
_ = mmm.plot.residuals_over_time(hdi_prob=[0.94, 0.50])

# Residuals posterior distribution
_ = mmm.plot.residuals_posterior_distribution(aggregation="mean")

# Posterior contributions over time (e.g., channel_contribution)
_ = mmm.plot.contributions_over_time(var=["channel_contribution"], hdi_prob=0.9)

# Posterior distribution of parameters (e.g., saturation parameter by channel)
_ = mmm.plot.posterior_distribution(var="lam", plot_dim="channel")

# Channel saturation scatter plot (scaled space by default)
_ = mmm.plot.saturation_scatterplot(original_scale=False)

# Channel contribution share forest plot
_ = mmm.plot.channel_contribution_share_hdi(hdi_prob=0.94)

Envuelva un modelo PyMC personalizado#

Requisitos

  • gráficas predictivas posteriores: un az.InferenceData con un grupo posterior_predictive que contiene la(s) variable(s) que desea graficar con una coordenada date.

  • residuals plots: a posterior_predictive group with y_original_scale variable (with date) and a constant_data group with target_data variable.

  • contribuciones_a_lo_largo_del_tiempo gráficos: un grupo posterior con variables de series temporales (con fecha).

  • gráficos de saturación: un conjunto de datos constant_data con variables: - channel_data: las dimensiones incluyen ("fecha", "canal", ...) - channel_scale: las dimensiones incluyen ("canal", ...) - target_scale: escalar o transmisible a las dimensiones de la curva y una variable posterior llamada channel_contribution (o channel_contribution_original_scale si se grafica original_scale=True).

import numpy as np
import pandas as pd
import pymc as pm
from pymc_marketing.mmm.plot import MMMPlotSuite

dates = pd.date_range("2025-01-01", periods=30, freq="D")
y_obs = np.random.normal(size=len(dates))

with pm.Model(coords={"date": dates}):
    sigma = pm.HalfNormal("sigma", 1.0)
    pm.Normal("y", 0.0, sigma, observed=y_obs, dims="date")

    idata = pm.sample_prior_predictive(random_seed=1)
    idata.extend(pm.sample(draws=200, chains=2, tune=200, random_seed=1))
    idata.extend(pm.sample_posterior_predictive(idata, random_seed=1))

plot = MMMPlotSuite(idata)
_ = plot.posterior_predictive(var=["y"], hdi_prob=0.9)

Contribuciones personalizadas_a_lo_largo_del_tiempo#

import numpy as np
import pandas as pd
import pymc as pm
from pymc_marketing.mmm.plot import MMMPlotSuite

dates = pd.date_range("2025-01-01", periods=30, freq="D")
x = np.linspace(0, 2 * np.pi, len(dates))
series = np.sin(x)

with pm.Model(coords={"date": dates}):
    pm.Deterministic("component", series, dims="date")
    idata = pm.sample_prior_predictive(random_seed=2)
    idata.extend(pm.sample(draws=50, chains=1, tune=0, random_seed=2))

plot = MMMPlotSuite(idata)
_ = plot.contributions_over_time(var=["component"], hdi_prob=0.9)

Gráficos de saturación con un modelo personalizado#

import numpy as np
import pandas as pd
import xarray as xr
import pymc as pm
from pymc_marketing.mmm.plot import MMMPlotSuite

dates = pd.date_range("2025-01-01", periods=20, freq="W-MON")
channels = ["C1", "C2"]

# Create constant_data required for saturation plots
channel_data = xr.DataArray(
    np.random.rand(len(dates), len(channels)),
    dims=("date", "channel"),
    coords={"date": dates, "channel": channels},
    name="channel_data",
)
channel_scale = xr.DataArray(
    np.ones(len(channels)),
    dims=("channel",),
    coords={"channel": channels},
    name="channel_scale",
)
target_scale = xr.DataArray(1.0, name="target_scale")

# Build a toy model that yields a matching posterior var
with pm.Model(coords={"date": dates, "channel": channels}):
    # A fake contribution over time per channel (dims must include date & channel)
    contrib = pm.Normal("channel_contribution", 0.0, 1.0, dims=("date", "channel"))

    idata = pm.sample_prior_predictive(random_seed=3)
    idata.extend(pm.sample(draws=50, chains=1, tune=0, random_seed=3))

# Attach constant_data to idata
idata.constant_data = xr.Dataset(
    {
        "channel_data": channel_data,
        "channel_scale": channel_scale,
        "target_scale": target_scale,
    }
)

plot = MMMPlotSuite(idata)
_ = plot.saturation_scatterplot(original_scale=False)

Notas#

  • MMM expone esta suite a través de la propiedad mmm.plot, que internamente pasa el idata del modelo a MMMPlotSuite.

  • Cualquier modelo de PyMC puede utilizar MMMPlotSuite directamente si su InferenceData contiene los grupos/variables necesarios descritos anteriormente.

Clases

MMMPlotSuite([idata, data])

Suite de Gráficos del Modelo de Mezcla de Medios.