diff_diff.to_pymc_marketing_lift_test#
- diff_diff.to_pymc_marketing_lift_test(*, channel, x, delta_x, delta_y=None, sigma=None, aggregation_result=None, scale=None, dims=None, on_wrong_sign='raise')[source]
Assemble a PyMC-Marketing lift-test DataFrame from scoped experiment results.
Produces one row per experiment with columns
channel, anydimscolumns,x,delta_x,delta_y,sigma- the exact schema consumed bypymc_marketing.mmm.MMM.add_lift_test_measurements(prophetverse’s lift-test API accepts the same shape). All values stay in original data units (PyMC-Marketing rescales internally).Two input routes. Either the caller supplies the scoped effect explicitly -
delta_yandsigma, the measured incremental outcome and its standard error already aggregated to the population and time window ONE target-MMM row represents - or passesaggregation_result=- the pinned container returned byresults.aggregate('simple')/results.aggregate('group')(together withscale=, this function derivingdelta_y = att * scaleandsigma = se * scaleper container row) or byresults.aggregate('total')(a single already-scaled total row; NO scale accepted). Rescaling is performed ONLY under that explicit contract - reconciliation context the container cannot carry (the MMM’s row granularity, the outcome’s scale) remains the caller’s acknowledgement, seescale. Either way, PyMC-Marketing scores one row’sdelta_yagainstsaturation(x + delta_x) - saturation(x), sox,delta_x,delta_y, andsigmamust all describe the SAME observation (same channel, same population, same period span, additive-level outcome).- Parameters:
channel (str or sequence of str) – MMM channel name(s); must match the target model’s
channel_columns.x (float or sequence of float) – Baseline channel spend for the row’s observation, in original spend units.
delta_x (float or sequence of float) – Spend change during the experiment (nonzero; negative for go-dark/holdout tests, with
x + delta_x >= 0), in the same units asx.delta_y (float or sequence of float, optional) – Measured incremental outcome for the SAME observation as
x/delta_x, in original outcome units. Finite; must be nonzero and sharedelta_x’s sign (seeon_wrong_sign). Required together withsigmaunlessaggregation_resultis given (the two routes are mutually exclusive).sigma (float or sequence of float, optional) – Standard error of
delta_y(finite, positive). Required together withdelta_yunlessaggregation_resultis given.aggregation_result (AggregationResult, optional) – The pinned container returned by
results.aggregate('simple')(one experiment row),results.aggregate('group')(one row per cohort), orresults.aggregate('total')(one already-scaled total row). Mutually exclusive withdelta_y/sigma; requiresscalefor ‘simple’/’group’ containers and FORBIDS it for ‘total’. Rows are consumed inaggregation_result.to_dataframe()order - the ordersummary()prints - and every per-row sequence kwarg (scale,x,delta_x,dims, …) aligns to that order. Raw results objects andEventStudyResultsare rejected; this function never callsaggregate()itself. On a bootstrapped fit,aggregate('simple')and, where supported,aggregate('total')relay the stored percentile SE, which is used as-is. Group-container cautions: (1) cohort rows come from ONE fit sharing controls and windows, yet each emitted lift row is scored by PyMC-Marketing as an independent observation with only its marginalsigma- the omitted cross-cohort covariance can misstate the joint evidence (overstating it when the net covariance is positive, as shared controls typically induce), and its direction cannot be determined from marginal SEs alone; (2) a scalarxordelta_xreplicates to every cohort row, asserting the channel’s FULL baseline spend / spend change produced only that cohort’sdelta_y- pass per-cohort values; (3) the emitted frame carries NO cohort-label column, so pass per-rowdimsto keep multi-cohort rows distinguishable.scale (float, sequence of float, or "auto", optional) – Converts each container row’s per-observation ATT to the row’s total incremental outcome:
delta_y = att * scale,sigma = se * scale. Required with a ‘simple’/’group’aggregation_result; forbidden with a ‘total’ container, whose row is already the estimator-owned total (finite, positive; scalar or one value per row into_dataframe()order; e.g. treated units x treated periods for an unweighted additive fit - an example, not a universal formula).scale="auto"derivesscalefrom the container’s per-rownand is accepted ONLY for ImputationDiD and TwoStageDiD fits, whosenis the treated observations the ATT averages over. Passing"auto"acknowledges three assumptions the container cannot verify: the outcome is in additive levels (not log/rate/share); the fit is unweighted (on survey-weighted fitsattis a weighted average whilenis a raw count); and every treated observation’s effect is identified (ImputationDiD averages finite tau-hat only whilenstays the raw count at both levels; TwoStageDiD’s ‘simple’ ATT support excludes rows with non-finite first-stage residuals whilenreports the pre-filter count, though its ‘group’ counts are post-filter - the affected fits warn at fit time on the degenerate branch, and"auto"there overcounts). Anatt * scale(orse * scale) that overflows the float range surfaces via this function’s ordinary finiteness errors -sigmais validated beforedelta_y, so a row where both overflow reportssigma.dims (mapping or sequence of mappings, optional) – Extra model-dimension columns, e.g.
{"geo": "US-CA"}for a geo-level MMM built withMMM(dims=("geo",)). Values must match the target model’s coordinate values exactly and identify the populationdelta_ydescribes (do not label a multi-geo average with one specific geo). All rows must share one key set; column order follows the first mapping.on_wrong_sign ({"raise", "drop", "keep"}, default "raise") – Policy for rows PyMC-Marketing cannot use:
sign(delta_y)contradictingsign(delta_x)(rejected upstream withNonMonotonicError), ordelta_y == 0(degenerate for its strictly-positive Gamma lift likelihood, which its own monotonicity check does not catch)."raise"(default) errors with guidance;"drop"warns and removes such rows (raises if that would empty the frame);"keep"warns and emits them anyway (for non-PyMC consumers - the frame is not valid PyMC-Marketing input).
- Returns:
Columns
[channel, *dims, x, delta_x, delta_y, sigma], one row per experiment.- Return type:
pd.DataFrame
- Raises:
ValueError – On invalid inputs (non-positive
sigma, non-finite values,delta_x == 0,x + delta_x < 0, broadcasting length mismatches, empty inputs, heterogeneousdimskey sets) or wrong-signed/zero rows under the default policy.