diff_diff.PreTrendsPower#

class diff_diff.PreTrendsPower[source]#

Bases: object

Pre-trends power analysis (Roth 2022).

Computes the power of pre-trends tests to detect violations of parallel trends, and the minimum detectable violation (MDV).

Parameters:
  • alpha (float, default=0.05) – Significance level for the pre-trends test.

  • power (float, default=0.80) – Target power level for MDV calculation.

  • violation_type (str, default='linear') – Type of violation pattern to consider: - ‘linear’: Violations follow a linear trend (most common) - ‘constant’: Same violation in all pre-periods - ‘last_period’: Violation only in the last pre-period - ‘custom’: User-specified violation pattern (via violation_weights)

  • violation_weights (array-like, optional) – Custom weights for violation pattern. Length must equal number of pre-periods. Only used when violation_type=’custom’.

  • pretest_form ({'nis', 'wald'}, default='nis') –

    Pre-trends test acceptance-region form:

    • 'nis': Roth (2022) no-individually-significant pretest (Section II.A-B). Acceptance region is B_NIS(Σ) = { b : |b_t| <= z_{1-α/2} σ_t for all t }. Power computed via multivariate normal box probability. This is the new default (PR-B 2026-05-17), matching both the paper’s primary analysis and the R pretrends package.

    • 'wald': Noncentral chi-squared on the quadratic form δ' Σ_22^{-1} δ (the shipped behavior prior to PR-B 2026-05-17). Retained as a paper-supported alternative under Propositions 1+3+4 (Wald acceptance region is a convex ellipsoid, so all four propositions apply). Use this for backwards-compat with shipped numerical baselines.

Examples

Basic usage with MultiPeriodDiD results:

>>> from diff_diff import MultiPeriodDiD
>>> from diff_diff.pretrends import PreTrendsPower
>>>
>>> # Fit event study
>>> mp_did = MultiPeriodDiD()
>>> results = mp_did.fit(data, outcome='y', treatment='treated',
...                      time='period', post_periods=[4, 5, 6, 7])
>>>
>>> # Analyze pre-trends power
>>> pt = PreTrendsPower(alpha=0.05, power=0.80)
>>> power_results = pt.fit(results)
>>> print(power_results.summary())
>>>
>>> # Get power curve
>>> curve = pt.power_curve(results)
>>> curve.plot()

Notes

The pre-trends test is typically a joint test that all pre-period coefficients are zero. This test has limited power to detect small violations, especially when:

  1. There are few pre-periods

  2. Standard errors are large

  3. The violation pattern is smooth (e.g., linear trend)

Passing a pre-trends test does NOT mean parallel trends holds. It means violations smaller than the MDV cannot be ruled out. For robust inference, combine with HonestDiD sensitivity analysis.

References

Roth, J. (2022). Pretest with Caution: Event-Study Estimates after Testing

for Parallel Trends. American Economic Review: Insights, 4(3), 305-322.

Methods

__init__([alpha, power, violation_type, ...])

fit(results[, M, pre_periods])

Compute pre-trends power analysis.

get_params()

Get parameters for this estimator.

power_at(results, M[, pre_periods])

Compute power to detect a specific violation magnitude.

power_curve(results[, M_grid, n_points, ...])

Compute power across a range of violation magnitudes.

sensitivity_to_honest_did(results[, pre_periods])

Compare pre-trends power analysis with HonestDiD sensitivity.

set_params(**params)

Set parameters for this estimator.

__init__(alpha=0.05, power=0.8, violation_type='linear', violation_weights=None, pretest_form='nis')[source]#
Parameters:
  • alpha (float)

  • power (float)

  • violation_type (Literal['linear', 'constant', 'last_period', 'custom'])

  • violation_weights (ndarray | None)

  • pretest_form (Literal['nis', 'wald'])

classmethod __new__(*args, **kwargs)#