diff_diff.PowerAnalysis#

class diff_diff.PowerAnalysis[source]#

Bases: object

Power analysis for difference-in-differences designs.

Provides analytical power calculations for basic 2x2 DiD and panel DiD designs. For complex designs like staggered adoption, use simulate_power() instead.

Parameters:
  • alpha (float, default=0.05) – Significance level for hypothesis testing.

  • power (float, default=0.80) – Target statistical power.

  • alternative (str, default='two-sided') – Alternative hypothesis: ‘two-sided’, ‘greater’, or ‘less’.

Examples

Calculate minimum detectable effect:

>>> from diff_diff import PowerAnalysis
>>> pa = PowerAnalysis(alpha=0.05, power=0.80)
>>> results = pa.mde(n_treated=50, n_control=50, sigma=1.0)
>>> print(f"MDE: {results.mde:.3f}")

Calculate required sample size:

>>> results = pa.sample_size(effect_size=0.5, sigma=1.0)
>>> print(f"Required N: {results.required_n}")

Calculate power for given sample and effect:

>>> results = pa.power(effect_size=0.5, n_treated=50, n_control=50, sigma=1.0)
>>> print(f"Power: {results.power:.1%}")

Notes

The power calculations are based on the variance of the DiD estimator.

Critical values use the normal (z) distribution following Bloom (1995): MDE = (z_{1-alpha/2} + z_{1-kappa}) * SE. This is a large-sample approximation to Burlig et al.’s t-based multiplier (their Eq. 1) and is mildly anti-conservative for very small numbers of units.

The variance is the within-unit equicorrelated special case of Burlig, Preonas & Woerman (2020), Eq. 2 (psi^B = psi^A = psi^X = rho * sigma^2), for m = n_pre pre-periods and r = n_post post-periods:

Var(ATT) = sigma^2 * (1/N_treated + 1/N_control) * (1/m + 1/r) * (1 - rho)

where rho is the within-unit (serial) equicorrelation. Cross-period correlation lowers the DiD variance (differencing cancels the shared within-unit component), so the MDE decreases as rho increases – the opposite of a Moulton mean-inflation factor.

The basic 2x2 design (n_pre = n_post = 1) is the m = r = 1 special case (Burlig footnote 11), Var(ATT) = 2 * sigma^2 * (1/N_treated + 1/N_control) * (1 - rho), reducing to Bloom (1995) Eq. 1’s DiD analog at rho = 0.

The fully general serial-correlation-robust form (independent psi^B, psi^A, psi^X) is not implemented; see docs/methodology/REGISTRY.md ## PowerAnalysis and the source audits under docs/methodology/papers/.

References

Bloom, H. S. (1995). “Minimum Detectable Effects.” Burlig, F., Preonas, L., & Woerman, M. (2020). “Panel Data and Experimental Design.”

Methods

__init__([alpha, power, alternative])

mde(n_treated, n_control, sigma[, n_pre, ...])

Calculate minimum detectable effect given sample size.

power(effect_size, n_treated, n_control, sigma)

Calculate statistical power for given effect size and sample.

power_curve(n_treated, n_control, sigma[, ...])

Compute power for a range of effect sizes.

sample_size(effect_size, sigma[, n_pre, ...])

Calculate required sample size to detect given effect.

sample_size_curve(effect_size, sigma[, ...])

Compute power for a range of sample sizes.

__init__(alpha=0.05, power=0.8, alternative='two-sided')[source]#
Parameters:
classmethod __new__(*args, **kwargs)#