Skip to content

Commit 5c5b6fa

Browse files
authored
Merge pull request #281 from igerber/release-v3.0
v3.0.0: Deprecation removals, version bump, docs refresh
2 parents a703f4e + d598fed commit 5c5b6fa

23 files changed

Lines changed: 1065 additions & 270 deletions

CHANGELOG.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [3.0.0] - 2026-04-07
11+
12+
v3.0 completes the survey support roadmap: all 16 estimators (15 inference-level +
13+
BaconDecomposition diagnostic) now accept `survey_design`. See v2.8.0–v2.9.1 entries
14+
for the full feature history leading to this release.
15+
16+
### Breaking Changes
17+
- **Remove `bootstrap_weight_type` parameter** from CallawaySantAnna — use `bootstrap_weights` instead (deprecated since v1.0.1)
18+
- **Remove TROP `method="twostep"` alias** — use `method="local"` (deprecated since v2.7.2)
19+
- **Remove TROP `method="joint"` alias** — use `method="global"` (deprecated since v2.7.2)
20+
21+
### Upgrading from v2.x
22+
- `CallawaySantAnna(bootstrap_weight_type="mammen")``CallawaySantAnna(bootstrap_weights="mammen")`
23+
- `TROP(method="twostep")``TROP(method="local")`
24+
- `TROP(method="joint")``TROP(method="global")`
25+
26+
### Deprecated
27+
- SyntheticDiD `lambda_reg` and `zeta` parameters formally scheduled for removal in v3.1 — use `zeta_omega`/`zeta_lambda` instead
28+
29+
### Changed
30+
- Internal attribute `bootstrap_weight_type` renamed to `bootstrap_weights` in bootstrap mixin and StaggeredTripleDifference for consistency
31+
- TROP `set_params()` now validates `method` against `("local", "global")` — previously only validated in `__init__`
32+
- Documentation updated: all survey gap notes for WooldridgeDiD removed, ROADMAP Phase 10 items marked shipped
33+
1034
## [2.9.1] - 2026-04-06
1135

1236
### Added

ROADMAP.md

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ For past changes and release history, see [CHANGELOG.md](CHANGELOG.md).
66

77
---
88

9-
## Current Status (v2.9.0)
9+
## Current Status (v3.0)
1010

1111
diff-diff is a **production-ready** DiD library with feature parity with R's `did` + `HonestDiD` + `synthdid` ecosystem for core DiD analysis, plus **unique survey support** that no R or Python package matches.
1212

@@ -28,19 +28,17 @@ diff-diff is a **production-ready** DiD library with feature parity with R's `di
2828

2929
### Survey Support
3030

31-
`SurveyDesign` with strata, PSU, FPC, weight types (pweight/fweight/aweight), lonely PSU handling. 15 of 16 estimators accept `survey_design` (WooldridgeDiD support planned for Phase 10f); design-based variance estimation varies by estimator:
31+
`SurveyDesign` with strata, PSU, FPC, weight types (pweight/fweight/aweight), lonely PSU handling. All 16 estimators accept `survey_design` (15 inference-level + BaconDecomposition diagnostic); design-based variance estimation varies by estimator:
3232

3333
- **TSL variance** (Taylor Series Linearization) with strata + PSU + FPC
34-
- **Replicate weights**: BRR, Fay's BRR, JK1, JKn, SDR — 12 of 16 estimators (not SyntheticDiD, TROP, BaconDecomposition, or WooldridgeDiD)
34+
- **Replicate weights**: BRR, Fay's BRR, JK1, JKn, SDR — 12 of 16 estimators (not SyntheticDiD, TROP, BaconDecomposition, WooldridgeDiD)
3535
- **Survey-aware bootstrap**: multiplier at PSU (IF-based) and Rao-Wu rescaled (resampling-based)
3636
- **DEFF diagnostics**, **subpopulation analysis**, **weight trimming**, **CV on estimates**
3737
- **Repeated cross-sections**: `CallawaySantAnna(panel=False)` for BRFSS, ACS, CPS
3838
- **R cross-validation**: 15 tests against R's `survey` package using NHANES, RECS, and API datasets
3939

4040
See [Survey Design Support](docs/choosing_estimator.rst#survey-design-support) for the full compatibility matrix, and [survey-roadmap.md](docs/survey-roadmap.md) for implementation details.
4141

42-
**Gap**: WooldridgeDiD does not yet accept `survey_design`. Planned for Phase 10f.
43-
4442
### Infrastructure
4543

4644
- Optional Rust backend for accelerated computation
@@ -50,24 +48,29 @@ See [Survey Design Support](docs/choosing_estimator.rst#survey-design-support) f
5048

5149
---
5250

53-
## Active Work: Survey Academic Credibility (Phase 10)
51+
## Survey Academic Credibility (Phase 10)
5452

55-
Before broadly announcing survey capability, we are establishing the theoretical
56-
and empirical foundation needed for credibility with practitioners and
57-
methodologists. See [survey-roadmap.md](docs/survey-roadmap.md) for detailed specs.
53+
Phase 10 established the theoretical and empirical foundation for survey support
54+
credibility. See [survey-roadmap.md](docs/survey-roadmap.md) for detailed specs.
5855

5956
| Item | Priority | Status |
6057
|------|----------|--------|
61-
| **10a.** Theory document (`survey-theory.md`) | HIGH | Not started |
62-
| **10b.** Research-grade survey DGP (enhance `generate_survey_did_data`) | HIGH | Not started |
63-
| **10c.** Expand R validation (ImputationDiD, StackedDiD, SunAbraham, TripleDifference) | HIGH | Not started |
64-
| **10d.** Tutorial: flat-weight vs design-based comparison | HIGH | Not started — depends on 10b |
58+
| **10a.** Theory document (`survey-theory.md`) | HIGH | ✅ Shipped (v2.9.1) |
59+
| **10b.** Research-grade survey DGP (enhance `generate_survey_did_data`) | HIGH | ✅ Shipped (v2.9.1) |
60+
| **10c.** Expand R validation (ImputationDiD, StackedDiD, SunAbraham, TripleDifference) | HIGH | ✅ Shipped (v2.9.1) |
61+
| **10d.** Tutorial: flat-weight vs design-based comparison | HIGH | ✅ Shipped (v2.9.1) |
6562
| **10e.** Position paper / arXiv preprint | MEDIUM | Not started — depends on 10b |
66-
| **10f.** WooldridgeDiD survey support (OLS + logit + Poisson) | MEDIUM | Not started |
63+
| **10f.** WooldridgeDiD survey support (OLS + logit + Poisson) | MEDIUM | ✅ Shipped (v2.9.0) |
6764
| **10g.** Practitioner guidance: when does survey design matter? | LOW | Not started |
6865

6966
---
7067

68+
## Future: Survey Aggregation Helper
69+
70+
**`survey_aggregate()` helper function** for the microdata-to-panel workflow. Bridges individual-level survey data (BRFSS, ACS, CPS) collected as repeated cross-sections to geographic-level (state, city) panel DiD. Computes design-based cell means and precision weights that estimators can consume directly.
71+
72+
---
73+
7174
## Future Estimators
7275

7376
### de Chaisemartin-D'Haultfouille Estimator

TODO.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,9 @@ Mypy reports 0 errors. All mixin `attr-defined` errors resolved via
116116

117117
Deprecated parameters still present for backward compatibility:
118118

119-
- `bootstrap_weight_type` in `CallawaySantAnna` (`staggered.py`)
120-
- Deprecated in favor of `bootstrap_weights` parameter
121-
- Remove in next major version (v3.0)
119+
- `lambda_reg` and `zeta` in `SyntheticDiD` (`synthetic_did.py`)
120+
- Deprecated in favor of `zeta_omega`/`zeta_lambda` parameters
121+
- Remove in v3.1
122122

123123
---
124124

diff_diff/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@
214214
EDiD = EfficientDiD
215215
ETWFE = WooldridgeDiD
216216

217-
__version__ = "2.9.1"
217+
__version__ = "3.0.0"
218218
__all__ = [
219219
# Estimators
220220
"DifferenceInDifferences",

diff_diff/staggered.py

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,6 @@ class CallawaySantAnna(
153153
- "rademacher": +1/-1 with equal probability (standard choice)
154154
- "mammen": Two-point distribution (asymptotically valid, matches skewness)
155155
- "webb": Six-point distribution (recommended when n_clusters < 20)
156-
bootstrap_weight_type : str, optional
157-
.. deprecated:: 1.0.1
158-
Use ``bootstrap_weights`` instead. Will be removed in v3.0.
159156
seed : int, optional
160157
Random seed for reproducibility.
161158
rank_deficient_action : str, default="warn"
@@ -293,7 +290,6 @@ def __init__(
293290
cluster: Optional[str] = None,
294291
n_bootstrap: int = 0,
295292
bootstrap_weights: Optional[str] = None,
296-
bootstrap_weight_type: Optional[str] = None,
297293
seed: Optional[int] = None,
298294
rank_deficient_action: str = "warn",
299295
base_period: str = "varying",
@@ -323,18 +319,7 @@ def __init__(
323319
f"pscore_fallback must be 'error' or 'unconditional', " f"got '{pscore_fallback}'"
324320
)
325321

326-
# Handle bootstrap_weight_type deprecation
327-
if bootstrap_weight_type is not None:
328-
warnings.warn(
329-
"bootstrap_weight_type is deprecated and will be removed in v3.0. "
330-
"Use bootstrap_weights instead.",
331-
DeprecationWarning,
332-
stacklevel=2,
333-
)
334-
if bootstrap_weights is None:
335-
bootstrap_weights = bootstrap_weight_type
336-
337-
# Default to rademacher if neither specified
322+
# Default to rademacher if not specified
338323
if bootstrap_weights is None:
339324
bootstrap_weights = "rademacher"
340325

@@ -362,8 +347,6 @@ def __init__(
362347
self.cluster = cluster
363348
self.n_bootstrap = n_bootstrap
364349
self.bootstrap_weights = bootstrap_weights
365-
# Keep bootstrap_weight_type for backward compatibility
366-
self.bootstrap_weight_type = bootstrap_weights
367350
self.seed = seed
368351
self.rank_deficient_action = rank_deficient_action
369352
self.base_period = base_period
@@ -3881,8 +3864,6 @@ def get_params(self) -> Dict[str, Any]:
38813864
"cluster": self.cluster,
38823865
"n_bootstrap": self.n_bootstrap,
38833866
"bootstrap_weights": self.bootstrap_weights,
3884-
# Deprecated but kept for backward compatibility
3885-
"bootstrap_weight_type": self.bootstrap_weight_type,
38863867
"seed": self.seed,
38873868
"rank_deficient_action": self.rank_deficient_action,
38883869
"base_period": self.base_period,

diff_diff/staggered_bootstrap.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ class CallawaySantAnnaBootstrapMixin:
118118

119119
# Type hints for attributes accessed from the main class
120120
n_bootstrap: int
121-
bootstrap_weight_type: str
121+
bootstrap_weights: str
122122
alpha: float
123123
seed: Optional[int]
124124
anticipation: int
@@ -329,7 +329,7 @@ def _run_multiplier_bootstrap(
329329
if _use_survey_bootstrap:
330330
# PSU-level multiplier weights
331331
psu_weights, psu_ids = _generate_survey_multiplier_weights_batch(
332-
self.n_bootstrap, resolved_survey_unit, self.bootstrap_weight_type, rng
332+
self.n_bootstrap, resolved_survey_unit, self.bootstrap_weights, rng
333333
)
334334
# Build unit → PSU column map
335335
if resolved_survey_unit.psu is not None:
@@ -348,7 +348,7 @@ def _run_multiplier_bootstrap(
348348
else:
349349
# Standard unit-level weights (no survey or weights-only)
350350
all_bootstrap_weights = _generate_bootstrap_weights_batch(
351-
self.n_bootstrap, n_units, self.bootstrap_weight_type, rng
351+
self.n_bootstrap, n_units, self.bootstrap_weights, rng
352352
)
353353

354354
# Vectorized bootstrap ATT(g,t) computation
@@ -534,7 +534,7 @@ def _run_multiplier_bootstrap(
534534

535535
return CSBootstrapResults(
536536
n_bootstrap=self.n_bootstrap,
537-
weight_type=self.bootstrap_weight_type,
537+
weight_type=self.bootstrap_weights,
538538
alpha=self.alpha,
539539
overall_att_se=overall_se,
540540
overall_att_ci=overall_ci,

diff_diff/staggered_triple_diff.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@ def __init__(
147147
self.base_period = base_period
148148
self.n_bootstrap = n_bootstrap
149149
self.bootstrap_weights = bootstrap_weights
150-
self.bootstrap_weight_type = bootstrap_weights
151150
self.seed = seed
152151
self.cband = cband
153152
self.pscore_trim = pscore_trim
@@ -186,7 +185,7 @@ def set_params(self, **params) -> "StaggeredTripleDifference":
186185
raise ValueError(f"Unknown parameter: {key}")
187186
setattr(self, key, value)
188187
if "bootstrap_weights" in params:
189-
self.bootstrap_weight_type = params["bootstrap_weights"]
188+
self.bootstrap_weights = params["bootstrap_weights"]
190189
return self
191190

192191
# ------------------------------------------------------------------

diff_diff/synthetic_did.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,14 +144,14 @@ def __init__(
144144
warnings.warn(
145145
"lambda_reg is deprecated and ignored. Regularization is now "
146146
"auto-computed from data. Use zeta_omega to override unit weight "
147-
"regularization.",
147+
"regularization. Will be removed in v3.1.",
148148
DeprecationWarning,
149149
stacklevel=2,
150150
)
151151
if zeta is not None:
152152
warnings.warn(
153153
"zeta is deprecated and ignored. Use zeta_lambda to override "
154-
"time weight regularization.",
154+
"time weight regularization. Will be removed in v3.1.",
155155
DeprecationWarning,
156156
stacklevel=2,
157157
)
@@ -1124,7 +1124,8 @@ def set_params(self, **params) -> "SyntheticDiD":
11241124
for key, value in params.items():
11251125
if key in _deprecated:
11261126
warnings.warn(
1127-
f"{key} is deprecated and ignored. Use zeta_omega/zeta_lambda " f"instead.",
1127+
f"{key} is deprecated and ignored. Use zeta_omega/zeta_lambda "
1128+
f"instead. Will be removed in v3.1.",
11281129
DeprecationWarning,
11291130
stacklevel=2,
11301131
)

diff_diff/trop.py

Lines changed: 4 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,6 @@ class TROP(TROPLocalMixin, TROPGlobalMixin):
7777
ATT is the mean of these effects. For the paper's full
7878
per-treated-cell estimator, use ``method='local'``.
7979
80-
- 'twostep': Deprecated alias for 'local'. Will be removed in v3.0.
81-
82-
- 'joint': Deprecated alias for 'global'. Will be removed in v3.0.
83-
8480
lambda_time_grid : list, optional
8581
Grid of time weight decay parameters. 0.0 = uniform weights (disabled).
8682
Must not contain inf. Default: [0, 0.1, 0.5, 1, 2, 5].
@@ -140,26 +136,9 @@ def __init__(
140136
seed: Optional[int] = None,
141137
):
142138
# Validate method parameter
143-
# 'local'/'global' are preferred; 'twostep'/'joint' are deprecated aliases
144-
valid_methods = ("local", "twostep", "joint", "global")
139+
valid_methods = ("local", "global")
145140
if method not in valid_methods:
146141
raise ValueError(f"method must be one of {valid_methods}, got '{method}'")
147-
if method == "twostep":
148-
warnings.warn(
149-
"method='twostep' is deprecated and will be removed in v3.0. "
150-
"Use method='local' instead.",
151-
FutureWarning,
152-
stacklevel=2,
153-
)
154-
method = "local"
155-
if method == "joint":
156-
warnings.warn(
157-
"method='joint' is deprecated and will be removed in v3.0. "
158-
"Use method='global' instead.",
159-
FutureWarning,
160-
stacklevel=2,
161-
)
162-
method = "global"
163142
self.method = method
164143

165144
# Default grids from paper
@@ -913,22 +892,10 @@ def get_params(self) -> Dict[str, Any]:
913892
def set_params(self, **params) -> "TROP":
914893
"""Set estimator parameters."""
915894
for key, value in params.items():
916-
if key == "method" and value == "twostep":
917-
warnings.warn(
918-
"method='twostep' is deprecated and will be removed in "
919-
"v3.0. Use method='local' instead.",
920-
FutureWarning,
921-
stacklevel=2,
922-
)
923-
value = "local"
924-
if key == "method" and value == "joint":
925-
warnings.warn(
926-
"method='joint' is deprecated and will be removed in "
927-
"v3.0. Use method='global' instead.",
928-
FutureWarning,
929-
stacklevel=2,
895+
if key == "method" and value not in ("local", "global"):
896+
raise ValueError(
897+
f"method must be one of ('local', 'global'), got '{value}'"
930898
)
931-
value = "global"
932899
if hasattr(self, key):
933900
setattr(self, key, value)
934901
else:

docs/api/_autosummary/diff_diff.CallawaySantAnna.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
.. autosummary::
3030

3131
~CallawaySantAnna.n_bootstrap
32-
~CallawaySantAnna.bootstrap_weight_type
32+
~CallawaySantAnna.bootstrap_weights
3333
~CallawaySantAnna.alpha
3434
~CallawaySantAnna.seed
3535
~CallawaySantAnna.anticipation

0 commit comments

Comments
 (0)