Skip to content

Commit 6c841d2

Browse files
igerberclaude
andcommitted
docs(paper): finalize JOSS submission - 20 estimators, required sections, draft-pdf CI
- paper.md: update estimator count 19 -> 20 (LPDiD merged after #564); add LPDiD to the staggered-adoption method list with Dube2025 citation - paper.md: restructure to current JOSS required sections - add State of the Field (Python/R/Stata landscape with build-vs-contribute justification), Software Design (shared inference core, influence-function survey architecture, minimal-dependency policy, Rust backend), and Research Impact Statement (companion preprint, golden-file R validation, real-data survey validation, community-readiness signals); 1,269 words, within the 750-1750 target - paper.bib: add Dube2025 (LP-DiD, J. Applied Econometrics), Binder1983 (previously cited in-text without a bib entry), pyfixest (software citation for State of the Field) - paper.md: AI disclosure updated to name the Opus, Sonnet, and Fable model families - llms.txt / llms-full.txt: stale counts 19 -> 20 and "13 of 16" -> "13 of 20" replicate-weight support - practitioner_decision_tree.rst: stale "17 estimators" -> 20, mention Local Projections DiD - choosing_estimator.rst survey matrix: dCDH replicate weights "--" -> "Full (analytical)" (support landed with test_survey_dcdh_replicate_psu coverage); add missing SpilloverDiD and SyntheticControl rows; note the SyntheticControl NotImplementedError in the intro - .github/workflows/draft-pdf.yml: SHA-pinned openjournals draft action compiles the paper on paper.md/paper.bib changes and uploads the PDF artifact Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 0251fee commit 6c841d2

7 files changed

Lines changed: 184 additions & 51 deletions

File tree

.github/workflows/draft-pdf.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: Draft PDF
2+
3+
on:
4+
push:
5+
branches: [main]
6+
paths:
7+
- paper.md
8+
- paper.bib
9+
- .github/workflows/draft-pdf.yml
10+
pull_request:
11+
paths:
12+
- paper.md
13+
- paper.bib
14+
- .github/workflows/draft-pdf.yml
15+
workflow_dispatch:
16+
17+
permissions:
18+
contents: read
19+
20+
jobs:
21+
paper:
22+
runs-on: ubuntu-latest
23+
name: Compile JOSS paper draft
24+
steps:
25+
- name: Checkout
26+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
27+
- name: Build draft PDF
28+
uses: openjournals/openjournals-draft-action@85a18372e48f551d8af9ddb7a747de685fbbb01c # v1.0
29+
with:
30+
journal: joss
31+
paper-path: paper.md
32+
- name: Upload paper artifact
33+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
34+
with:
35+
name: joss-paper
36+
path: paper.pdf

diff_diff/guides/llms-full.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2120,7 +2120,7 @@ sd_female, data_female = sd.subpopulation(data, mask=lambda df: df['sex'] == 'F'
21202120

21212121
**Key features:**
21222122
- Taylor Series Linearization (TSL) variance with strata + PSU + FPC
2123-
- Replicate weight variance: BRR, Fay's BRR, JK1, JKn, SDR (13 of 16 estimators, including dCDH)
2123+
- Replicate weight variance: BRR, Fay's BRR, JK1, JKn, SDR (13 of 20 estimators, including dCDH)
21242124
- Survey-aware bootstrap: multiplier at PSU (Hall-Mammen wild; dCDH, staggered) or Rao-Wu rescaled (SunAbraham, SyntheticDiD, TROP). SyntheticDiD bootstrap composes Rao-Wu rescaled per-draw weights with the weighted Frank-Wolfe variant of `_sc_weight_fw` (PR #355): each draw solves `min ||A·diag(rw)·ω - b||² + ζ²·Σ rw_i ω_i²` and composes `ω_eff = rw·ω/Σ(rw·ω)` for the SDID estimator. Pweight-only fits use constant `rw = w_control`; full designs use Rao-Wu. SDID's placebo (stratified permutation + weighted FW) and jackknife (PSU-level LOO with stratum aggregation, Rust & Rao 1996) paths also support pweight-only and full strata/PSU/FPC designs
21252125
- DEFF diagnostics, subpopulation analysis, weight trimming (`trim_weights`)
21262126
- Repeated cross-sections: `CallawaySantAnna(panel=False)`

diff_diff/guides/llms.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
> A Python library for Difference-in-Differences (DiD) causal inference analysis. Provides sklearn-like estimators with statsmodels-style summary output for econometric analysis.
44

5-
diff-diff offers 19 estimators covering basic 2x2 DiD, modern staggered adoption methods, reversible (non-absorbing) treatments, advanced panel estimators, nonlinear models, and diagnostic tools. It supports robust and cluster-robust standard errors, wild cluster bootstrap, formula and column-name interfaces, fixed effects (dummy and absorbed), complex survey designs (strata/PSU/FPC, replicate weights, design-based variance), and publication-ready output. The optional Rust backend accelerates compute-intensive estimators like Synthetic DiD and TROP.
5+
diff-diff offers 20 estimators covering basic 2x2 DiD, modern staggered adoption methods, reversible (non-absorbing) treatments, advanced panel estimators, nonlinear models, and diagnostic tools. It supports robust and cluster-robust standard errors, wild cluster bootstrap, formula and column-name interfaces, fixed effects (dummy and absorbed), complex survey designs (strata/PSU/FPC, replicate weights, design-based variance), and publication-ready output. The optional Rust backend accelerates compute-intensive estimators like Synthetic DiD and TROP.
66

77
- Install: `pip install diff-diff`
88
- License: MIT

docs/choosing_estimator.rst

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -771,7 +771,8 @@ If you're unsure which estimator to use:
771771
Survey Design Support
772772
---------------------
773773

774-
All estimators accept an optional ``survey_design`` parameter in ``fit()``.
774+
All estimators accept an optional ``survey_design`` parameter in ``fit()``
775+
(``SyntheticControl`` does not yet support it and raises ``NotImplementedError``).
775776
Pass a :class:`~diff_diff.SurveyDesign` object to get design-based variance
776777
estimation. The depth of support varies by estimator:
777778

@@ -820,7 +821,7 @@ estimation. The depth of support varies by estimator:
820821
* - ``ChaisemartinDHaultfoeuille``
821822
- pweight only
822823
- Full (TSL)
823-
- --
824+
- Full (analytical)
824825
- Group-level (warning)
825826
* - ``TripleDifference``
826827
- pweight only
@@ -872,6 +873,11 @@ estimation. The depth of support varies by estimator:
872873
- Via bootstrap
873874
- --
874875
- Hybrid pairs-bootstrap + Rao-Wu rescaled (bootstrap only)
876+
* - ``SyntheticControl``
877+
- --
878+
- --
879+
- --
880+
- --
875881
* - ``TROP``
876882
- pweight only
877883
- Via bootstrap
@@ -887,6 +893,11 @@ estimation. The depth of support varies by estimator:
887893
- Full (Binder TSL)
888894
- --
889895
- --
896+
* - ``SpilloverDiD``
897+
- pweight only
898+
- Full (Binder TSL + Conley)
899+
- --
900+
- --
890901
* - ``BaconDecomposition``
891902
- Diagnostic
892903
- Diagnostic

docs/practitioner_decision_tree.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -463,9 +463,10 @@ At a Glance
463463
What About the Other Estimators?
464464
--------------------------------
465465

466-
diff-diff has 17 estimators covering advanced scenarios: Sun-Abraham for
466+
diff-diff has 20 estimators covering advanced scenarios: Sun-Abraham for
467467
interaction-weighted estimation, Imputation DiD and Two-Stage DiD for alternative
468-
staggered approaches, Stacked DiD, Efficient DiD, Triple Difference, TROP, and more.
468+
staggered approaches, Local Projections DiD, Stacked DiD, Efficient DiD,
469+
Triple Difference, TROP, and more.
469470
The six scenarios above cover the most common business use cases.
470471

471472
For the full academic decision tree with all estimators, see :doc:`choosing_estimator`.

paper.bib

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,3 +249,32 @@ @misc{deChaisemartin2026
249249
primaryclass = {econ.EM},
250250
doi = {10.48550/arXiv.2405.04465}
251251
}
252+
253+
@article{Dube2025,
254+
author = {Dube, Arindrajit and Girardi, Daniele and Jord{\`a}, {\`O}scar and Taylor, Alan M.},
255+
title = {A Local Projections Approach to Difference-in-Differences},
256+
journal = {Journal of Applied Econometrics},
257+
volume = {40},
258+
number = {5},
259+
pages = {741--758},
260+
year = {2025},
261+
doi = {10.1002/jae.70000}
262+
}
263+
264+
@article{Binder1983,
265+
author = {Binder, David A.},
266+
title = {On the Variances of Asymptotically Normal Estimators from Complex Surveys},
267+
journal = {International Statistical Review},
268+
volume = {51},
269+
number = {3},
270+
pages = {279--292},
271+
year = {1983},
272+
doi = {10.2307/1402588}
273+
}
274+
275+
@misc{pyfixest,
276+
author = {{The PyFixest Authors}},
277+
title = {pyfixest: Fast High-Dimensional Fixed Effect Estimation in Python},
278+
year = {2025},
279+
url = {https://github.com/py-econometrics/pyfixest}
280+
}

paper.md

Lines changed: 101 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ bibliography: paper.bib
2121
# Summary
2222

2323
`diff-diff` is a Python library for Difference-in-Differences (DiD) causal inference
24-
analysis. It provides 19 estimators covering the full modern DiD toolkit - from classic
24+
analysis. It provides 20 estimators covering the full modern DiD toolkit - from classic
2525
two-group/two-period designs through heterogeneity-robust staggered adoption methods,
2626
synthetic control hybrids, and sensitivity analysis - under a consistent scikit-learn-style
2727
API. Most estimators accept an optional `SurveyDesign` object for design-based variance
@@ -41,76 +41,132 @@ modern methods - including Callaway and Sant'Anna [-@Callaway2021], Sun and Abra
4141
[-@Sun2021], Borusyak, Jaravel, and Spiess [-@Borusyak2024], and others - are now standard
4242
practice in applied work.
4343

44-
The R ecosystem provides mature implementations across several packages: `did`
45-
[@Callaway2021], `fixest` [@Berge2018], `synthdid` [@Arkhangelsky2021], and `HonestDiD`
46-
[@Rambachan2023]. Stata offers `csdid` and `didregress`. Python, however, lacks a unified
47-
DiD library. Practitioners working in Python-based data science workflows - increasingly
48-
common in industry settings for marketing measurement, product experimentation, and policy
49-
evaluation - must either context-switch to R, reimplement methods from scratch, or rely on
50-
partial implementations scattered across unrelated packages.
44+
These methods are well served in R and Stata, but Python lacks a unified DiD library.
45+
Practitioners working in Python-based data science workflows - increasingly common in
46+
industry settings for marketing measurement, product experimentation, and policy
47+
evaluation - must either context-switch to another language, reimplement methods from
48+
scratch, or rely on partial implementations scattered across unrelated packages.
5149

52-
`diff-diff` fills this gap by providing a single-import library that covers 19 estimators
50+
`diff-diff` fills this gap by providing a single-import library that covers 20 estimators
5351
with a consistent API, survey-weighted inference, and numerical validation against R. It
5452
is also the companion software for the design-based variance framework of @Gerber2026,
5553
which establishes design-consistent standard errors for modern DiD estimators under
5654
complex survey designs. It targets both applied researchers who need rigorous econometric
5755
methods and data science practitioners who need accessible causal inference tools
5856
integrated into Python workflows.
5957

58+
# State of the Field
59+
60+
The R ecosystem provides mature implementations across several packages: `did`
61+
[@Callaway2021], `fixest` [@Berge2018], `synthdid` [@Arkhangelsky2021], and `HonestDiD`
62+
[@Rambachan2023]; Stata offers `csdid` and `didregress`. Python coverage is partial and
63+
fragmented. `pyfixest` [@pyfixest] brings `fixest`-style high-dimensional fixed-effects
64+
regression to Python, including Sun-Abraham, two-stage, and local-projections estimators,
65+
but is organized around its regression engine rather than the wider DiD taxonomy;
66+
`differences` implements Callaway-Sant'Anna group-time estimation; `CausalPy` offers
67+
Bayesian analysis of quasi-experiments, including synthetic control, without
68+
staggered-adoption support. General-purpose causal inference toolkits such as `DoWhy` and
69+
`EconML` target other identification strategies.
70+
71+
`diff-diff` was built as a new library, rather than as contributions to these packages,
72+
because its central contribution is cross-cutting: one estimator contract, one shared
73+
inference core, and an influence-function architecture that composes design-based survey
74+
variance with every estimator in the taxonomy. To our knowledge, no existing DiD software
75+
in any language provides design-based variance estimation for complex survey data, and no
76+
Python package covers the modern estimator taxonomy end-to-end; `diff-diff` provides
77+
both, validated against the R reference implementations where they exist.
78+
6079
# Key Features
6180

62-
**Breadth of methods.** `diff-diff` implements 19 estimators organized across the modern
81+
**Breadth of methods.** `diff-diff` implements 20 estimators organized across the modern
6382
DiD taxonomy. Classic designs include two-group/two-period DiD, two-way fixed effects, and
6483
event-study estimation with period-specific effects. Heterogeneity-robust staggered-adoption
6584
estimators include Callaway-Sant'Anna [@Callaway2021], Sun-Abraham [@Sun2021], imputation
66-
[@Borusyak2024], two-stage [@Gardner2022], stacked [@Wing2024], and efficient [@Chen2025]
67-
approaches, together with reversible-treatment DiD for non-absorbing interventions
68-
[@deChaisemartin2020] and a ring-indicator estimator for spatial spillovers [@Butts2021].
69-
Synthetic-control hybrids include synthetic DiD [@Arkhangelsky2021] and the classic
70-
synthetic control method [@Abadie2010]. Extended designs include triple-difference and
71-
staggered triple-difference estimators [@OrtizVillavicencio2025], continuous-treatment DiD
72-
with dose-response curves [@Callaway2024], heterogeneous-adoption designs where no unit
73-
remains untreated [@deChaisemartin2026], nonlinear ETWFE [@Wooldridge2025; @Wooldridge2023],
74-
and triply robust panel estimation [@Athey2025]. Separate diagnostic and sensitivity tools -
75-
outside the 19 estimators - include Goodman-Bacon decomposition [@GoodmanBacon2021], Honest
76-
DiD sensitivity analysis [@Rambachan2023], placebo tests, and pre-trends power analysis
77-
[@Roth2022]. All estimators share a consistent `fit()` interface with
78-
`get_params()`/`set_params()` for configuration, R-style formula support, and rich results
79-
objects with `summary()` output. An optional Rust backend via PyO3 accelerates
80-
compute-intensive operations.
85+
[@Borusyak2024], two-stage [@Gardner2022], stacked [@Wing2024], efficient [@Chen2025], and
86+
local-projections [@Dube2025] approaches, together with reversible-treatment DiD for
87+
non-absorbing interventions [@deChaisemartin2020] and a ring-indicator estimator for
88+
spatial spillovers [@Butts2021]. Synthetic-control hybrids include synthetic DiD
89+
[@Arkhangelsky2021] and the classic synthetic control method [@Abadie2010]. Extended
90+
designs include triple-difference and staggered triple-difference estimators
91+
[@OrtizVillavicencio2025], continuous-treatment DiD with dose-response curves
92+
[@Callaway2024], heterogeneous-adoption designs where no unit remains untreated
93+
[@deChaisemartin2026], nonlinear ETWFE [@Wooldridge2025; @Wooldridge2023], and triply
94+
robust panel estimation [@Athey2025]. Separate diagnostic and sensitivity tools - outside
95+
the 20 estimators - include Goodman-Bacon decomposition [@GoodmanBacon2021], Honest DiD
96+
sensitivity analysis [@Rambachan2023], placebo tests, and pre-trends power analysis
97+
[@Roth2022].
8198

8299
**Survey-weighted inference.** A `SurveyDesign` class supports stratification, primary
83100
sampling units, finite population corrections, and probability weights. Variance estimation
84101
includes Taylor series linearization, five replicate weight methods (BRR, Fay's BRR, JK1,
85-
JKn, SDR), and survey-aware bootstrap. Survey variance is validated against R's `survey`
86-
package [@Lumley2004] on three real complex-survey datasets - NHANES, RECS 2020, and the
87-
California API school dataset - to a tight tolerance (test gaps < 1e-8, typically below
88-
1e-10). The design-based variance result - that the influence functions of modern DiD
89-
estimators satisfy Binder's (1983) smoothness conditions, so stratified-cluster
90-
linearization yields design-consistent standard errors - is derived in @Gerber2026. No
91-
other DiD package in any language provides integrated survey support.
92-
93-
**Validation against R.** Point estimates match the R `did`, `synthdid`, and `fixest`
94-
packages to machine precision (differences < 1e-10). Standard errors match exactly for
95-
core estimators including Callaway-Sant'Anna and basic DiD. Validation includes the
96-
canonical MPDTA minimum-wage dataset from Callaway and Sant'Anna [-@Callaway2021].
102+
JKn, SDR), and survey-aware bootstrap. The design-based variance result - that the
103+
influence functions of modern DiD estimators satisfy the smoothness conditions of
104+
@Binder1983, so stratified-cluster linearization yields design-consistent standard
105+
errors - is derived in @Gerber2026. No other DiD package in any language provides
106+
integrated survey support.
97107

98108
**Practitioner tooling.** Beyond estimation, `diff-diff` includes a practitioner decision
99109
tree for estimator selection, an 8-step diagnostic workflow based on Baker et al.
100110
[-@Baker2025], AI agent integration with structured next-steps guidance, and microdata
101111
aggregation utilities for converting individual-level survey responses into
102112
geographic-period panels suitable for DiD analysis.
103113

114+
# Software Design
115+
116+
Every estimator implements a common contract: a scikit-learn-style `fit()` with
117+
`get_params()`/`set_params()` for configuration, R-style formula support, and rich results
118+
dataclasses with `summary()`, `to_dict()`, and `to_dataframe()`. Numerical work is
119+
deliberately centralized: all estimators solve their least-squares problems and their
120+
robust, cluster-robust, and survey variances through a single shared linear-algebra core,
121+
so numerical hardening - rank-deficiency guards, degrees-of-freedom corrections,
122+
small-cluster behavior - lands in one place and propagates to every estimator. Inference
123+
fields (standard error, t-statistic, p-value, confidence interval) are always computed
124+
together and become NaN together when inference is not identified, rather than silently
125+
reporting partial results.
126+
127+
Two design choices carry the survey capability and the deployment story. First, estimators
128+
compute influence functions for their target parameters, so design-based variance - Taylor
129+
series linearization over strata and clusters, replicate weights, survey-aware
130+
bootstrap - composes uniformly with estimators as different as Callaway-Sant'Anna and
131+
synthetic DiD instead of requiring per-estimator derivations. Second, the runtime
132+
dependency footprint is minimal by policy - numpy, pandas, and scipy only - keeping the
133+
library easy to install in restricted industry environments; high-dimensional fixed
134+
effects are handled by within-transformation rather than by delegating to a heavier
135+
econometrics stack. An optional Rust backend (via PyO3) accelerates compute-intensive
136+
kernels such as synthetic-control weight solving and fixed-effects absorption; the Python
137+
implementation remains canonical, equivalence between backends is enforced by the test
138+
suite, and the library falls back to pure Python automatically when the extension is
139+
unavailable.
140+
141+
# Research Impact Statement
142+
143+
`diff-diff` is the companion software of the design-based variance preprint [@Gerber2026]:
144+
the framework derived there is implemented here, and the preprint's numerical results are
145+
produced with the library. Correctness evidence ships with the repository as reproducible
146+
material. Golden-file benchmarks pin point estimates against R's `did`, `synthdid`, and
147+
`fixest` to machine precision (differences < 1e-10), including the canonical MPDTA
148+
minimum-wage application of Callaway and Sant'Anna [-@Callaway2021], with standard errors
149+
matching exactly for core estimators such as Callaway-Sant'Anna and basic DiD. Survey
150+
variance is validated against R's `survey` package [@Lumley2004] on three real
151+
complex-survey datasets - NHANES, RECS 2020, and the California API school data - with
152+
test gaps below 1e-8 and typically below 1e-10. The library is distributed on PyPI with
153+
tagged releases, has six months of continuous public development history (3,000+
154+
commits), and is exercised by a CI test suite of more than 7,600 tests; 26 tutorial
155+
notebooks and full API documentation are published on Read the Docs, and machine-readable
156+
guides bundled in the wheel (`llms.txt`) make the library directly usable by AI-assisted
157+
analysis workflows.
158+
104159
# AI Usage Disclosure
105160

106161
Generative AI tools were used in developing this software and manuscript. Anthropic's
107-
Claude models (the Opus and Sonnet families, via the Claude Code CLI) assisted with code
108-
generation and refactoring, test scaffolding, documentation, and drafting and editing of
109-
this manuscript. The author reviewed, modified, and validated all AI-generated code and
110-
text and made all primary architectural and methodological decisions. Numerical results
111-
were independently verified against established R reference packages (`did`, `synthdid`,
112-
`fixest`, `survey`) for every estimator with an R equivalent, and against the author's
113-
reference derivations or simulation otherwise. The author takes full responsibility for the
114-
accuracy and integrity of the software and this paper.
162+
Claude models (the Opus, Sonnet, and Fable model families, via the Claude Code CLI)
163+
assisted with code generation and refactoring, test scaffolding, documentation, and
164+
drafting and editing of this manuscript. The author reviewed, modified, and validated all
165+
AI-generated code and text and made all primary architectural and methodological
166+
decisions. Numerical results were independently verified against established R reference
167+
packages (`did`, `synthdid`, `fixest`, `survey`) for every estimator with an R
168+
equivalent, and against the author's reference derivations or simulation otherwise. The
169+
author takes full responsibility for the accuracy and integrity of the software and this
170+
paper.
115171

116172
# References

0 commit comments

Comments
 (0)