SoftPlusHSGP#

pydantic model pymc_marketing.mmm.hsgp.SoftPlusHSGP[source]#

HSGP with softplus transformation.

The use of the softplus transformation maps the latent GP to positive values. We then normalize multiplicatively by the time-mean so the resulting multiplier has mean 1 over the first dimension while remaining strictly positive.

Examples

Literature recommended SoftPlusHSGP configuration:

import numpy as np
import pandas as pd

import matplotlib.pyplot as plt

from pymc_marketing.mmm import SoftPlusHSGP

seed = sum(map(ord, "Out of the box GP"))
rng = np.random.default_rng(seed)

n = 52
X = np.arange(n)

hsgp = SoftPlusHSGP.parameterize_from_data(
    X=X,
    dims="time",
)

dates = pd.date_range("2022-01-01", periods=n, freq="W-MON")
coords = {
    "time": dates,
}
prior = hsgp.sample_prior(coords=coords, random_seed=rng)
curve = prior["f"]
hsgp.plot_curve(curve, random_seed=rng)
plt.show()

(Source code, png, hires.png, pdf)

../../_images/pymc_marketing-mmm-hsgp-SoftPlusHSGP-1.png

New data predictions with SoftPlusHSGP

Note

In making the predictions, the model needs to be transformed in order to keep the data centered around 1. There is a helper function pymc_marketing.model_graph.deterministics_to_flat() that can be used to transform the model upon out of sample predictions.

This transformation is automatically handled in the provided MMMs.

import numpy as np
import pandas as pd

import pymc as pm

import matplotlib.pyplot as plt

from pymc_marketing.mmm import SoftPlusHSGP
from pymc_marketing.model_graph import deterministics_to_flat
from pymc_extras.prior import Prior

seed = sum(map(ord, "New data predictions with SoftPlusHSGP"))
rng = np.random.default_rng(seed)

eta = Prior("Exponential", lam=1)
ls = Prior("InverseGamma", alpha=2, beta=1)
hsgp = SoftPlusHSGP(
    eta=eta,
    ls=ls,
    m=20,
    L=150,
    dims=("time", "channel"),
)

n = 52
X = np.arange(n)

channels = ["A", "B", "C"]
dates = pd.date_range("2022-01-01", periods=n, freq="W-MON")
coords = {"time": dates, "channel": channels}
with pm.Model(coords=coords) as model:
    data = pm.Data("data", X, dims="time")
    hsgp.register_data(data).create_variable("f", xdist=True)
    idata = pm.sample_prior_predictive(random_seed=rng)

prior = idata.prior

n_new = 10
X_new = np.arange(n - 1 , n + n_new)
last_date = dates[-1]
new_dates = pd.date_range(last_date, periods=n_new + 1, freq="W-MON")

with deterministics_to_flat(model, hsgp.deterministics_to_replace("f")):
    pm.set_data(
        new_data={
            "data": X_new,
        },
        coords={"time": new_dates},
    )
    post = pm.sample_posterior_predictive(
        prior,
        var_names=["f"],
        random_seed=rng,
    )

chain, draw = 0, rng.choice(prior.sizes["draw"])
colors = [f"C{i}" for i in range(len(channels))]

def get_sample(curve):
    return curve.loc[chain, draw].to_series().unstack()

ax = prior["f"].pipe(get_sample).plot(color=colors)
post.posterior_predictive["f"].pipe(get_sample).plot(
    ax=ax, color=colors, linestyle="--", legend=False
)
ax.set(xlabel="time", ylabel="f", title="New data predictions")
plt.show()

(Source code, png, hires.png, pdf)

../../_images/pymc_marketing-mmm-hsgp-SoftPlusHSGP-2.png

Methods

SoftPlusHSGP.__init__(**data)

Create a new model by parsing and validating input data from keyword arguments.

SoftPlusHSGP.create_variable(name[, xdist])

Create the variable.

SoftPlusHSGP.deterministics_to_replace(name)

Name of the Deterministic variables that are replaced with pm.Flat for out-of-sample.

SoftPlusHSGP.from_dict(data)

Create an object from a dictionary.

SoftPlusHSGP.parameterize_from_data(X, dims)

Create a HSGP informed by the data with literature-based recommendations.

SoftPlusHSGP.plot_curve(curve[, n_samples, ...])

Plot the curve.

SoftPlusHSGP.register_data(X)

Register the data to be used in the model.

SoftPlusHSGP.sample_prior([coords])

Sample from the prior distribution.

SoftPlusHSGP.to_dict([_orig])

Convert the object to a dictionary.

field L: float [Required][source]#

Extent of basis functions

Constraints:
  • gt = 0

field X: InstanceOf[XTensorVariable] | InstanceOf[DataArray] | InstanceOf[np.ndarray] | None = None[source]#

The data to be used in the model

field X_mid: float | None = None[source]#

The mean of the training data

field centered: bool = False[source]#

Whether the model is centered or not

field cov_func: CovFunc = CovFunc.ExpQuad[source]#

The covariance function

field demeaned_basis: bool = False[source]#

Whether each basis has its mean subtracted from it.

field dims: Dims [Required][source]#

The dimensions of the variable

field drop_first: bool = True[source]#

Whether to drop the first basis function

field eta: InstanceOf[VariableFactory] | DeferredFactory | float [Required][source]#

Prior for the variance

field ls: InstanceOf[VariableFactory] | DeferredFactory | float [Required][source]#

Prior for the lengthscales

field m: int [Required][source]#

Number of basis functions

field transform: str | None = None[source]#

Optional transformation for the variable. Must be registered or from either pytensor.tensor or pymc.math namespaces.