Skip to content

Commit 40ff236

Browse files
authored
Merge pull request #28 from igerber/claude/prepare-0.6.0-release-V6fGP
Prepare 0.6.0 release
2 parents 0c3fdbb + c3e5b03 commit 40ff236

21 files changed

Lines changed: 303 additions & 196 deletions

CHANGELOG.md

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [0.6.0] - 2025-01-04
9+
10+
### Added
11+
- **CallawaySantAnna covariate adjustment** for conditional parallel trends
12+
- Outcome regression (`estimation_method='reg'`)
13+
- Inverse probability weighting (`estimation_method='ipw'`)
14+
- Doubly robust estimation (`estimation_method='dr'`)
15+
- Pass covariates via `covariates` parameter in `fit()`
16+
- **Honest DiD sensitivity analysis** (Rambachan & Roth 2023)
17+
- `HonestDiD` class for computing bounds under parallel trends violations
18+
- Relative magnitudes restriction (`DeltaRM`) - bounds post-treatment violations by pre-treatment
19+
- Smoothness restriction (`DeltaSD`) - bounds second differences of trend violations
20+
- Combined restrictions (`DeltaSDRM`)
21+
- FLCI and C-LF confidence interval methods
22+
- Breakdown value computation via `breakdown_value()`
23+
- Sensitivity analysis over M grid via `sensitivity_analysis()`
24+
- `HonestDiDResults` and `SensitivityResults` dataclasses
25+
- `compute_honest_did()` convenience function
26+
- `plot_sensitivity()` for sensitivity analysis visualization
27+
- `plot_honest_event_study()` for event study with honest CIs
28+
- Tutorial notebook: `docs/tutorials/05_honest_did.ipynb`
29+
- **API documentation site** with Sphinx
30+
- Full API reference auto-generated from docstrings
31+
- "Which estimator should I use?" decision guide
32+
- Comparison with R packages (did, HonestDiD)
33+
- Getting started / quickstart guide
34+
35+
### Changed
36+
- Updated mypy configuration for better numpy type compatibility
37+
- Modernized ruff configuration to use `[tool.ruff.lint]` section
38+
39+
### Fixed
40+
- Fixed 21 ruff linting issues (import ordering, unused variables, ambiguous names)
41+
- Fixed 94 mypy type checking issues (Optional types, numpy type casts, assertions)
42+
- Added missing return statement in `run_placebo_test()`
43+
44+
## [0.5.0] - 2024-12-01
45+
46+
### Added
47+
- **Wild cluster bootstrap** for valid inference with few clusters
48+
- Rademacher weights (default, good for most cases)
49+
- Webb's 6-point distribution (recommended for <10 clusters)
50+
- Mammen's two-point distribution
51+
- `WildBootstrapResults` dataclass
52+
- `wild_bootstrap_se()` utility function
53+
- Integration with `DifferenceInDifferences` and `TwoWayFixedEffects` via `inference='wild_bootstrap'`
54+
- **Placebo tests module** (`diff_diff.diagnostics`)
55+
- `placebo_timing_test()` - fake treatment timing test
56+
- `placebo_group_test()` - fake treatment group test
57+
- `permutation_test()` - permutation-based inference
58+
- `leave_one_out_test()` - sensitivity to individual treated units
59+
- `run_placebo_test()` - unified dispatcher for all test types
60+
- `run_all_placebo_tests()` - comprehensive diagnostic suite
61+
- `PlaceboTestResults` dataclass
62+
- **Tutorial notebooks** in `docs/tutorials/`
63+
- `01_basic_did.ipynb` - Basic 2x2 DiD, formula interface, covariates, fixed effects, wild bootstrap
64+
- `02_staggered_did.ipynb` - Staggered adoption with Callaway-Sant'Anna
65+
- `03_synthetic_did.ipynb` - Synthetic DiD with unit/time weights
66+
- `04_parallel_trends.ipynb` - Parallel trends testing and diagnostics
67+
- Comprehensive test coverage (380+ tests)
68+
69+
## [0.4.0] - 2024-11-01
70+
71+
### Added
72+
- **Callaway-Sant'Anna estimator** for staggered difference-in-differences
73+
- `CallawaySantAnna` class with group-time ATT(g,t) estimation
74+
- Support for `never_treated` and `not_yet_treated` control groups
75+
- Aggregation methods: `simple`, `group`, `calendar`, `event_study`
76+
- `CallawaySantAnnaResults` with group-time effects and aggregations
77+
- `GroupTimeEffect` dataclass for individual effects
78+
- **Event study visualization** via `plot_event_study()`
79+
- Works with `MultiPeriodDiDResults`, `CallawaySantAnnaResults`, or DataFrames
80+
- Publication-ready formatting with customization options
81+
- **Group effects visualization** via `plot_group_effects()`
82+
- **Parallel trends testing utilities**
83+
- `check_parallel_trends()` - simple slope-based test
84+
- `check_parallel_trends_robust()` - Wasserstein distance test
85+
- `equivalence_test_trends()` - TOST equivalence test
86+
87+
## [0.3.0] - 2024-10-01
88+
89+
### Added
90+
- **Synthetic Difference-in-Differences** (`SyntheticDiD`)
91+
- Unit weight optimization for synthetic control
92+
- Time weight computation for pre-treatment periods
93+
- Placebo-based and bootstrap inference
94+
- `SyntheticDiDResults` with weight accessors
95+
- **Multi-period DiD** (`MultiPeriodDiD`)
96+
- Event-study style estimation with period-specific effects
97+
- `MultiPeriodDiDResults` with `period_effects` dictionary
98+
- `PeriodEffect` dataclass for individual period results
99+
- **Data preparation utilities** (`diff_diff.prep`)
100+
- `generate_did_data()` - synthetic data generation
101+
- `make_treatment_indicator()` - create treatment from categorical/numeric
102+
- `make_post_indicator()` - create post-treatment indicator
103+
- `wide_to_long()` - reshape wide to long format
104+
- `balance_panel()` - ensure balanced panel data
105+
- `validate_did_data()` - data validation
106+
- `summarize_did_data()` - summary statistics by group
107+
- `create_event_time()` - event time for staggered designs
108+
- `aggregate_to_cohorts()` - aggregate to cohort means
109+
- `rank_control_units()` - rank controls by similarity
110+
111+
## [0.2.0] - 2024-09-01
112+
113+
### Added
114+
- **Two-Way Fixed Effects** (`TwoWayFixedEffects`)
115+
- Within-transformation for unit and time fixed effects
116+
- Efficient handling of high-dimensional fixed effects via `absorb`
117+
- **Fixed effects support** in base `DifferenceInDifferences`
118+
- `fixed_effects` parameter for dummy variable approach
119+
- `absorb` parameter for within-transformation approach
120+
- **Cluster-robust standard errors**
121+
- `cluster` parameter for cluster-robust inference
122+
- **Formula interface**
123+
- R-style formulas like `"outcome ~ treated * post"`
124+
- Support for covariates in formulas
125+
126+
## [0.1.0] - 2024-08-01
127+
128+
### Added
129+
- Initial release
130+
- **Basic Difference-in-Differences** (`DifferenceInDifferences`)
131+
- sklearn-like API with `fit()` method
132+
- Column name interface for outcome, treatment, time
133+
- Heteroskedasticity-robust (HC1) standard errors
134+
- `DiDResults` dataclass with ATT, SE, p-value, confidence intervals
135+
- `summary()` and `print_summary()` methods
136+
- `to_dict()` and `to_dataframe()` export methods
137+
- `is_significant` and `significance_stars` properties
138+
139+
[0.6.0]: https://github.com/igerber/diff-diff/compare/v0.5.0...v0.6.0
140+
[0.5.0]: https://github.com/igerber/diff-diff/compare/v0.4.0...v0.5.0
141+
[0.4.0]: https://github.com/igerber/diff-diff/compare/v0.3.0...v0.4.0
142+
[0.3.0]: https://github.com/igerber/diff-diff/compare/v0.2.0...v0.3.0
143+
[0.2.0]: https://github.com/igerber/diff-diff/compare/v0.1.0...v0.2.0
144+
[0.1.0]: https://github.com/igerber/diff-diff/releases/tag/v0.1.0

README.md

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -698,14 +698,31 @@ CallawaySantAnna(
698698
estimation_method='dr', # 'dr', 'ipw', or 'reg'
699699
alpha=0.05, # Significance level
700700
cluster=None, # Column for cluster SEs
701-
n_bootstrap=0, # Must be 0 (bootstrap not yet implemented)
701+
n_bootstrap=0, # Bootstrap iterations (0 = analytical SEs)
702702
seed=None # Random seed
703703
)
704704
```
705705

706+
**Covariate adjustment for conditional parallel trends:**
707+
708+
When parallel trends only holds conditional on covariates, use the `covariates` parameter:
709+
710+
```python
711+
# Doubly robust estimation with covariates
712+
cs = CallawaySantAnna(estimation_method='dr') # 'dr', 'ipw', or 'reg'
713+
results = cs.fit(
714+
data,
715+
outcome='sales',
716+
unit='firm_id',
717+
time='year',
718+
first_treat='first_treat',
719+
covariates=['size', 'age', 'industry'], # Covariates for conditional PT
720+
aggregate='event_study'
721+
)
722+
```
723+
706724
**Current limitations:**
707-
- Bootstrap inference (`n_bootstrap > 0`) is not yet implemented
708-
- Covariate adjustment for conditional parallel trends is not yet implemented
725+
- Bootstrap inference (`n_bootstrap > 0`) is not yet fully implemented
709726

710727
### Event Study Visualization
711728

TODO.md

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,16 @@ Beyond the API site:
267267

268268
## Completed Features
269269

270-
### v0.5.2
270+
### v0.6.0
271+
- [x] **All 1.0 Blockers Complete** - Library is now production-ready for core DiD analysis
272+
- [x] **API Documentation Site** (Sphinx + ReadTheDocs theme)
273+
- Full API reference auto-generated from docstrings
274+
- "Which estimator should I use?" decision guide
275+
- Comparison with R packages
276+
- Getting started / quickstart guide
277+
- [x] **CallawaySantAnna Covariate Adjustment**
278+
- Outcome regression, IPW, and doubly robust methods
279+
- Conditional parallel trends support
271280
- [x] **Honest DiD sensitivity analysis** (Rambachan & Roth 2023)
272281
- Relative magnitudes (ΔRM) and smoothness (ΔSD) restrictions
273282
- Combined restrictions (ΔSDRM)
@@ -276,22 +285,18 @@ Beyond the API site:
276285
- Sensitivity analysis over M grid
277286
- `plot_sensitivity()` and `plot_honest_event_study()` visualization
278287
- HonestDiD, HonestDiDResults, SensitivityResults classes
279-
- DeltaSD, DeltaRM, DeltaSDRM restriction classes
280288
- Tutorial notebook: `05_honest_did.ipynb`
281-
- 49 comprehensive tests
282289

283-
### v0.5.1
284-
- [x] Comprehensive test coverage for `utils.py` module (72 tests)
290+
### v0.5.0
291+
- [x] Wild cluster bootstrap (Rademacher, Webb, Mammen weights)
292+
- [x] Placebo tests module (fake timing, fake group, permutation, leave-one-out)
293+
- [x] Comprehensive test coverage (380+ tests)
285294
- [x] Tutorial notebooks in `docs/tutorials/`
286295
- Basic DiD, formula interface, covariates, fixed effects, wild bootstrap
287296
- Staggered adoption with Callaway-Sant'Anna
288297
- Synthetic DiD with unit/time weights
289298
- Parallel trends testing and diagnostics
290299

291-
### v0.5.0
292-
- [x] Wild cluster bootstrap (Rademacher, Webb, Mammen weights)
293-
- [x] Placebo tests module (fake timing, fake group, permutation, leave-one-out)
294-
295300
### v0.4.0
296301
- [x] Callaway-Sant'Anna estimator for staggered DiD
297302
- [x] Event study visualization
@@ -308,4 +313,4 @@ Beyond the API site:
308313
4. **Goodman-Bacon Decomposition** - Key diagnostic for TWFE users
309314
5. **Power Analysis** - Study design tool practitioners need
310315

311-
With items 1-2 complete, diff-diff now has feature parity with R's `did` + `HonestDiD` ecosystem for core sensitivity analysis. The remaining items (3-5) will complete the 1.0 release.
316+
All 1.0 blockers (items 1-3) are now complete. diff-diff has feature parity with R's `did` + `HonestDiD` ecosystem for core DiD analysis. Items 4-5 would strengthen the 1.0 release but are not strictly required.

diff_diff/__init__.py

Lines changed: 42 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,69 +5,69 @@
55
using the difference-in-differences methodology.
66
"""
77

8+
from diff_diff.diagnostics import (
9+
PlaceboTestResults,
10+
leave_one_out_test,
11+
permutation_test,
12+
placebo_group_test,
13+
placebo_timing_test,
14+
run_all_placebo_tests,
15+
run_placebo_test,
16+
)
817
from diff_diff.estimators import (
918
DifferenceInDifferences,
10-
TwoWayFixedEffects,
1119
MultiPeriodDiD,
1220
SyntheticDiD,
21+
TwoWayFixedEffects,
1322
)
14-
from diff_diff.staggered import (
15-
CallawaySantAnna,
16-
CallawaySantAnnaResults,
17-
GroupTimeEffect,
23+
from diff_diff.honest_did import (
24+
DeltaRM,
25+
DeltaSD,
26+
DeltaSDRM,
27+
HonestDiD,
28+
HonestDiDResults,
29+
SensitivityResults,
30+
compute_honest_did,
31+
sensitivity_plot,
32+
)
33+
from diff_diff.prep import (
34+
aggregate_to_cohorts,
35+
balance_panel,
36+
create_event_time,
37+
generate_did_data,
38+
make_post_indicator,
39+
make_treatment_indicator,
40+
rank_control_units,
41+
summarize_did_data,
42+
validate_did_data,
43+
wide_to_long,
1844
)
1945
from diff_diff.results import (
2046
DiDResults,
2147
MultiPeriodDiDResults,
2248
PeriodEffect,
2349
SyntheticDiDResults,
2450
)
25-
from diff_diff.visualization import (
26-
plot_event_study,
27-
plot_group_effects,
28-
plot_sensitivity,
29-
plot_honest_event_study,
30-
)
31-
from diff_diff.prep import (
32-
make_treatment_indicator,
33-
make_post_indicator,
34-
wide_to_long,
35-
balance_panel,
36-
validate_did_data,
37-
summarize_did_data,
38-
generate_did_data,
39-
create_event_time,
40-
aggregate_to_cohorts,
41-
rank_control_units,
51+
from diff_diff.staggered import (
52+
CallawaySantAnna,
53+
CallawaySantAnnaResults,
54+
GroupTimeEffect,
4255
)
4356
from diff_diff.utils import (
57+
WildBootstrapResults,
4458
check_parallel_trends,
4559
check_parallel_trends_robust,
4660
equivalence_test_trends,
47-
WildBootstrapResults,
4861
wild_bootstrap_se,
4962
)
50-
from diff_diff.diagnostics import (
51-
PlaceboTestResults,
52-
run_placebo_test,
53-
placebo_timing_test,
54-
placebo_group_test,
55-
permutation_test,
56-
leave_one_out_test,
57-
run_all_placebo_tests,
58-
)
59-
from diff_diff.honest_did import (
60-
HonestDiD,
61-
HonestDiDResults,
62-
SensitivityResults,
63-
DeltaSD,
64-
DeltaRM,
65-
DeltaSDRM,
66-
compute_honest_did,
67-
sensitivity_plot,
63+
from diff_diff.visualization import (
64+
plot_event_study,
65+
plot_group_effects,
66+
plot_honest_event_study,
67+
plot_sensitivity,
6868
)
6969

70-
__version__ = "0.5.0"
70+
__version__ = "0.6.0"
7171
__all__ = [
7272
# Estimators
7373
"DifferenceInDifferences",

diff_diff/diagnostics.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,9 @@ def run_placebo_test(
360360
**estimator_kwargs
361361
)
362362

363+
# This should never be reached due to validation above
364+
raise ValueError(f"Unknown test type: {test_type}")
365+
363366

364367
def placebo_timing_test(
365368
data: pd.DataFrame,

0 commit comments

Comments
 (0)