This guide compares diff-diff with other Python packages for DiD analysis, helping users understand the landscape and choose the right tool.
| Feature | diff-diff | pyfixest | differences | CausalPy | linearmodels |
|---|---|---|---|---|---|
| Basic DiD | ✅ | ✅ | ✅ | ✅ | ✅ (manual) |
| TWFE | ✅ | ✅ | ❌ | ❌ | ✅ |
| Callaway-Sant'Anna | ✅ | ❌ | ✅ | ❌ | ❌ |
| Sun-Abraham | ✅ | ✅ | ❌ | ❌ | ❌ |
| Synthetic DiD | ✅ | ❌ | ❌ | ✅ (SC only) | ❌ |
| Honest DiD | ✅ | ❌ | ❌ | ❌ | ❌ |
| Wild bootstrap | ✅ | ✅ | ❌ | ❌ | ❌ |
pyfixest is inspired by R's
fixest package and excels at fast fixed effects estimation.
Strengths:
- Very fast for high-dimensional fixed effects (JIT-compiled)
- Sun-Abraham event study estimator
- Gardner's did2s two-stage estimator
- Local projections (Dube et al. 2023)
- Publication-ready tables
Gaps:
- No Callaway-Sant'Anna estimator
- No sensitivity analysis (Honest DiD)
- No synthetic DiD
differences provides a pure Callaway-Sant'Anna implementation.
Strengths:
- Faithful implementation of Callaway & Sant'Anna (2021)
- Multi-valued treatment support
- Triple difference estimation
- Handles unbalanced panels
Gaps:
- No sensitivity analysis
- No synthetic DiD
- Limited inference options (no wild bootstrap)
CausalPy takes a Bayesian approach using PyMC for uncertainty quantification.
Strengths:
- Bayesian credible intervals
- Synthetic control methods
- Nice built-in visualizations
- Interrupted time series
Gaps:
- Limited to simple 2x2 DiD designs
- No staggered treatment support
- No event study methods
linearmodels provides panel data econometrics, serving as a building block for DiD.
Strengths:
- Solid PanelOLS implementation
- Two-way fixed effects
- Various standard error options
- statsmodels-compatible
Gaps:
- No DiD-specific methods (manual implementation required)
- No staggered treatment handling
- No diagnostics or sensitivity analysis
diff-diff fills critical gaps in the Python DiD ecosystem:
Only Python library with Honest DiD sensitivity analysis
Reviewers increasingly expect sensitivity analysis showing robustness to parallel trends violations. diff-diff is the only Python package implementing Rambachan & Roth (2023).
Unified toolkit
Combines Callaway-Sant'Anna, Synthetic DiD, TWFE, and Honest DiD in one package with a consistent API.
Built-in diagnostics
Placebo tests, parallel trends tests, Goodman-Bacon decomposition, and sensitivity analysis out of the box.
sklearn-style API
Familiar
fit()interface with rich result objects.
| Feature | diff-diff | pyfixest | differences | CausalPy | linearmodels |
|---|---|---|---|---|---|
| Basic 2x2 DiD | ✅ | ✅ | ✅ | ✅ | ✅ |
| Two-way fixed effects | ✅ | ✅ | ❌ | ❌ | ✅ |
| Staggered DiD (CS) | ✅ | ❌ | ✅ | ❌ | ❌ |
| Sun-Abraham estimator | ✅ | ✅ | ❌ | ❌ | ❌ |
| Gardner's did2s | ✅ | ✅ | ❌ | ❌ | ❌ |
| Local projections | ❌ | ✅ | ❌ | ❌ | ❌ |
| Synthetic DiD | ✅ | ❌ | ❌ | ❌ | ❌ |
| Synthetic control | ❌ | ❌ | ❌ | ✅ | ❌ |
| Covariate adjustment | ✅ | ✅ | ✅ | Limited | ✅ |
| Doubly robust | ✅ | ❌ | ✅ | ❌ | ❌ |
| IPW | ✅ | ❌ | ✅ | ❌ | ❌ |
| Group-time effects | ✅ | ❌ | ✅ | ❌ | ❌ |
| Event study aggregation | ✅ | ✅ | ✅ | ❌ | ❌ |
| Honest DiD (ΔRM) | ✅ | ❌ | ❌ | ❌ | ❌ |
| Honest DiD (ΔSD) | ✅ | ❌ | ❌ | ❌ | ❌ |
| Sensitivity analysis | ✅ | ❌ | ❌ | ❌ | ❌ |
| Wild bootstrap | ✅ | ✅ | ❌ | ❌ | ❌ |
| Cluster-robust SE | ✅ | ✅ | ✅ | ❌ | ✅ |
| Placebo tests | ✅ | ❌ | ❌ | ❌ | ❌ |
| Parallel trends tests | ✅ | ❌ | ❌ | ❌ | ❌ |
| Bacon decomposition | ✅ | ❌ | ❌ | ❌ | ❌ |
| Event study plots | ✅ | ✅ | ✅ | ✅ | ❌ |
| Triple Difference (DDD) | ✅ | ❌ | ✅ | ❌ | ❌ |
| TROP | ✅ | ❌ | ❌ | ❌ | ❌ |
| Stacked DiD | ✅ | ❌ | ❌ | ❌ | ❌ |
| Bacon Decomposition | ✅ | ❌ | ❌ | ❌ | ❌ |
| Continuous DiD | ✅ | ❌ | ❌ | ❌ | ❌ |
| Efficient DiD | ✅ | ❌ | ❌ | ❌ | ❌ |
| Built-in datasets | ✅ | ❌ | ❌ | ❌ | ❌ |
| Bayesian inference | ❌ | ❌ | ❌ | ✅ | ❌ |
# diff-diff
from diff_diff import DifferenceInDifferences
did = DifferenceInDifferences()
results = did.fit(data, outcome='y', treatment='treated', time='post')
print(results.summary())# pyfixest
import pyfixest as pf
fit = pf.feols("y ~ treated:post | unit + time", data=data)
fit.summary()# linearmodels
from linearmodels.panel import PanelOLS
mod = PanelOLS.from_formula(
'y ~ treated:post + EntityEffects + TimeEffects',
data=data.set_index(['unit', 'time'])
)
results = mod.fit(cov_type='clustered', cluster_entity=True)# diff-diff
from diff_diff import CallawaySantAnna
cs = CallawaySantAnna(estimation_method='dr')
results = cs.fit(
data,
outcome='y',
unit='unit',
time='time',
first_treat='first_treat',
covariates=['x1', 'x2'],
aggregate='event_study'
)
event_study = results.event_study_effects# differences
from differences import ATTgt
att = ATTgt(
data=data,
outcome='y',
cohort='first_treat',
time='time',
strata='unit'
)
att.fit()
att.aggregate('event')# diff-diff (only Python option)
from diff_diff import HonestDiD, plot_sensitivity
honest = HonestDiD(method='relative_magnitude', M=1.0)
results = honest.fit(event_study_results)
# Sensitivity over M grid
sensitivity = honest.sensitivity_analysis(
event_study_results,
M_grid=[0, 0.5, 1.0, 1.5, 2.0]
)
plot_sensitivity(sensitivity)
# No equivalent in other Python packagesUse diff-diff when:
- You need sensitivity analysis (Honest DiD)
- You want Callaway-Sant'Anna with doubly robust estimation
- You need built-in diagnostics (placebo tests, parallel trends)
- You prefer a unified sklearn-style API
Use pyfixest when:
- Speed is critical (high-dimensional fixed effects)
- You need Sun-Abraham or did2s estimators
- You want R's fixest-style syntax
- You need local projections
Use differences when:
- You need multi-valued treatment effects
- You need triple difference estimation
- You want the most faithful CS implementation
Use CausalPy when:
- You want Bayesian uncertainty quantification
- You're doing synthetic control (not synthetic DiD)
- You prefer PyMC-based modeling
Use linearmodels when:
- You're doing general panel econometrics beyond DiD
- You need statsmodels compatibility
- You're implementing DiD manually with full control