Results Classes#
Dataclass containers for estimation results from various estimators.
DiDResults#
Results from basic DifferenceInDifferences estimation.
- class diff_diff.DiDResults[source]
Bases:
BaseResultsResults from a Difference-in-Differences estimation.
Provides easy access to coefficients, standard errors, confidence intervals, and summary statistics in a Pythonic way.
- att
Average Treatment effect on the Treated (ATT).
- Type:
- se
Standard error of the ATT estimate.
- Type:
- t_stat
T-statistic for the ATT estimate.
- Type:
- p_value
P-value for the null hypothesis that ATT = 0.
- Type:
- n_obs
Number of observations used in estimation.
- Type:
- n_treated
Number of treated units/observations.
- Type:
- n_control
Number of control units/observations.
- Type:
Attributes
is_significantCheck if the ATT is statistically significant at the alpha level.
significance_starsReturn significance stars based on p-value.
Methods
summary([alpha])Generate a formatted summary of the estimation results.
to_dict()Convert results to a dictionary.
to_dataframe()Convert results to a pandas DataFrame.
- att: float
- se: float
- t_stat: float
- p_value: float
- n_obs: int
- n_treated: int
- n_control: int
- alpha: float = 0.05
- inference_method: str = 'analytical'
- property coef_var: float
SE / abs(ATT). NaN when ATT is 0 or SE non-finite.
- Type:
Coefficient of variation
- summary(alpha=None)[source]
Generate a formatted summary of the estimation results.
- Parameters:
alpha (float, optional) – Accepted for signature uniformity. The stored intervals were computed at fit time; a value different from the stored
alpharaises ValueError rather than silently recomputing or relabeling. Re-fit at the desired alpha instead.- Returns:
Formatted summary table.
- Return type:
- print_summary(alpha=None)[source]
Print the summary to stdout.
- Parameters:
alpha (float | None)
- Return type:
None
- to_dict()[source]
Convert results to a dictionary.
- Returns:
Dictionary containing all estimation results.
- Return type:
Dict[str, Any]
- to_dataframe()[source]
Convert results to a pandas DataFrame.
- Returns:
DataFrame with estimation results.
- Return type:
pd.DataFrame
- property is_significant: bool
Check if the ATT is statistically significant at the alpha level.
- property significance_stars: str
Return significance stars based on p-value.
- __init__(att, se, t_stat, p_value, conf_int, n_obs, n_treated, n_control, alpha=0.05, coefficients=None, vcov=None, residuals=None, fitted_values=None, r_squared=None, inference_method='analytical', n_bootstrap=None, n_clusters=None, p_val_type=None, bootstrap_distribution=None, survey_metadata=None, vcov_type=None, cluster_name=None, conley_lag_cutoff=None, df_convention=None, inference_df=None)
- Parameters:
att (float)
se (float)
t_stat (float)
p_value (float)
n_obs (int)
n_treated (int)
n_control (int)
alpha (float)
vcov (ndarray | None)
residuals (ndarray | None)
fitted_values (ndarray | None)
r_squared (float | None)
inference_method (str)
n_bootstrap (int | None)
n_clusters (int | None)
p_val_type (str | None)
bootstrap_distribution (ndarray | None)
survey_metadata (Any | None)
vcov_type (str | None)
cluster_name (str | None)
conley_lag_cutoff (int | None)
df_convention (str | None)
inference_df (float | None)
- Return type:
None
MultiPeriodDiDResults#
Results from MultiPeriodDiD event study estimation.
- class diff_diff.MultiPeriodDiDResults[source]
Bases:
BaseResultsResults from a Multi-Period Difference-in-Differences estimation.
Provides access to period-specific treatment effects as well as an aggregate average treatment effect.
- period_effects
Dictionary mapping period identifiers to their PeriodEffect objects. Contains all estimated period effects (pre and post, excluding the reference period which is normalized to zero).
- Type:
dict[any, PeriodEffect]
- avg_att
Average Treatment effect on the Treated across post-periods only.
- Type:
- avg_se
Standard error of the average ATT.
- Type:
- avg_t_stat
T-statistic for the average ATT.
- Type:
- avg_p_value
P-value for the null hypothesis that average ATT = 0.
- Type:
- n_obs
Number of observations used in estimation.
- Type:
- n_treated
Number of treated units/observations.
- Type:
- n_control
Number of control units/observations.
- Type:
- pre_periods
List of pre-treatment period identifiers.
- Type:
- post_periods
List of post-treatment period identifiers.
- Type:
- reference_period
The reference (omitted) period. Its coefficient is zero by construction and it is excluded from
period_effects.- Type:
any, optional
- interaction_indices
Mapping from period identifier to column index in the full variance-covariance matrix. Used internally for sub-VCV extraction (e.g., by HonestDiD and PreTrendsPower).
- Type:
dict, optional
Attributes
attpre_period_effectsPre-period effects only (for parallel trends assessment).
post_period_effectsPost-period effects only.
- period_effects: Dict[Any, PeriodEffect]
- avg_att: float
- avg_se: float
- avg_t_stat: float
- avg_p_value: float
- n_obs: int
- n_treated: int
- n_control: int
- alpha: float = 0.05
- inference_method: str = 'analytical'
- property att: float
- property se: float
- property p_value: float
- property t_stat: float
- property pre_period_effects: Dict[Any, PeriodEffect]
Pre-period effects only (for parallel trends assessment).
- property post_period_effects: Dict[Any, PeriodEffect]
Post-period effects only.
- property coef_var: float
SE / abs(overall ATT). NaN when ATT is 0 or SE non-finite.
- Type:
Coefficient of variation
- summary(alpha=None)[source]
Generate a formatted summary of the estimation results.
- Parameters:
alpha (float, optional) – Accepted for signature uniformity. The stored intervals were computed at fit time; a value different from the stored
alpharaises ValueError rather than silently recomputing or relabeling. Re-fit at the desired alpha instead.- Returns:
Formatted summary table.
- Return type:
- print_summary(alpha=None)[source]
Print the summary to stdout.
- Parameters:
alpha (float | None)
- Return type:
None
- get_effect(period)[source]
Get the treatment effect for a specific period.
- Parameters:
period (any) – The period identifier.
- Returns:
The treatment effect for the specified period.
- Return type:
- Raises:
KeyError – If the period is not found in post-treatment periods.
- to_dict()[source]
Convert results to a dictionary.
- Returns:
Dictionary containing all estimation results.
- Return type:
Dict[str, Any]
- to_dataframe()[source]
Convert period-specific effects to a pandas DataFrame.
- Returns:
DataFrame with one row per estimated period (pre and post).
- Return type:
pd.DataFrame
- property is_significant: bool
Check if the average ATT is statistically significant at the alpha level.
- property significance_stars: str
Return significance stars for the average ATT based on p-value.
- __init__(period_effects, avg_att, avg_se, avg_t_stat, avg_p_value, avg_conf_int, n_obs, n_treated, n_control, pre_periods, post_periods, alpha=0.05, coefficients=None, vcov=None, residuals=None, fitted_values=None, r_squared=None, reference_period=None, interaction_indices=None, survey_metadata=None, inference_method='analytical', n_bootstrap=None, n_clusters=None, vcov_type=None, cluster_name=None, conley_lag_cutoff=None, df_convention=None, inference_df=None, event_study_df=None)
- Parameters:
period_effects (Dict[Any, PeriodEffect])
avg_att (float)
avg_se (float)
avg_t_stat (float)
avg_p_value (float)
n_obs (int)
n_treated (int)
n_control (int)
alpha (float)
vcov (ndarray | None)
residuals (ndarray | None)
fitted_values (ndarray | None)
r_squared (float | None)
reference_period (Any | None)
survey_metadata (Any | None)
inference_method (str)
n_bootstrap (int | None)
n_clusters (int | None)
vcov_type (str | None)
cluster_name (str | None)
conley_lag_cutoff (int | None)
df_convention (str | None)
inference_df (float | None)
- Return type:
None
PeriodEffect#
Container for a single period’s treatment effect in event studies.
- class diff_diff.PeriodEffect[source]
Bases:
objectTreatment effect for a single time period.
- period
The time period identifier.
- Type:
any
- effect
The treatment effect estimate for this period.
- Type:
- se
Standard error of the effect estimate.
- Type:
- t_stat
T-statistic for the effect estimate.
- Type:
- p_value
P-value for the null hypothesis that effect = 0.
- Type:
- period: Any
- effect: float
- se: float
- t_stat: float
- p_value: float
- property is_significant: bool
Check if the effect is statistically significant at 0.05 level.
- property significance_stars: str
Return significance stars based on p-value.
SyntheticDiDResults#
Results from SyntheticDiD estimation.
- class diff_diff.SyntheticDiDResults[source]
Bases:
BaseResultsResults from a Synthetic Difference-in-Differences estimation.
Combines DiD with synthetic control by re-weighting control units to match pre-treatment trends of treated units.
- att
Average Treatment effect on the Treated (ATT).
- Type:
- se
Standard error of the ATT estimate (bootstrap, jackknife, or placebo-based).
- Type:
- t_stat
T-statistic for the ATT estimate.
- Type:
- p_value
P-value for the null hypothesis that ATT = 0.
- Type:
- n_obs
Number of observations used in estimation.
- Type:
- n_treated
Number of treated units/observations.
- Type:
- n_control
Number of control units/observations.
- Type:
- unit_weights
Dictionary mapping control unit IDs to their synthetic weights. When survey weights are used, these are the composed effective weights (omega_eff = raw Frank-Wolfe * survey, renormalized) that were applied to produce the ATT, not the raw Frank-Wolfe solution.
- Type:
- time_weights
Dictionary mapping pre-treatment periods to their time weights.
- Type:
- pre_periods
List of pre-treatment period identifiers.
- Type:
- post_periods
List of post-treatment period identifiers.
- Type:
- variance_method
Method used for variance estimation:
"bootstrap"(paper-faithful pairs bootstrap re-estimating ω and λ via Frank-Wolfe on each draw; Arkhangelsky et al. 2021 Algorithm 2 step 2, and R’s defaultsynthdid::vcov(method="bootstrap")),"jackknife", or"placebo".- Type:
- variance_effects
Method-specific per-iteration estimates: placebo treatment effects (for
"placebo"), bootstrap ATT estimates with re-estimated weights per draw (for"bootstrap"), or leave-one-out estimates (for"jackknife"). Thevariance_methodfield disambiguates the contents. (The deprecated read-only aliasplacebo_effectsreturns this array and is removed in v4.0.0.)- Type:
np.ndarray, optional
- pre_treatment_fit
Shape-only pre-treatment fit: the RMSE of the pre-period residual (treated mean minus synthetic control) after removing its mean. The Frank-Wolfe unit weights are fit on column-centered outcomes, so a constant level gap is not a fit failure (SDID differences it out) and is excluded here. NaN with a single pre-period.
- Type:
float, optional
- pre_treatment_level_gap
Signed mean pre-period gap, treated minus synthetic control. This is the constant offset absorbed by the DiD step; it is reported for inspection and never enters the poor-fit warning.
- Type:
float, optional
- pre_fit_placebo_rmse
Reference distribution for
pre_treatment_fit: the shape-only pre-fit RMSE of each placebo fit in which a random set ofn_treatedcontrol units is treated as if treated and the unit weights are re-estimated on the remaining controls (Algorithm 4 draws, fit-time zeta). At most 20 draws (min(n_bootstrap, 20));Nonewhen no placebo fit is possible (no pseudo-control left, or a single pre-period).- Type:
np.ndarray, optional
- pre_fit_placebo_pvalue
(1 + #{placebo RMSE >= treated RMSE}) / (1 + n_draws): the plus-one-adjusted rank of the treated units’ fit among the placebo fits — a fit diagnostic, not a treatment-effect p-value. The poor-fit warning fires at<= 0.05(in-space placebo fit assessment, Abadie, Diamond & Hainmueller 2010; Abadie 2021), which needs at least 19 successful draws to be reachable.- Type:
float, optional
- synthetic_pre_trajectory
Synthetic control trajectory in pre-treatment periods, shape
(n_pre,). Equal toY_pre_control @ omega_effwhereomega_effis the composed effective weight vector.- Type:
np.ndarray, optional
- synthetic_post_trajectory
Synthetic control trajectory in post-treatment periods, shape
(n_post,).- Type:
np.ndarray, optional
- treated_pre_trajectory
Treated-unit mean trajectory in pre-treatment periods, shape
(n_pre,). Survey-weighted when the fit used survey weights.- Type:
np.ndarray, optional
- treated_post_trajectory
Treated-unit mean trajectory in post-treatment periods, shape
(n_post,).- Type:
np.ndarray, optional
- time_weights_array
The Frank-Wolfe time weights as a 1-D array (same values as the
time_weightsdict but order-stable and usable for re-estimation by sensitivity methods). Shape(n_pre,).- Type:
np.ndarray, optional
Attributes
- att: float
- se: float
- t_stat: float
- p_value: float
- n_obs: int
- n_treated: int
- n_control: int
- alpha: float = 0.05
- variance_method: str = 'placebo'
- __getstate__()[source]
Exclude the internal fit snapshot from pickling.
The snapshot retains outcome matrices, unit IDs, and survey weights to support post-hoc diagnostics (in_time_placebo, sensitivity_to_zeta_omega). Serialization would otherwise carry that panel state to wherever the pickle is sent, which is a privacy hazard for survey-weighted or sensitive fits.
Unpickled results keep the public fields (ATT, weights, trajectories, etc.); calling a diagnostic method that needs the snapshot raises a ValueError directing the user to re-fit.
- __setstate__(state)[source]
Restore from pickle, migrating the legacy field name.
Results pickled before the
placebo_effects→variance_effectsrename (<= 3.5.x) carry the old key in their state; map it so the stored variance draws survive and remain reachable through bothvariance_effectsand the deprecatedplacebo_effectsalias. Remove together with the alias in v4.0.0.
- property coef_var: float
SE / abs(ATT). NaN when ATT is 0 or SE non-finite.
- Type:
Coefficient of variation
- property placebo_effects: ndarray | None
Deprecated alias for
variance_effects(removed in v4.0.0).Deprecated since version 3.5.2: Renamed to
variance_effectsbecause the array’s contents are method-specific (placebo effects, bootstrap ATT draws, or leave-one-out estimates depending onvariance_method).
- summary(alpha=None)[source]
Generate a formatted summary of the estimation results.
- Parameters:
alpha (float, optional) – Accepted for signature uniformity. The stored intervals were computed at fit time; a value different from the stored
alpharaises ValueError rather than silently recomputing or relabeling. Re-fit at the desired alpha instead.- Returns:
Formatted summary table.
- Return type:
- print_summary(alpha=None)[source]
Print the summary to stdout.
- Parameters:
alpha (float | None)
- Return type:
None
- to_dict()[source]
Convert results to a dictionary.
- Returns:
Dictionary containing all estimation results.
- Return type:
Dict[str, Any]
- to_dataframe()[source]
Convert results to a pandas DataFrame.
- Returns:
DataFrame with estimation results.
- Return type:
pd.DataFrame
- get_unit_weights_df()[source]
Get unit weights as a pandas DataFrame.
- Returns:
DataFrame with unit IDs and their weights.
- Return type:
pd.DataFrame
- get_time_weights_df()[source]
Get time weights as a pandas DataFrame.
- Returns:
DataFrame with time periods and their weights.
- Return type:
pd.DataFrame
- get_loo_effects_df()[source]
Per-unit leave-one-out ATT from the jackknife variance pass.
Requires
variance_method='jackknife'(ValueErrorotherwise) and unit-level LOO granularity (NotImplementedErrorfor the full-design survey jackknife path, which uses PSU-level LOO).Available on:
non-survey jackknife fits (classical Arkhangelsky Algorithm 3).
pweight-only survey jackknife fits (Algorithm 3 with post-hoc ω_eff composition; PSU labels in
survey_metadatacome from implicit-PSU metadata but the LOO remains unit-level).
Blocked on:
full-design survey jackknife fits (strata / PSU / FPC set in
SurveyDesign) - the underlying replicates are PSU-levelτ̂_{(h,j)}(Rust & Rao 1996), not unit-level. Seeresult.variance_effectsfor the raw PSU-level replicate array and REGISTRY §SyntheticDiD “Note (survey + jackknife composition)” for the aggregation formula.
The underlying unit-level values come from the jackknife loops in
SyntheticDiD._jackknife_se: control LOO estimates fill the firstn_controlpositions (in the order of the control units seen by fit), then treated LOO estimates fill the nextn_treatedpositions. This method joins those estimates back to user-facing unit identities.att_loois NaN when the fit hit the zero-sum weight guard for that unit (survey weights composed to zero once the unit was dropped).delta_from_fullpropagates NaN in that case.- Returns:
Columns:
unit- user’s unit IDrole-'control'or'treated'att_loo- ATT with this unit droppeddelta_from_full-att_loo - self.att
Sorted by
|delta_from_full|descending, NaN rows at the end.- Return type:
pd.DataFrame
- in_time_placebo(fake_treatment_periods=None, zeta_omega_override=None, zeta_lambda_override=None)[source]
Re-estimate the ATT on shifted fake treatment periods within the original pre-treatment window.
A credible placebo should produce near-zero ATTs at every shifted date. Departures from zero signal that whatever the estimator picked up at the real treatment date is also present pre-treatment, weakening the causal interpretation.
The post-treatment data is never used — only the pre-window is re-sliced. Regularization reuses
self.zeta_omegaandself.zeta_lambdafrom the original fit (Rsynthdidconvention), unless overrides are supplied.- Parameters:
fake_treatment_periods (list, optional) – Explicit pre-period values to test. If
None(default), sweeps every feasible pre-period — every P inpre_periodswhose positionisatisfiesi >= 2(so at least 2 pre-fake periods remain for weight estimation) andi <= n_pre - 1(so at least 1 post-fake period exists). Values not inpre_periodsraise ValueError (a value inpost_periodsis explicitly not a placebo).zeta_omega_override (float, optional) – Override
self.zeta_omegafor the refit. Default reuses the original.zeta_lambda_override (float, optional) – Override
self.zeta_lambdafor the refit.
- Returns:
- Columns:
fake_treatment_period— the shifted dateatt— placebo ATT (ideally near 0)pre_fit_rmse— shape-only RMSE on the fake pre-window (pre-period mean gap removed, matchingpre_treatment_fit)n_pre_fake— periods before the fake daten_post_fake— periods from the fake date onward
NaN is emitted only for dimensional infeasibility. Frank-Wolfe does not expose a mid-solver non-convergence signal; inspect
pre_fit_rmsefor poor refit quality.- Return type:
pd.DataFrame
- sensitivity_to_zeta_omega(zeta_grid=None, multipliers=(0.25, 0.5, 1.0, 2.0, 4.0))[source]
Re-estimate the ATT across a grid of
zeta_omegavalues to show how sensitive the estimate is to the unit-weight regularization.The Frank-Wolfe time weights computed during the original fit are held fixed here — this method isolates sensitivity to
zeta_omegaspecifically.zeta_lambdaand the time weights are not re-fit.- Parameters:
zeta_grid (list of float, optional) – Absolute
zeta_omegavalues to evaluate. IfNone(default), usesmultipliers * self.zeta_omega— i.e. a 5-point grid by default, spanning 16x from the smallest to the largest multiplier and symmetric in log space around 1.0.multipliers (tuple of float, default
(0.25, 0.5, 1.0, 2.0, 4.0)) – Multipliers onself.zeta_omega. Ignored whenzeta_gridis supplied.
- Returns:
- Columns:
zeta_omega— the regularization value evaluatedatt— resulting ATTpre_fit_rmse— shape-only RMSE on the original pre-period (pre-period mean gap removed, matchingpre_treatment_fit; NaN with a single pre-period)max_unit_weight— max element of the composedomega_eff(sensitivity indicator: close to 1 means near-one-hot solutions; close to1/n_controlmeans near-uniform)effective_n—1 / sum(omega_eff**2)
- Return type:
pd.DataFrame
Notes
Extreme
zeta_omega: very small values push weights toward sparse one-hot solutions (few controls dominate); very large values push toward uniform weighting. Thepre_fit_rmsecolumn exposes the tradeoff.
- get_weight_concentration(top_k=5)[source]
Concentration metrics for the control unit weights.
Operates on
self.unit_weights, which for survey-weighted fits stores the composed effective weights (omega_eff = raw_omega * w_control, renormalized to sum to 1) that were applied to produce the ATT. For non-survey fits the values equal the raw Frank-Wolfe solution. Either way, the concentration reflects the distribution actually used by the estimator.- Parameters:
top_k (int, default 5) – Number of largest weights to sum for
top_k_share. Must be non-negative. Clamped to the available number of control units.- Returns:
- Keys:
effective_n—1 / sum(w**2), inverse Herfindahlherfindahl—sum(w**2)top_k_share— sum of thetop_klargest weightstop_k— the (possibly clamped) value used
- Return type:
- Raises:
ValueError – If
top_kis negative.
- property is_significant: bool
Check if the ATT is statistically significant at the alpha level.
- property significance_stars: str
Return significance stars based on p-value.
- __init__(att, se, t_stat, p_value, conf_int, n_obs, n_treated, n_control, unit_weights, time_weights, pre_periods, post_periods, alpha=0.05, variance_method='placebo', noise_level=None, zeta_omega=None, zeta_lambda=None, pre_treatment_fit=None, pre_treatment_level_gap=None, pre_fit_placebo_rmse=None, pre_fit_placebo_pvalue=None, variance_effects=None, n_bootstrap=None, survey_metadata=None, synthetic_pre_trajectory=None, synthetic_post_trajectory=None, treated_pre_trajectory=None, treated_post_trajectory=None, time_weights_array=None)
- Parameters:
att (float)
se (float)
t_stat (float)
p_value (float)
n_obs (int)
n_treated (int)
n_control (int)
alpha (float)
variance_method (str)
noise_level (float | None)
zeta_omega (float | None)
zeta_lambda (float | None)
pre_treatment_fit (float | None)
pre_treatment_level_gap (float | None)
pre_fit_placebo_rmse (ndarray | None)
pre_fit_placebo_pvalue (float | None)
variance_effects (ndarray | None)
n_bootstrap (int | None)
survey_metadata (Any | None)
synthetic_pre_trajectory (ndarray | None)
synthetic_post_trajectory (ndarray | None)
treated_pre_trajectory (ndarray | None)
treated_post_trajectory (ndarray | None)
time_weights_array (ndarray | None)
- Return type:
None
Results-contract foundations#
Shared bases introduced by the 4.0 API-unification program.
BaseResults is the estimator-results base;
Diagnostic marks diagnostic result containers (which carry no
inference row); EventStudyResults is the unified per-event-time
representation.
- class diff_diff.BaseResults[source]
Bases:
objectShared base for ESTIMATOR result containers (spec section 5).
Behaviorally inert in 3.9 - a TRANSITIONAL marker base that makes the results contract checkable and anchors the 4.0 storage flip. It does not yet enforce a uniform runtime protocol: most subclasses are scalar estimator results (one canonical quintet), but
EventStudyResultsis intentionally vector-valued, and a few inherited classes still exposesummary()without analphaargument. Full protocol uniformity (uniformsummary(alpha=None), native canonical storage) is enforced in later Phase 2 / 4.0 PRs. The target contract every ESTIMATOR-results subclass converges to:Canonical quintet.
att,se,t_stat,p_value,conf_intbound to ONE coherent inference row (native fields or property aliases over legacyoverall_*/avg_*storage; the storage flips to native canonical fields at 4.0, ledger rows M-050..M-058, with legacy names living on as FutureWarning properties until 5.0).Serialization.
summary(alpha=None),to_dict()(canonical key names only - deprecated names never leak into serialized output), andto_dataframe(level=...)where multiple views exist.Pickle migration. Classes whose stored field names change ship
__setstate__migration following theSyntheticDiDResults.__setstate__precedent (diff_diff/results.py) so 3.x pickles load under 4.0.Planned estimand self-description hook. The per-class headline semantics (name / definition / aggregation / headline attribute) currently live in
_reporting_helpers.describe_target_parameter, keyed by result-class name. A later PR lifts that block onto this base so results self-describe their target parameter (the MMM exporter’s verified allowlist is the first consumer); nothing here constrains that lift.
Diagnostic result containers (spec section 3.5) do NOT inherit this base - they are marked with
Diagnosticand are exempt from the quintet by type.
- class diff_diff.Diagnostic[source]
Bases:
objectMarker base for diagnostic RESULT containers (spec section 3.5).
diff-diff distinguishes three object kinds: estimators, estimator results, and diagnostics. Exactly one bit is load-bearing: an estimator’s result carries a causal-effect inference row (the canonical quintet
att/se/t_stat/p_value/conf_int); a diagnostic’s result does NOT - it assesses a design, an identifying assumption, or robustness.Marked classes expose
summary()andto_dataframe()and are exempt from the quintet BY TYPE, so consumers route withisinstance(result, Diagnostic)instead of result-class-name special-casing. The contract is enforced by the roster test intests/test_diagnostic_marker.py(ledger row M-091), not by the type system - this class intentionally has no methods.
- class diff_diff.EventStudyResults[source]
Bases:
BaseResultsUnified event-study representation (spec section 5, row M-092).
ONE representation for per-event-time effects across all estimators. Columnar numpy arrays index-aligned to
event_time(theHeterogeneousAdoptionDiDEventStudyResultsprecedent). Values are copied bit-exactly from each estimator’s native surface - never recomputed - except the mandated reference-row normalization (att=0.0, inference NaN).- Parameters:
event_time (np.ndarray) – Sorted estimator-native event-time labels, NEVER renumbered. Relative producers use their own origin (see
event_time_convention); the pre-4.0 MultiPeriodDiD surface is calendar-keyed (time_scale="calendar") and may carry object dtype (str/datetime period labels).att (np.ndarray) – Canonical per-event-time inference columns. On the reference row (if any):
att == 0.0andse/t_stat/p_valueare NaN.se (np.ndarray) – Canonical per-event-time inference columns. On the reference row (if any):
att == 0.0andse/t_stat/p_valueare NaN.t_stat (np.ndarray) – Canonical per-event-time inference columns. On the reference row (if any):
att == 0.0andse/t_stat/p_valueare NaN.p_value (np.ndarray) – Canonical per-event-time inference columns. On the reference row (if any):
att == 0.0andse/t_stat/p_valueare NaN.conf_int_lower (np.ndarray) – Confidence-interval bounds at
alpha(NaN on the reference row).conf_int_upper (np.ndarray) – Confidence-interval bounds at
alpha(NaN on the reference row).is_reference (np.ndarray) – Boolean; the EXPLICIT reference-period marking. This column - not any count sentinel - is the sole consumer-facing signal. Usually one True entry, but MULTIPLE are legal (CallawaySantAnna universal base on a gapped grid carries one per cohort’s positional base), and ZERO when the estimator omits no baseline (e.g. HAD, Wooldridge). Use
reference_periodsfor the general case;reference_periodis the single-reference convenience scalar.n (np.ndarray) – Per-event-time count as float, NaN where the producer records none (and on the reference row - no estimation happened there).
n_kind (str or None) – Semantic of
nfor this producer, drawn from the sharedN_KIND_VOCABULARY:"groups"(a group-level count - cohorts for CallawaySantAnna/SunAbraham, eligible switcher groups per horizon for de Chaisemartin-D’Haultfoeuille withL_max >= 1),"switcher_cells"(dCDH legacyL_max is Nonepath: switching(g, t)cells, where one group may contribute several),"cells"((g, t)cells generally - what CallawaySantAnna’s"group"aggregation counts),"units"(distinct units, as in the overall/simple aggregation),"obs"(observations),"clusters", or None when no count is recorded. Never conflate these units.reference_period (Any or None) – Convenience scalar echo of the marked row’s
event_timelabel when there is EXACTLY ONE reference row; None when there are zero or several. Useis_reference(or thereference_periodsproperty) for the general case - some estimators (CallawaySantAnna universal base on a gapped grid) carry multiple reference-only horizons.time_scale (str) –
"relative"or"calendar".event_time_convention (str or None) – Origin documentation for relative scales:
"e0_first_treated"(e = t - g; first treated period at e=0) or"l1_first_switch"(de Chaisemartin-D’Haultfoeuille: instantaneous effect at l=1, placebos at negative keys). Horizons are documented, not renumbered. (EfficientDiD buckets fractional-period horizons byint(t - g)— see its REGISTRY truncation Note.)vcov (np.ndarray or None) – Full event-study variance-covariance matrix where the RESULT CONTAINER exposes one (e.g. CallawaySantAnna, SunAbraham, MultiPeriodDiD, StackedDiD, and TwoStageDiD’s analytical modes), ordered by
vcov_index. None when the producer records no matrix or when the stored SEs are no longer its diagonal (bootstrap and replicate-weight overrides clear it rather than ship an inconsistent matrix).vcov_index (np.ndarray or None) –
event_timelabels labellingvcov’s rows/columns (explicit ordering for HonestDiD / PreTrendsPower consumption).cband_lower (np.ndarray or None) – Simultaneous confidence-band bounds where computed; None when the producer has none (
to_dataframethen emits NaN columns - the schema never changes).cband_upper (np.ndarray or None) – Simultaneous confidence-band bounds where computed; None when the producer has none (
to_dataframethen emits NaN columns - the schema never changes).cband_crit_value (float or None) – Critical value of the simultaneous band, where computed.
alpha (float) – Significance level of the stored intervals.
source (str or None) – Producing results-class name (provenance).
df (float, np.ndarray, or None) – Per-row inference degrees of freedom:
df[i]is the df ACTUALLY passed tosafe_inferencefor row i’s stored p-value/CI, threaded from the producer. Accepts None (no df exposed -> all-NaN column), a scalar (broadcast to every row - e.g. CallawaySantAnna, whose explicit-survey event study applies ONE conservative df, the minimum per-horizon effective df, to all rows; or de Chaisemartin-D’Haultfoeuille, whose effect and placebo rows share one design df), or a length-n array (per-row producers: StackedDiD and SunAbrahamhc2_bmper-event Bell-McCaffrey df, LPDiD per-horizon cluster df, MultiPeriodDiDhc2_bmper-period df). NaN on any row means normal-theory inference, an undefined df, bootstrap-overridden inference, or a producer that records none; reference rows and rows with NaN p-values are always NaN.base_period (str or None) – Producer provenance: the fit’s base-period regime where the producer has one (CallawaySantAnna vocabulary:
"varying"or"universal"). None when the producer has no such notion. HonestDiD reads this for its universal-base interpretation warning.anticipation (int or None) – Producer provenance: the fit’s anticipation window in periods, where the producer has one. None when the producer has no such notion. PreTrendsPower reads this to exclude anticipation-window rows (
event_time >= -anticipation) from the pre-trend set.df_survey (float or None) – Producer provenance: the fit’s resolved SCALAR inference df, with the established semantics of the fit-time consumers -
survey_metadata.df_surveywhere present (0.0= replicate design with an undefined df, which fails closed to NaN critical values downstream), elsedf_inference(the bare-cluster=carrier), else None (no scalar df notion). Exists beside the per-rowdfcolumn because that column CANNOT encode the replicate-undefined sentinel:__post_init__forces per-row df to NaN wherever the p-value is non-finite.reference_event_times (tuple or None) – Producer provenance: the DISTINCT per-cohort normalization-base event times (CallawaySantAnna
base_period="universal": each cohort’s positional base period minus its cohort, deduplicated, sorted). More than one entry means the coefficients were normalized against DIFFERENT bases (gapped time grid) - and on such grids a cohort’s base can OVERLAP another cohort’s estimated horizon, where NO reference-only row exists to mark it, so this field (notis_reference) is the authoritative common-reference signal. HonestDiD and PreTrendsPower fail closed when it carries more than one entry. None when the producer records no such notion (varying base, non-CS producers, hand-built surfaces).
- event_time: ndarray
- att: ndarray
- se: ndarray
- t_stat: ndarray
- p_value: ndarray
- conf_int_lower: ndarray
- conf_int_upper: ndarray
- is_reference: ndarray
- n: ndarray
- time_scale: str = 'relative'
- alpha: float = 0.05
- estimand: str | None = None
The estimand label for the
attcolumn when the producer’s per-horizon estimand is NOT an ATT - HeterogeneousAdoptionDiD’s per-horizon “WAS”/”WAS_d_lower” (row M-027;_from_hadrelaystarget_parameter). None means the column is an ATT (every other producer), keeping their rendering byte-stable.summary()uses it as the column heading andto_dict()serializes it, so the numbers never silently change meaning. Optional provenance appended last (the M-092 pre-cut amendment convention).
- post_periods: Tuple[Any, ...] | None = None
Calendar-partition provenance (M-092 pre-cut amendment #5, with row M-010): the producer’s AUTHORITATIVE post-treatment period labels. MultiPeriodDiD accepts an ARBITRARY
post_periodssubset (a non-suffix split is legal), and the partition is not recoverable fromevent_time/is_referencepositionally - consumers that need pre/post classification on a calendar surface (HonestDiD, PreTrendsPower, the plotter) read THIS field; pre-periods derive as the complement: non-reference rows whoseevent_timeis not inpost_periods. Threaded by_from_mpd(and the TWFE event-study producer); None from every other builder.
- estimation_spec: str | None = None
TWFE event-study design provenance (M-092 amendment #5, with row M-010):
"within"(unit + time FE) or"pooled"(the MultiPeriodDiD design - treatment-group dummy + period dummies, no unit FE). The two specs differ materially in SEs, so the design must be recoverable from the container. None from every builder (only the TwoWayFixedEffects event-study producer sets it).
- property reference_periods: List[Any]
All reference-row
event_timelabels (JSON-safe scalars).The general accessor for the normalization anchors: one entry for the common single-reference case, several for CallawaySantAnna universal base on a gapped grid, empty when the estimator omits no baseline.
- to_dataframe()[source]
Return the pinned per-event-time table (
EVENT_STUDY_SCHEMA).The column schema is identical for every producer; band columns are NaN-filled when the producer computes no simultaneous band.
- Return type:
- to_dict()[source]
Return a JSON-friendly dict (columns as lists, plus metadata).
Calendar event-time labels (
pandas.Timestamp/Period/datetime) are converted to ISO strings so the result is JSON-serializable; relative-time integer labels pass through.
- summary(alpha=None)[source]
Return a formatted event-study table.
- Parameters:
alpha (float, optional) – Accepted for signature uniformity (spec section 5). The stored confidence columns were computed at fit time; passing a value different from the stored
alpharaises rather than silently recomputing or mislabeling - re-aggregate at the desired level instead.- Return type:
- __init__(event_time, att, se, t_stat, p_value, conf_int_lower, conf_int_upper, is_reference, n, n_kind=None, reference_period=None, time_scale='relative', event_time_convention=None, vcov=None, vcov_index=None, cband_lower=None, cband_upper=None, cband_crit_value=None, alpha=0.05, source=None, df=None, base_period=None, anticipation=None, df_survey=None, reference_event_times=None, estimand=None, post_periods=None, estimation_spec=None)
- Parameters:
event_time (ndarray)
att (ndarray)
se (ndarray)
t_stat (ndarray)
p_value (ndarray)
conf_int_lower (ndarray)
conf_int_upper (ndarray)
is_reference (ndarray)
n (ndarray)
n_kind (str | None)
reference_period (Any | None)
time_scale (str)
event_time_convention (str | None)
vcov (ndarray | None)
vcov_index (ndarray | None)
cband_lower (ndarray | None)
cband_upper (ndarray | None)
cband_crit_value (float | None)
alpha (float)
source (str | None)
base_period (str | None)
anticipation (int | None)
df_survey (float | None)
estimand (str | None)
estimation_spec (str | None)
- Return type:
None
- class diff_diff.AggregationResult[source]
Bases:
BaseResultsOne post-fit aggregation, as a table (spec section 6, row M-122).
Columnar arrays index-aligned to
label. Values are computed by the producing estimator’s aggregation machinery and stored here verbatim - this container never re-derives inference.- Parameters:
level (str) – The aggregation type that produced this table - one of
AGGREGATION_VOCABULARYor a documented per-estimator extra.label (np.ndarray) – Per-row aggregation key: the cohort for
"group", the calendar period for"calendar", the dose for"dose". A single"overall"entry for"simple"; a single"total"entry for"total".target (np.ndarray) – Per-row estimand discriminator, so one container can carry two aligned estimands over the same labels (ContinuousDiD’s ATT(d) and ACRT(d) become 2N rows).
"att"where an estimator has one;"total"on a"total"row - a total incremental outcome over the estimator’s aggregation mass, not an ATT.att (np.ndarray) – The canonical quintet, per row, carrying WHATEVER inference the fit stored - never recomputed. On a bootstrapped fit that usually means the producer’s percentile-bootstrap statistics carried through unchanged; view-relay producers can mix regimes per row where the fit itself did (dCDH’s
L_max >= 2cost-benefit delta keeps analyticalsafe_inferenceeven undern_bootstrap > 0- see the REGISTRY Phase 2 cost-benefit delta SE note).se (np.ndarray) – The canonical quintet, per row, carrying WHATEVER inference the fit stored - never recomputed. On a bootstrapped fit that usually means the producer’s percentile-bootstrap statistics carried through unchanged; view-relay producers can mix regimes per row where the fit itself did (dCDH’s
L_max >= 2cost-benefit delta keeps analyticalsafe_inferenceeven undern_bootstrap > 0- see the REGISTRY Phase 2 cost-benefit delta SE note).t_stat (np.ndarray) – The canonical quintet, per row, carrying WHATEVER inference the fit stored - never recomputed. On a bootstrapped fit that usually means the producer’s percentile-bootstrap statistics carried through unchanged; view-relay producers can mix regimes per row where the fit itself did (dCDH’s
L_max >= 2cost-benefit delta keeps analyticalsafe_inferenceeven undern_bootstrap > 0- see the REGISTRY Phase 2 cost-benefit delta SE note).p_value (np.ndarray) – The canonical quintet, per row, carrying WHATEVER inference the fit stored - never recomputed. On a bootstrapped fit that usually means the producer’s percentile-bootstrap statistics carried through unchanged; view-relay producers can mix regimes per row where the fit itself did (dCDH’s
L_max >= 2cost-benefit delta keeps analyticalsafe_inferenceeven undern_bootstrap > 0- see the REGISTRY Phase 2 cost-benefit delta SE note).conf_int_lower (np.ndarray) – Interval bounds at the fit’s
alpha.conf_int_upper (np.ndarray) – Interval bounds at the fit’s
alpha.n (np.ndarray) – Per-row count as float, NaN where the producer records none. Its SEMANTIC is
n_kind- never assume units.n_kind (str or None) – Semantic of
n, fromN_KIND_VOCABULARY- the SAME closed vocabularyEventStudyResultsdraws on, so a consumer can route onn_kindacross both containers.Nonewhen the producer records no count.weight (np.ndarray or None) – Normalized aggregation mass per row, summing to 1 within one
(level, target)group.Nonewhere no per-row mass exists - CallawaySantAnna’s"group"aggregation weights(g, t)cells equally WITHIN each cohort and has no cross-cohort mass, so inventing one would be a fabricated number. Single-row containers ("simple","total") carryweight=[1.0].df (np.ndarray) – Per-row inference degrees of freedom, NaN where none governed the stored p-value. NaN on percentile-bootstrap rows (no df governs them); a bootstrapped fit’s rows can still carry a finite df where the fit kept analytical inference for that row (the dCDH delta case above).
alpha (float) – Significance level the interval was computed at.
estimator (str or None) – Producing estimator class name, for provenance in
summary().
- level: str
- label: ndarray
- target: ndarray
- att: ndarray
- se: ndarray
- t_stat: ndarray
- p_value: ndarray
- conf_int_lower: ndarray
- conf_int_upper: ndarray
- n: ndarray
- df: ndarray
- alpha: float = 0.05
- to_dataframe()[source]
Return the pinned
AGGREGATION_SCHEMAcolumns, in order.Rows are ordered by
labelwhen the labels are homogeneously sortable, and in producer order otherwise (mixed-type cohort labels cannot be ordered without raising). Heterogeneous-targetcontainers (ContinuousDiD’s att/acrt, row M-025) order by FIRST-APPEARANCE target blocks instead - producer order, NOT lexicographic, which would put"acrt"before"att"- with labels ascending within each block under the same sortability guard.- Return type:
- to_dict()[source]
Canonical-name mapping (deprecated names never leak into output).
- summary(alpha=None)[source]
Human-readable table.
- Parameters:
alpha (float, optional) – Accepted for signature uniformity (spec section 5). The stored interval was computed at aggregation time; passing a value different from the stored
alpharaises rather than silently recomputing or mislabeling it - re-aggregate instead. Mirrorssummary().- Return type:
- __init__(level, label, target, att, se, t_stat, p_value, conf_int_lower, conf_int_upper, n, df, alpha=0.05, n_kind=None, weight=None, estimator=None, _COLUMN_FIELDS=('label', 'target', 'att', 'se', 't_stat', 'p_value', 'conf_int_lower', 'conf_int_upper', 'n', 'df'))
- Parameters:
- Return type:
None