Transformers (transformers.py)¶
This module provides various functions for transforming marketing data, primarily focusing on adstock (carryover effects) and saturation (diminishing returns) transformations commonly used in Marketing Mix Models (MMMs).
Protocols¶
SaturationTransformation¶
class SaturationTransformation(Protocol):
"""Protocol defining the interface for saturation transformations."""
@property
def function(self) -> Callable[..., TensorVariable]:
"""The mathematical function implementing the saturation."""
...
@property
def variable_mapping(self) -> Dict[str, str]:
"""Mapping from saturation function parameter names to model variable names."""
...
A protocol defining the required structure for saturation transformation functions used within the model, particularly for lift testing integration. Classes implementing this protocol must provide:
function: A callable representing the saturation function itself (e.g.,logistic_saturation).variable_mapping: A dictionary mapping the parameter names expected by thefunctionto the corresponding variable names used within the PyMC model.
Enums¶
ConvMode¶
class ConvMode(str, Enum):
After = "After"
Before = "Before"
Overlap = "Overlap"
Enum defining the different modes for applying 1D convolution in batched_convolution, affecting how boundaries are handled.
After: Standard adstock effect with trailing decay.Before: Leading effect (“excitement” or “wow factor”).Overlap: Effect overlaps both preceding and succeeding elements.
WeibullType¶
class WeibullType(str, Enum):
PDF = "PDF"
CDF = "CDF"
Enum defining the type of Weibull distribution function to use for the weibull_adstock transformation.
PDF: Uses the Probability Density Function for weighting.CDF: Uses the complementary Cumulative Distribution Function (1 - CDF) for weighting.
Functions¶
batched_convolution¶
def batched_convolution(
x: TensorLike,
w: TensorLike,
axis: int = 0,
mode: Union[ConvMode, str] = ConvMode.After,
) -> TensorVariable:
Applies a 1D convolution in a vectorized way across multiple batch dimensions. This is the core function used by the adstock transformations.
Parameters:
x(TensorLike): The input array to convolve.w(TensorLike): The convolution weights. The last axis determines the number of steps (lag).axis(int, optional): The axis ofxalong which to apply the convolution. Defaults to0.mode(Union[ConvMode, str], optional): The convolution mode (ConvMode.After,ConvMode.Before,ConvMode.Overlap). Defaults toConvMode.After.
Returns:
TensorVariable: The result of convolvingxwithw. Shape matchesx(considering broadcasting withw).
(See the docstring in the source code for a plot illustrating the different modes.)
geometric_adstock¶
def geometric_adstock(
x: TensorLike,
alpha: float = 0.0,
l_max: int = 12,
normalize: bool = False,
axis: int = 0
) -> TensorVariable:
Applies the geometric adstock transformation, assuming the peak advertising effect occurs at the time of exposure.
Parameters:
x(TensorLike): Input tensor (e.g., media spend/impressions).alpha(float, optional): Retention rate (0 to 1). Higher values mean longer-lasting effects. Defaults to0.0.l_max(int, optional): Maximum duration (lag) of the carryover effect. Defaults to12.normalize(bool, optional): Whether to normalize the adstock weights so they sum to 1. Defaults toFalse.axis(int, optional): Axis along which to apply the transformation. Defaults to0.
Returns:
TensorVariable: The transformed tensor with geometric adstock applied.
(See the docstring in the source code for a plot illustrating the effect of alpha and normalize.)
delayed_adstock¶
def delayed_adstock(
x: TensorLike,
alpha: float = 0.0,
theta: int = 0,
l_max: int = 12,
normalize: bool = False,
axis: int = 0,
) -> TensorLike:
Applies a delayed adstock transformation, allowing the peak effect to occur after the initial exposure time.
Parameters:
x(TensorLike): Input tensor.alpha(float, optional): Retention rate (0 to 1). Defaults to0.0.theta(int, optional): Delay of the peak effect (0 tol_max- 1). Defaults to0.l_max(int, optional): Maximum duration of carryover effect. Defaults to12.normalize(bool, optional): Whether to normalize the weights. Defaults toFalse.axis(int, optional): Axis along which to apply the transformation. Defaults to0.
Returns:
TensorLike: The transformed tensor with delayed adstock applied.
(See the docstring in the source code for a plot illustrating the effect of alpha, theta, and normalize.)
weibull_adstock¶
def weibull_adstock(
x: TensorLike,
lam: float = 1.0,
k: float = 1.0,
l_max: int = 12,
axis: int = 0,
type: Union[WeibullType, str] = WeibullType.PDF,
) -> TensorLike:
Applies an adstock transformation using weights derived from the Weibull distribution (either PDF or CDF). Offers more flexibility than geometric or delayed adstock.
Parameters:
x(TensorLike): Input tensor.lam(float, optional): Scale parameter (lambda > 0) of the Weibull distribution. Defaults to1.0.k(float, optional): Shape parameter (k > 0) of the Weibull distribution. Defaults to1.0.l_max(int, optional): Maximum duration of carryover effect. Defaults to12.axis(int, optional): Axis along which to apply the transformation. Defaults to0.type(Union[WeibullType, str], optional): Type of Weibull function to use (WeibullType.PDForWeibullType.CDF). Defaults toWeibullType.PDF.
Returns:
TensorLike: The transformed tensor with Weibull adstock applied.
(See the docstring in the source code for plots illustrating the effect of lam, k, and type.)
logistic_saturation¶
def logistic_saturation(
x: TensorLike,
lam: Union[npt.NDArray[np.float_], float] = 0.5
) -> TensorVariable:
Applies a logistic saturation function to model diminishing returns.
Formula: (1 - exp(-lam * x)) / (1 + exp(-lam * x))
Parameters:
x(TensorLike): Input tensor (e.g., adstocked media spend).lam(Union[npt.NDArray[np.float_], float], optional): Saturation parameter(s). Higher values cause saturation to occur more quickly. Defaults to0.5.
Returns:
TensorVariable: The transformed tensor with logistic saturation applied.
(See the docstring in the source code for a plot illustrating the effect of lam.)
tanh_saturation¶
def tanh_saturation(
x: TensorLike,
b: TensorLike = 0.5,
c: TensorLike = 0.5,
) -> TensorVariable:
Applies a hyperbolic tangent (tanh) saturation function.
Formula: b * tanh(x / (b * c))
Parameters:
x(TensorLike): Input tensor.b(TensorLike, optional): Saturation level (maximum effect). Defaults to0.5.c(TensorLike, optional): Controls the steepness / initial cost per acquisition. Defaults to0.5.
Returns:
TensorVariable: The transformed tensor with tanh saturation applied.
(See the docstring in the source code for a plot illustrating the effect of b and c.)
tanh_saturation_baselined¶
def tanh_saturation_baselined(
x: TensorLike,
x0: TensorLike,
gain: TensorLike = 0.5,
r: TensorLike = 0.5,
) -> TensorVariable:
Applies a reparameterized tanh saturation function based on a reference point (x0), gain at that point, and an overspend fraction. This parameterization can be more intuitive for setting priors based on domain knowledge.
Parameters:
x(TensorLike): Input tensor.x0(TensorLike): Reference point (e.g., median spend) where gain and overspend fraction are defined.gain(TensorLike, optional): The Return on Ad Spend (ROAS) or effectiveness at the reference pointx0. Defined asf(x0) / x0. Defaults to0.5.r(TensorLike, optional): The overspend fraction, indicating how closef(x0)is to the maximum saturation levelb. Defined asf(x0) / b. Defaults to0.5.
Returns:
TensorVariable: The transformed tensor with baselined tanh saturation applied.
(See the docstring in the source code for a plot illustrating the parameterization.)
Classes¶
LogisticSaturation¶
class LogisticSaturation:
"""Wrapper class for logistic_saturation to conform to SaturationTransformation protocol."""
@property
def function(self) -> Callable[[Any, Any], TensorVariable]: ...
@property
def variable_mapping(self) -> Dict[str, str]: ...
A simple wrapper class that makes the logistic_saturation function conform to the SaturationTransformation protocol. Used for integrating logistic saturation with features like lift testing.
function: Returns thelogistic_saturationfunction.variable_mapping: Returns{"lam": "lam"}, assuming the model variable for the saturation parameter is namedlam.
Named Tuples¶
TanhSaturationParameters¶
class TanhSaturationParameters(NamedTuple):
b: TensorLike # Saturation
c: TensorLike # Customer Acquisition Cost at 0
Represents the standard parameters (b: saturation, c: initial CAC) for the tanh_saturation function.
Methods:
baseline(self, x0: TensorLike) -> TanhSaturationBaselinedParameters: Converts these standard parameters to the baselined parameterization (TanhSaturationBaselinedParameters) given a reference pointx0.
TanhSaturationBaselinedParameters¶
class TanhSaturationBaselinedParameters(NamedTuple):
x0: TensorLike # Baseline spend
gain: TensorLike # ROAS at x0
r: TensorLike # Overspend Fraction (f(x0) / saturation)
Represents the baselined parameters (x0: reference spend, gain: ROAS at x0, r: overspend fraction) for the tanh_saturation_baselined function.
Methods:
debaseline(self) -> TanhSaturationParameters: Converts these baselined parameters back to the standard parameterization (TanhSaturationParameters).rebaseline(self, x1: TensorLike) -> TanhSaturationBaselinedParameters: Converts the parameters to be baselined at a new reference pointx1.