MMM.add_cost_per_target_calibration#

MMM.add_cost_per_target_calibration(data, calibration_data, name_prefix='cpt_calibration', *, target_column='cost_per_target', target_per_cost=False)[source]#

Calibrate cost-per-target (or ROAS) using an observed Normal likelihood.

By default this computes cost-per-target as mean(spend) / mean(contribution) over the date dimension and adds an observed Normal likelihood for each calibration row:

Normal(mu=cpt_mean, sigma=sigma, observed=target)

Set target_per_cost=True to flip the ratio to mean(contribution) / mean(spend), which is ROAS when the target is revenue (or conversions per dollar when the target is conversions).

The numerator and denominator are meaned separately because the ratio of means is the definition of the aggregate cost-per-target (or ROAS) over the period; averaging per-date ratios would estimate a different quantity.

Parameters:
datapd.DataFrame

Feature-like DataFrame with columns matching training X but with channel values representing spend (original units). Must include the same date and any model dims columns.

calibration_datapd.DataFrame

DataFrame with rows specifying calibration targets. Must include:

  • channel: channel name in self.channel_columns

  • the column named by the target_column argument (default "cost_per_target"): the CPT (or ROAS) value to calibrate to

  • sigma: accepted deviation; larger => weaker penalty

and one column per dimension in self.dims.

name_prefixstr

Prefix to use for generated potential names.

target_columnstr

Column in calibration_data holding the calibration values. Defaults to "cost_per_target".

target_per_costbool

If False (default), calibrate mean(spend) / mean(contribution) (cost-per-target). If True, calibrate mean(contribution) / mean(spend) (target-per-cost, e.g. ROAS).

Examples

Build a model and calibrate CPT for selected (dims, channel):

# spend data in original scale with the same structure as X
spend_df = X.copy()
# e.g., if X contains impressions, replace with monetary spend
# spend_df[channels] = ...

calibration_df = pd.DataFrame(
    {
        "channel": ["C1", "C2"],
        "geo": ["US", "US"],  # dims columns as needed
        "cost_per_target": [30.0, 45.0],
        "sigma": [2.0, 3.0],
    }
)

mmm.add_cost_per_target_calibration(
    data=spend_df,
    calibration_data=calibration_df,
    name_prefix="cpt_calibration",
)

Calibrate ROAS instead, using experiment-derived estimates:

roas_df = pd.DataFrame(
    {
        "channel": ["C1", "C2"],
        "geo": ["US", "US"],
        "roas": [3.5, 2.0],
        "sigma": [0.3, 0.2],
    }
)

mmm.add_cost_per_target_calibration(
    data=spend_df,
    calibration_data=roas_df,
    name_prefix="roas_calibration",
    target_column="roas",
    target_per_cost=True,
)