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, any dims columns, x, delta_x, delta_y, sigma - the exact schema consumed by pymc_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_y and sigma, the measured incremental outcome and its standard error already aggregated to the population and time window ONE target-MMM row represents - or passes aggregation_result= - the pinned container returned by results.aggregate('simple') / results.aggregate('group') (together with scale=, this function deriving delta_y = att * scale and sigma = se * scale per container row) or by results.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, see scale. Either way, PyMC-Marketing scores one row’s delta_y against saturation(x + delta_x) - saturation(x), so x, delta_x, delta_y, and sigma must 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 as x.

  • 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 share delta_x’s sign (see on_wrong_sign). Required together with sigma unless aggregation_result is given (the two routes are mutually exclusive).

  • sigma (float or sequence of float, optional) – Standard error of delta_y (finite, positive). Required together with delta_y unless aggregation_result is given.

  • aggregation_result (AggregationResult, optional) – The pinned container returned by results.aggregate('simple') (one experiment row), results.aggregate('group') (one row per cohort), or results.aggregate('total') (one already-scaled total row). Mutually exclusive with delta_y/sigma; requires scale for ‘simple’/’group’ containers and FORBIDS it for ‘total’. Rows are consumed in aggregation_result.to_dataframe() order - the order summary() prints - and every per-row sequence kwarg (scale, x, delta_x, dims, …) aligns to that order. Raw results objects and EventStudyResults are rejected; this function never calls aggregate() 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 marginal sigma - 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 scalar x or delta_x replicates to every cohort row, asserting the channel’s FULL baseline spend / spend change produced only that cohort’s delta_y - pass per-cohort values; (3) the emitted frame carries NO cohort-label column, so pass per-row dims to 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 in to_dataframe() order; e.g. treated units x treated periods for an unweighted additive fit - an example, not a universal formula). scale="auto" derives scale from the container’s per-row n and is accepted ONLY for ImputationDiD and TwoStageDiD fits, whose n is 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 fits att is a weighted average while n is a raw count); and every treated observation’s effect is identified (ImputationDiD averages finite tau-hat only while n stays the raw count at both levels; TwoStageDiD’s ‘simple’ ATT support excludes rows with non-finite first-stage residuals while n reports 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). An att * scale (or se * scale) that overflows the float range surfaces via this function’s ordinary finiteness errors - sigma is validated before delta_y, so a row where both overflow reports sigma.

  • dims (mapping or sequence of mappings, optional) – Extra model-dimension columns, e.g. {"geo": "US-CA"} for a geo-level MMM built with MMM(dims=("geo",)). Values must match the target model’s coordinate values exactly and identify the population delta_y describes (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) contradicting sign(delta_x) (rejected upstream with NonMonotonicError), or delta_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, heterogeneous dims key sets) or wrong-signed/zero rows under the default policy.