PlaceboInTime#
- class causalpy.checks.placebo_in_time.PlaceboInTime[source]#
Placebo-in-time sensitivity check with hierarchical null model.
Shifts the treatment time backward into the pre-intervention period to create
n_foldsplacebo experiments. Extracts the posterior cumulative impact from each fold, then fits a hierarchical Bayesian model to characterise the “status quo” distribution of effects when no intervention occurred. The actual intervention’s cumulative effect is compared against this learned null.When
expected_effect_priorandrope_half_widthare provided, additionally computes Bayesian assurance (operating characteristics) via simulation.- Parameters:
n_folds (
int) – Number of placebo folds to create. Must be >= 1. Each fold consumes oneintervention_lengthof pre-treatment history, so on a short pre-period a largen_foldsproduces ineligible folds that are skipped; shortenintervention_lengthto fit more folds.selection_method (
Literal['sequential','random']) –How to choose placebo windows.
"sequential"— evenly-spaced sliding windows stepping backward from the treatment time (original behaviour)."random"— randomly sample eligible windows from the pre-intervention period, subject tomin_training_pct,min_gap, andexclude_periodsconstraints.
Every placebo fold must have at least one full intervention window of observed pre-treatment history. Sequential folds that do not meet this rule are skipped with a warning and deterministic
skipped_foldsmetadata; random selection excludes them from its candidate pool.min_training_pct (
float) –(random mode only) Minimum fraction of total pre-period observations that must precede each candidate placebo window.
Note: the eligible pre-period is further shortened because a candidate’s pseudo-intervention window must also end before the actual treatment. With the derived default
intervention_length(see below) that window is roughly the post-period length, which can make the effective eligible window much smaller than(1 - min_training_pct)suggests; pass an explicitintervention_lengthto widen it.min_gap (
int) – (random mode only) Minimum number of pre-intervention observations between any two selected folds, measured as positions in the sorted pre-period index. The default of1only forbids picking the same candidate twice; use a larger value to spread folds further apart. Whenallow_overlapisFalse(the default) non-overlap of pseudo-intervention windows is enforced independently ofmin_gap.allow_overlap (
bool) – (random mode only) IfFalse(the default), selected pseudo-intervention windows are required to be non-overlapping in index/time units. Two folds at timest_aandt_bare considered non-overlapping whenabs(t_a - t_b) >= intervention_length. Set toTrueto allow overlapping windows, which relaxes the constraint at the cost of violating the exchangeability assumption of the hierarchical status-quo model (each fold mean is treated as an independent draw from a commonmu_status_quo).exclude_periods (
set[str] |None) – (random mode only) Set of period labels to exclude from candidate selection. For datetime-indexed data, use"YYYY-MM"strings; for numeric indices, use string representations of the index values.experiment_factory (
Any|None) – Custom factory(data, treatment_time) -> BaseExperiment. IfNone(default), the factory is derived from the pipeline’sexperiment_config. Required for standalone (non-pipeline) use. This is the escape hatch for adapting the model to the eligible placebo-fold data; custom factories remain responsible for any model-specific randomness they introduce.sample_kwargs (
dict[str,Any] |None) – MCMC settings for the hierarchical status-quo model. Defaults to{"draws": 1000, "chains": 4, "target_accept": 0.97}.threshold (
float) – Probability cutoff. Used both forpassed(P(actual effect outside null) must exceed this) and for the ROPE decision rule when computing assurance.prior_scale (
float) – Multiplier for auto-computed prior widths on the hierarchical model. The priors aremu ~ Normal(center, 5 * prior_scale * data_scale)andtau ~ HalfNormal(2 * prior_scale * data_scale).expected_effect_prior (
Any|None) – Prior belief about the true total effect under the alternative hypothesis. Accepts any object with an.rvs(n)method (PreliZ, scipy) or a numpy array of pre-drawn samples. Whenrandom_seedis set, distributions exposingrandom_statereceive a derived Generator; legacy.rvs(n)distributions remain supported but emit a reproducibility warning and are recorded in result metadata. Provided together withrope_half_width, assurance analysis runs automatically.rope_half_width (
float|None) – Half-width of the ROPE interval[-rope, +rope]. Required whenexpected_effect_prioris provided.n_design_replications (
int|None) – Number of simulation replications for assurance. Defaults tomin(theta_new.size, expected_effect_samples.size).random_seed (
int|None) – Master RNG seed for random fold selection, automatically constructed placebo-fold fits (usingrandom_seed + fold_index), hierarchical posterior predictive sampling, and assurance simulation. It also seeds the hierarchicalpm.samplecall unlesssample_kwargs["random_seed"]is explicitly supplied, which takes precedence for that call only.intervention_length (
Any|None) –Length of each placebo intervention window, in index units. When
None(default) the length is derived from the experiment:treatment_end_time - treatment_timewhen the experiment defines an explicit intervention window, otherwisedata.index.max() - treatment_time(roughly the post-period length).Set this explicitly to fit more well-supported folds into a short pre-period. The derived default consumes one post-period worth of history per fold, so when the pre-period is only a few times longer than the post-period the earliest folds fail the eligibility rule above and are skipped. A shorter
intervention_lengthshortens both the placebo window and the history each fold requires, so more folds become eligible.The actual effect is still summarised over the full post-intervention period, so a window materially shorter than that period compares a long actual cumulative impact against a null built from short windows, which inflates
P(actual outside null). Both observation counts are recorded inmetadata["comparison_window"]and a warning is emitted when they disagree by more than the one-observation half-open-window artefact of the derived default.
Examples
>>> import causalpy as cp >>> check = cp.checks.PlaceboInTime(n_folds=3)
Random selection with constraints:
>>> check = cp.checks.PlaceboInTime( ... n_folds=4, ... selection_method="random", ... min_training_pct=0.30, ... min_gap=2, ... random_seed=42, ... )
Methods
Apply a ROPE-based Bayesian decision rule.
PlaceboInTime.run(experiment[, context])Run placebo-in-time analysis with hierarchical null model.
PlaceboInTime.validate(experiment)Check the experiment is compatible with PlaceboInTime.
Attributes
applicable_methods- __init__(n_folds=3, selection_method='sequential', min_training_pct=0.3, min_gap=1, allow_overlap=False, exclude_periods=None, experiment_factory=None, sample_kwargs=None, threshold=0.95, prior_scale=1.0, expected_effect_prior=None, rope_half_width=None, n_design_replications=None, random_seed=None, intervention_length=None)[source]#
- Parameters:
n_folds (int)
selection_method (Literal['sequential', 'random'])
min_training_pct (float)
min_gap (int)
allow_overlap (bool)
experiment_factory (Any | None)
threshold (float)
prior_scale (float)
expected_effect_prior (Any | None)
rope_half_width (float | None)
n_design_replications (int | None)
random_seed (int | None)
intervention_length (Any | None)
- Return type:
None
- classmethod __new__(*args, **kwargs)#