add_cost_per_target_observations#

pymc_marketing.mmm.lift_test.add_cost_per_target_observations(calibration_df, *, model=None, cost_value, target_value, target_column='cost_per_target', name_prefix='cpt_calibration', target_per_cost=False, get_indices=<function exact_row_indices>)[source]#

Add observed Normal likelihood to calibrate cost-per-target.

By default the ratio is mean(cost) / mean(target) (cost-per-target). Set target_per_cost=True to flip it to mean(target) / mean(cost) (target-per-cost, e.g. conversions per dollar).

An observed Normal likelihood term is added for each calibration row:

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

Using the mean of numerator and denominator separately avoids mean(cost / target) which is numerically unstable when spend is spiky and the channel has slow or delayed adstock decay.

Parameters:
calibration_dfpd.DataFrame

Must include columns channel, sigma, and a target column. By default the target column is assumed to be cost_per_target. The DataFrame must also include one column per model dimension found in the CPT variable (excluding date).

modelpm.Model, optional

Model containing the cost-per-target tensor. If None, uses the current model context.

cost_valueXTensorVariable

XTensor representing cost (spend) values over the model coordinates, including a date dimension.

target_valueXTensorVariable

XTensor representing target (contribution) values over the model coordinates, including a date dimension.

target_columnstr

Column in calibration_df containing the calibration targets.

name_prefixstr

Name for the observed likelihood variable.

target_per_costbool

If False (default), computes mean(cost) / mean(target). If True, computes mean(target) / mean(cost).

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

Alignment function mapping rows to model coordinate indices.

Examples

cost = as_xtensor(spend_array, dims=("date", "geo", "channel"))
target = as_xtensor(contribution_array, dims=("date", "geo", "channel"))

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

add_cost_per_target_observations(
    calibration_df=calibration_df,
    model=mmm.model,
    cost_value=cost,
    target_value=target,
    name_prefix="cpt_calibration",
)