diff-diff 3.1.3__tar.gz → 3.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {diff_diff-3.1.3 → diff_diff-3.3.0}/PKG-INFO +41 -2
- {diff_diff-3.1.3 → diff_diff-3.3.0}/README.md +40 -1
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/__init__.py +102 -9
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/_backend.py +12 -4
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/_guides_api.py +7 -3
- diff_diff-3.3.0/diff_diff/_nprobust_port.py +1412 -0
- diff_diff-3.3.0/diff_diff/_reporting_helpers.py +634 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/bootstrap_utils.py +85 -0
- diff_diff-3.3.0/diff_diff/business_report.py +2653 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/chaisemartin_dhaultfoeuille.py +1769 -344
- diff_diff-3.3.0/diff_diff/chaisemartin_dhaultfoeuille_bootstrap.py +1015 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/chaisemartin_dhaultfoeuille_results.py +289 -39
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/continuous_did.py +59 -3
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/continuous_did_bspline.py +29 -3
- diff_diff-3.3.0/diff_diff/diagnostic_report.py +3381 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/efficient_did.py +52 -29
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/efficient_did_covariates.py +64 -1
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/efficient_did_results.py +6 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/estimators.py +330 -52
- diff_diff-3.3.0/diff_diff/guides/llms-autonomous.txt +844 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/guides/llms-full.txt +145 -4
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/guides/llms-practitioner.txt +44 -0
- diff_diff-3.3.0/diff_diff/had.py +4415 -0
- diff_diff-3.3.0/diff_diff/had_pretests.py +3019 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/imputation.py +1 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/imputation_results.py +1 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/linalg.py +779 -75
- diff_diff-3.3.0/diff_diff/local_linear.py +1332 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/power.py +42 -14
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/practitioner.py +50 -8
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/prep.py +96 -5
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/pretrends.py +34 -6
- diff_diff-3.3.0/diff_diff/profile.py +714 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/results.py +224 -70
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/stacked_did.py +1 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/stacked_did_results.py +1 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/staggered.py +78 -15
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/staggered_results.py +8 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/staggered_triple_diff.py +80 -6
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/staggered_triple_diff_results.py +5 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/sun_abraham.py +7 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/survey.py +353 -1
- diff_diff-3.3.0/diff_diff/synthetic_did.py +2688 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/trop_global.py +64 -48
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/trop_local.py +91 -107
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/twfe.py +121 -10
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/two_stage.py +17 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/two_stage_bootstrap.py +15 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/two_stage_results.py +1 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/utils.py +603 -161
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/wooldridge.py +23 -3
- {diff_diff-3.1.3 → diff_diff-3.3.0}/pyproject.toml +1 -1
- {diff_diff-3.1.3 → diff_diff-3.3.0}/rust/Cargo.lock +7 -7
- {diff_diff-3.1.3 → diff_diff-3.3.0}/rust/Cargo.toml +1 -1
- {diff_diff-3.1.3 → diff_diff-3.3.0}/rust/src/lib.rs +4 -2
- {diff_diff-3.1.3 → diff_diff-3.3.0}/rust/src/linalg.rs +1 -1
- {diff_diff-3.1.3 → diff_diff-3.3.0}/rust/src/trop.rs +289 -142
- {diff_diff-3.1.3 → diff_diff-3.3.0}/rust/src/weights.rs +582 -145
- diff_diff-3.1.3/diff_diff/chaisemartin_dhaultfoeuille_bootstrap.py +0 -590
- diff_diff-3.1.3/diff_diff/synthetic_did.py +0 -1482
- {diff_diff-3.1.3 → diff_diff-3.3.0}/LICENSE +0 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/bacon.py +0 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/continuous_did_results.py +0 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/datasets.py +0 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/diagnostics.py +0 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/efficient_did_bootstrap.py +0 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/efficient_did_weights.py +0 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/guides/__init__.py +0 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/guides/llms.txt +0 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/honest_did.py +0 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/imputation_bootstrap.py +0 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/prep_dgp.py +0 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/staggered_aggregation.py +0 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/staggered_bootstrap.py +0 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/triple_diff.py +0 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/trop.py +0 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/trop_results.py +0 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/visualization/__init__.py +0 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/visualization/_common.py +0 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/visualization/_continuous.py +0 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/visualization/_diagnostic.py +0 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/visualization/_event_study.py +0 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/visualization/_power.py +0 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/visualization/_staggered.py +0 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/visualization/_synthetic.py +0 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/diff_diff/wooldridge_results.py +0 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/rust/build.rs +0 -0
- {diff_diff-3.1.3 → diff_diff-3.3.0}/rust/src/bootstrap.rs +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: diff-diff
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.3.0
|
|
4
4
|
Classifier: Development Status :: 5 - Production/Stable
|
|
5
5
|
Classifier: Intended Audience :: Science/Research
|
|
6
6
|
Classifier: Operating System :: OS Independent
|
|
@@ -57,6 +57,7 @@ Project-URL: Repository, https://github.com/igerber/diff-diff
|
|
|
57
57
|
[](https://opensource.org/licenses/MIT)
|
|
58
58
|
[](https://pypi.org/project/diff-diff/)
|
|
59
59
|
[](https://diff-diff.readthedocs.io/en/stable/)
|
|
60
|
+
[](https://doi.org/10.5281/zenodo.19646175)
|
|
60
61
|
|
|
61
62
|
A Python library for Difference-in-Differences (DiD) causal inference analysis with an sklearn-like API and statsmodels-style outputs.
|
|
62
63
|
|
|
@@ -144,6 +145,38 @@ Measuring campaign lift? Evaluating a product launch? diff-diff handles the caus
|
|
|
144
145
|
- **[Brand awareness survey tutorial](docs/tutorials/17_brand_awareness_survey.ipynb)** - Full example with complex survey design, brand funnel analysis, and staggered rollouts
|
|
145
146
|
- **Have BRFSS/ACS/CPS individual records?** Use [`aggregate_survey()`](docs/api/prep.rst) to roll respondent-level microdata into a geographic-period panel with inverse-variance precision weights. The returned second-stage design uses analytic weights (`aweight`), so it works directly with `DifferenceInDifferences`, `TwoWayFixedEffects`, `MultiPeriodDiD`, `SunAbraham`, `ContinuousDiD`, and `EfficientDiD` (estimators marked **Full** in the [survey support matrix](docs/choosing_estimator.rst))
|
|
146
147
|
|
|
148
|
+
### Experimental preview: `BusinessReport` and `DiagnosticReport`
|
|
149
|
+
|
|
150
|
+
diff-diff ships two preview classes, `BusinessReport` and `DiagnosticReport`, that produce plain-English output and a structured `to_dict()` schema from any fitted result. **Both are experimental in this release** — wording, verdict thresholds, and schema shape will change as the library learns from real practitioner usage. Do not anchor downstream tooling on the schema yet; the experimental flag is noted in the CHANGELOG.
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
from diff_diff import CallawaySantAnna, BusinessReport
|
|
154
|
+
|
|
155
|
+
cs = CallawaySantAnna(base_period="universal").fit(
|
|
156
|
+
df, outcome="revenue", unit="store", time="month",
|
|
157
|
+
first_treat="first_treat", aggregate="event_study",
|
|
158
|
+
)
|
|
159
|
+
report = BusinessReport(
|
|
160
|
+
cs,
|
|
161
|
+
outcome_label="Revenue per store",
|
|
162
|
+
outcome_unit="$",
|
|
163
|
+
business_question="Did the loyalty program lift revenue?",
|
|
164
|
+
treatment_label="the loyalty program",
|
|
165
|
+
# Optional: pass the panel + column names so the auto-constructed
|
|
166
|
+
# DiagnosticReport can run data-dependent checks (2x2 pre-trends,
|
|
167
|
+
# Goodman-Bacon decomposition, EfficientDiD Hausman pretest).
|
|
168
|
+
# Without these the auto path still runs but skips those checks.
|
|
169
|
+
data=df,
|
|
170
|
+
outcome="revenue",
|
|
171
|
+
unit="store",
|
|
172
|
+
time="month",
|
|
173
|
+
first_treat="first_treat",
|
|
174
|
+
)
|
|
175
|
+
print(report.summary())
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
`BusinessReport` auto-constructs a `DiagnosticReport` so the summary mentions pre-trends, sensitivity, and design-effect findings in one call. Methodology (phrasing rules, verdict thresholds, schema stability) is documented in [docs/methodology/REPORTING.md](docs/methodology/REPORTING.md). Feedback on wording, applicability, and missing diagnostics is welcome — this is the part of the library most likely to evolve in the next few releases.
|
|
179
|
+
|
|
147
180
|
Already know DiD? The [academic quickstart](docs/quickstart.rst) and [estimator guide](docs/choosing_estimator.rst) cover the full technical details.
|
|
148
181
|
|
|
149
182
|
## Features
|
|
@@ -3119,14 +3152,20 @@ If you use diff-diff in your research, please cite it:
|
|
|
3119
3152
|
```bibtex
|
|
3120
3153
|
@software{diff_diff,
|
|
3121
3154
|
title = {diff-diff: Difference-in-Differences Causal Inference for Python},
|
|
3122
|
-
author = {
|
|
3155
|
+
author = {Gerber, Isaac},
|
|
3156
|
+
year = {2026},
|
|
3123
3157
|
url = {https://github.com/igerber/diff-diff},
|
|
3158
|
+
doi = {10.5281/zenodo.19646175},
|
|
3124
3159
|
license = {MIT},
|
|
3125
3160
|
}
|
|
3126
3161
|
```
|
|
3127
3162
|
|
|
3163
|
+
The DOI above is the Zenodo concept DOI — it always resolves to the latest release. To cite a specific version, look up its versioned DOI on [the Zenodo project page](https://doi.org/10.5281/zenodo.19646175).
|
|
3164
|
+
|
|
3128
3165
|
See [`CITATION.cff`](CITATION.cff) for the full citation metadata.
|
|
3129
3166
|
|
|
3167
|
+
**Note on authorship**: academic citation (`CITATION.cff`, the BibTeX above) lists individual authors with ORCIDs per scholarly convention. Package metadata surfaces (`pyproject.toml`, Sphinx docs) list "diff-diff contributors" to acknowledge the collective — see [`CONTRIBUTORS.md`](CONTRIBUTORS.md) for the full list.
|
|
3168
|
+
|
|
3130
3169
|
## License
|
|
3131
3170
|
|
|
3132
3171
|
MIT License
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
6
|
[](https://pypi.org/project/diff-diff/)
|
|
7
7
|
[](https://diff-diff.readthedocs.io/en/stable/)
|
|
8
|
+
[](https://doi.org/10.5281/zenodo.19646175)
|
|
8
9
|
|
|
9
10
|
A Python library for Difference-in-Differences (DiD) causal inference analysis with an sklearn-like API and statsmodels-style outputs.
|
|
10
11
|
|
|
@@ -92,6 +93,38 @@ Measuring campaign lift? Evaluating a product launch? diff-diff handles the caus
|
|
|
92
93
|
- **[Brand awareness survey tutorial](docs/tutorials/17_brand_awareness_survey.ipynb)** - Full example with complex survey design, brand funnel analysis, and staggered rollouts
|
|
93
94
|
- **Have BRFSS/ACS/CPS individual records?** Use [`aggregate_survey()`](docs/api/prep.rst) to roll respondent-level microdata into a geographic-period panel with inverse-variance precision weights. The returned second-stage design uses analytic weights (`aweight`), so it works directly with `DifferenceInDifferences`, `TwoWayFixedEffects`, `MultiPeriodDiD`, `SunAbraham`, `ContinuousDiD`, and `EfficientDiD` (estimators marked **Full** in the [survey support matrix](docs/choosing_estimator.rst))
|
|
94
95
|
|
|
96
|
+
### Experimental preview: `BusinessReport` and `DiagnosticReport`
|
|
97
|
+
|
|
98
|
+
diff-diff ships two preview classes, `BusinessReport` and `DiagnosticReport`, that produce plain-English output and a structured `to_dict()` schema from any fitted result. **Both are experimental in this release** — wording, verdict thresholds, and schema shape will change as the library learns from real practitioner usage. Do not anchor downstream tooling on the schema yet; the experimental flag is noted in the CHANGELOG.
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from diff_diff import CallawaySantAnna, BusinessReport
|
|
102
|
+
|
|
103
|
+
cs = CallawaySantAnna(base_period="universal").fit(
|
|
104
|
+
df, outcome="revenue", unit="store", time="month",
|
|
105
|
+
first_treat="first_treat", aggregate="event_study",
|
|
106
|
+
)
|
|
107
|
+
report = BusinessReport(
|
|
108
|
+
cs,
|
|
109
|
+
outcome_label="Revenue per store",
|
|
110
|
+
outcome_unit="$",
|
|
111
|
+
business_question="Did the loyalty program lift revenue?",
|
|
112
|
+
treatment_label="the loyalty program",
|
|
113
|
+
# Optional: pass the panel + column names so the auto-constructed
|
|
114
|
+
# DiagnosticReport can run data-dependent checks (2x2 pre-trends,
|
|
115
|
+
# Goodman-Bacon decomposition, EfficientDiD Hausman pretest).
|
|
116
|
+
# Without these the auto path still runs but skips those checks.
|
|
117
|
+
data=df,
|
|
118
|
+
outcome="revenue",
|
|
119
|
+
unit="store",
|
|
120
|
+
time="month",
|
|
121
|
+
first_treat="first_treat",
|
|
122
|
+
)
|
|
123
|
+
print(report.summary())
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
`BusinessReport` auto-constructs a `DiagnosticReport` so the summary mentions pre-trends, sensitivity, and design-effect findings in one call. Methodology (phrasing rules, verdict thresholds, schema stability) is documented in [docs/methodology/REPORTING.md](docs/methodology/REPORTING.md). Feedback on wording, applicability, and missing diagnostics is welcome — this is the part of the library most likely to evolve in the next few releases.
|
|
127
|
+
|
|
95
128
|
Already know DiD? The [academic quickstart](docs/quickstart.rst) and [estimator guide](docs/choosing_estimator.rst) cover the full technical details.
|
|
96
129
|
|
|
97
130
|
## Features
|
|
@@ -3067,14 +3100,20 @@ If you use diff-diff in your research, please cite it:
|
|
|
3067
3100
|
```bibtex
|
|
3068
3101
|
@software{diff_diff,
|
|
3069
3102
|
title = {diff-diff: Difference-in-Differences Causal Inference for Python},
|
|
3070
|
-
author = {
|
|
3103
|
+
author = {Gerber, Isaac},
|
|
3104
|
+
year = {2026},
|
|
3071
3105
|
url = {https://github.com/igerber/diff-diff},
|
|
3106
|
+
doi = {10.5281/zenodo.19646175},
|
|
3072
3107
|
license = {MIT},
|
|
3073
3108
|
}
|
|
3074
3109
|
```
|
|
3075
3110
|
|
|
3111
|
+
The DOI above is the Zenodo concept DOI — it always resolves to the latest release. To cite a specific version, look up its versioned DOI on [the Zenodo project page](https://doi.org/10.5281/zenodo.19646175).
|
|
3112
|
+
|
|
3076
3113
|
See [`CITATION.cff`](CITATION.cff) for the full citation metadata.
|
|
3077
3114
|
|
|
3115
|
+
**Note on authorship**: academic citation (`CITATION.cff`, the BibTeX above) lists individual authors with ORCIDs per scholarly convention. Package metadata surfaces (`pyproject.toml`, Sphinx docs) list "diff-diff contributors" to acknowledge the collective — see [`CONTRIBUTORS.md`](CONTRIBUTORS.md) for the full list.
|
|
3116
|
+
|
|
3078
3117
|
## License
|
|
3079
3118
|
|
|
3080
3119
|
MIT License
|
|
@@ -4,14 +4,20 @@ diff-diff: A library for Difference-in-Differences analysis.
|
|
|
4
4
|
This library provides sklearn-like estimators for causal inference
|
|
5
5
|
using the difference-in-differences methodology.
|
|
6
6
|
|
|
7
|
-
For
|
|
8
|
-
on Baker et al. (2025). After estimation, call
|
|
9
|
-
``practitioner_next_steps(results)`` for context-aware guidance on
|
|
10
|
-
remaining diagnostic steps.
|
|
7
|
+
For AI agents:
|
|
11
8
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
``get_llm_guide("
|
|
9
|
+
1. Describe your data: ``diff_diff.profile_panel(df, unit=..., time=...,
|
|
10
|
+
treatment=..., outcome=...)``
|
|
11
|
+
2. Consult the reference: ``diff_diff.get_llm_guide("autonomous")``
|
|
12
|
+
(estimator-support matrix + reasoning)
|
|
13
|
+
3. Follow the workflow: ``diff_diff.get_llm_guide("practitioner")``
|
|
14
|
+
(Baker et al. (2025) 8-step recipe)
|
|
15
|
+
4. Report results: ``diff_diff.BusinessReport(results)``
|
|
16
|
+
(structured agent-legible output)
|
|
17
|
+
|
|
18
|
+
For a comprehensive API reference call ``diff_diff.get_llm_guide("full")``;
|
|
19
|
+
``practitioner_next_steps(results)`` returns context-aware guidance after
|
|
20
|
+
any estimator's ``fit()``.
|
|
15
21
|
"""
|
|
16
22
|
|
|
17
23
|
# Import backend detection from dedicated module (avoids circular imports)
|
|
@@ -21,7 +27,6 @@ from diff_diff._backend import (
|
|
|
21
27
|
_rust_compute_robust_vcov,
|
|
22
28
|
_rust_project_simplex,
|
|
23
29
|
_rust_solve_ols,
|
|
24
|
-
_rust_synthetic_weights,
|
|
25
30
|
)
|
|
26
31
|
|
|
27
32
|
from diff_diff.bacon import (
|
|
@@ -43,6 +48,38 @@ from diff_diff.linalg import (
|
|
|
43
48
|
InferenceResult,
|
|
44
49
|
LinearRegression,
|
|
45
50
|
)
|
|
51
|
+
from diff_diff.local_linear import (
|
|
52
|
+
KERNELS,
|
|
53
|
+
BandwidthResult,
|
|
54
|
+
BiasCorrectedFit,
|
|
55
|
+
LocalLinearFit,
|
|
56
|
+
bias_corrected_local_linear,
|
|
57
|
+
epanechnikov_kernel,
|
|
58
|
+
kernel_moments,
|
|
59
|
+
local_linear_fit,
|
|
60
|
+
mse_optimal_bandwidth,
|
|
61
|
+
triangular_kernel,
|
|
62
|
+
uniform_kernel,
|
|
63
|
+
)
|
|
64
|
+
from diff_diff.had import (
|
|
65
|
+
HeterogeneousAdoptionDiD,
|
|
66
|
+
HeterogeneousAdoptionDiDEventStudyResults,
|
|
67
|
+
HeterogeneousAdoptionDiDResults,
|
|
68
|
+
)
|
|
69
|
+
from diff_diff.had_pretests import (
|
|
70
|
+
HADPretestReport,
|
|
71
|
+
QUGTestResults,
|
|
72
|
+
StuteJointResult,
|
|
73
|
+
StuteTestResults,
|
|
74
|
+
YatchewTestResults,
|
|
75
|
+
did_had_pretest_workflow,
|
|
76
|
+
joint_homogeneity_test,
|
|
77
|
+
joint_pretrends_test,
|
|
78
|
+
qug_test,
|
|
79
|
+
stute_joint_pretest,
|
|
80
|
+
stute_test,
|
|
81
|
+
yatchew_hr_test,
|
|
82
|
+
)
|
|
46
83
|
from diff_diff.estimators import (
|
|
47
84
|
DifferenceInDifferences,
|
|
48
85
|
MultiPeriodDiD,
|
|
@@ -202,7 +239,18 @@ from diff_diff.visualization import (
|
|
|
202
239
|
plot_synth_weights,
|
|
203
240
|
)
|
|
204
241
|
from diff_diff.practitioner import practitioner_next_steps
|
|
242
|
+
from diff_diff.business_report import (
|
|
243
|
+
BUSINESS_REPORT_SCHEMA_VERSION,
|
|
244
|
+
BusinessContext,
|
|
245
|
+
BusinessReport,
|
|
246
|
+
)
|
|
247
|
+
from diff_diff.diagnostic_report import (
|
|
248
|
+
DIAGNOSTIC_REPORT_SCHEMA_VERSION,
|
|
249
|
+
DiagnosticReport,
|
|
250
|
+
DiagnosticReportResults,
|
|
251
|
+
)
|
|
205
252
|
from diff_diff._guides_api import get_llm_guide
|
|
253
|
+
from diff_diff.profile import Alert, PanelProfile, profile_panel
|
|
206
254
|
from diff_diff.datasets import (
|
|
207
255
|
clear_cache,
|
|
208
256
|
list_datasets,
|
|
@@ -230,8 +278,9 @@ Bacon = BaconDecomposition
|
|
|
230
278
|
EDiD = EfficientDiD
|
|
231
279
|
ETWFE = WooldridgeDiD
|
|
232
280
|
DCDH = ChaisemartinDHaultfoeuille
|
|
281
|
+
HAD = HeterogeneousAdoptionDiD
|
|
233
282
|
|
|
234
|
-
__version__ = "3.
|
|
283
|
+
__version__ = "3.3.0"
|
|
235
284
|
__all__ = [
|
|
236
285
|
# Estimators
|
|
237
286
|
"DifferenceInDifferences",
|
|
@@ -395,6 +444,40 @@ __all__ = [
|
|
|
395
444
|
# Linear algebra helpers
|
|
396
445
|
"LinearRegression",
|
|
397
446
|
"InferenceResult",
|
|
447
|
+
# Local-linear regression infrastructure (Phase 1a for HeterogeneousAdoptionDiD)
|
|
448
|
+
"KERNELS",
|
|
449
|
+
"LocalLinearFit",
|
|
450
|
+
"epanechnikov_kernel",
|
|
451
|
+
"kernel_moments",
|
|
452
|
+
"local_linear_fit",
|
|
453
|
+
"triangular_kernel",
|
|
454
|
+
"uniform_kernel",
|
|
455
|
+
# MSE-optimal bandwidth selector (Phase 1b for HeterogeneousAdoptionDiD)
|
|
456
|
+
"BandwidthResult",
|
|
457
|
+
"mse_optimal_bandwidth",
|
|
458
|
+
# Bias-corrected local-linear (Phase 1c for HeterogeneousAdoptionDiD)
|
|
459
|
+
"BiasCorrectedFit",
|
|
460
|
+
"bias_corrected_local_linear",
|
|
461
|
+
# HeterogeneousAdoptionDiD (Phase 2a single-period, Phase 2b event study)
|
|
462
|
+
"HeterogeneousAdoptionDiD",
|
|
463
|
+
"HeterogeneousAdoptionDiDResults",
|
|
464
|
+
"HeterogeneousAdoptionDiDEventStudyResults",
|
|
465
|
+
"HAD",
|
|
466
|
+
# HeterogeneousAdoptionDiD pre-test diagnostics (Phase 3)
|
|
467
|
+
"qug_test",
|
|
468
|
+
"stute_test",
|
|
469
|
+
"yatchew_hr_test",
|
|
470
|
+
"did_had_pretest_workflow",
|
|
471
|
+
"QUGTestResults",
|
|
472
|
+
"StuteTestResults",
|
|
473
|
+
"YatchewTestResults",
|
|
474
|
+
"HADPretestReport",
|
|
475
|
+
# HAD joint pre-tests (Phase 3 follow-up) — multi-period event-study
|
|
476
|
+
# workflow dispatch via did_had_pretest_workflow(aggregate="event_study")
|
|
477
|
+
"stute_joint_pretest",
|
|
478
|
+
"joint_pretrends_test",
|
|
479
|
+
"joint_homogeneity_test",
|
|
480
|
+
"StuteJointResult",
|
|
398
481
|
# Datasets
|
|
399
482
|
"load_card_krueger",
|
|
400
483
|
"load_castle_doctrine",
|
|
@@ -405,6 +488,16 @@ __all__ = [
|
|
|
405
488
|
"clear_cache",
|
|
406
489
|
# Practitioner guidance
|
|
407
490
|
"practitioner_next_steps",
|
|
491
|
+
"BusinessReport",
|
|
492
|
+
"BusinessContext",
|
|
493
|
+
"BUSINESS_REPORT_SCHEMA_VERSION",
|
|
494
|
+
"DiagnosticReport",
|
|
495
|
+
"DiagnosticReportResults",
|
|
496
|
+
"DIAGNOSTIC_REPORT_SCHEMA_VERSION",
|
|
497
|
+
# Panel profiling (agent-facing pre-fit describe utility)
|
|
498
|
+
"profile_panel",
|
|
499
|
+
"PanelProfile",
|
|
500
|
+
"Alert",
|
|
408
501
|
# LLM guide accessor
|
|
409
502
|
"get_llm_guide",
|
|
410
503
|
]
|
|
@@ -19,7 +19,6 @@ _backend_env = os.environ.get("DIFF_DIFF_BACKEND", "auto").lower()
|
|
|
19
19
|
try:
|
|
20
20
|
from diff_diff._rust_backend import (
|
|
21
21
|
generate_bootstrap_weights_batch as _rust_bootstrap_weights,
|
|
22
|
-
compute_synthetic_weights as _rust_synthetic_weights,
|
|
23
22
|
project_simplex as _rust_project_simplex,
|
|
24
23
|
solve_ols as _rust_solve_ols,
|
|
25
24
|
compute_robust_vcov as _rust_compute_robust_vcov,
|
|
@@ -35,6 +34,9 @@ try:
|
|
|
35
34
|
compute_time_weights as _rust_compute_time_weights,
|
|
36
35
|
compute_noise_level as _rust_compute_noise_level,
|
|
37
36
|
sc_weight_fw as _rust_sc_weight_fw,
|
|
37
|
+
sc_weight_fw_with_convergence as _rust_sc_weight_fw_with_convergence,
|
|
38
|
+
sc_weight_fw_weighted as _rust_sc_weight_fw_weighted,
|
|
39
|
+
sc_weight_fw_weighted_with_convergence as _rust_sc_weight_fw_weighted_with_convergence,
|
|
38
40
|
# Diagnostics
|
|
39
41
|
rust_backend_info as _rust_backend_info,
|
|
40
42
|
)
|
|
@@ -43,7 +45,6 @@ try:
|
|
|
43
45
|
except ImportError:
|
|
44
46
|
_rust_available = False
|
|
45
47
|
_rust_bootstrap_weights = None
|
|
46
|
-
_rust_synthetic_weights = None
|
|
47
48
|
_rust_project_simplex = None
|
|
48
49
|
_rust_solve_ols = None
|
|
49
50
|
_rust_compute_robust_vcov = None
|
|
@@ -59,6 +60,9 @@ except ImportError:
|
|
|
59
60
|
_rust_compute_time_weights = None
|
|
60
61
|
_rust_compute_noise_level = None
|
|
61
62
|
_rust_sc_weight_fw = None
|
|
63
|
+
_rust_sc_weight_fw_with_convergence = None
|
|
64
|
+
_rust_sc_weight_fw_weighted = None
|
|
65
|
+
_rust_sc_weight_fw_weighted_with_convergence = None
|
|
62
66
|
_rust_backend_info = None
|
|
63
67
|
|
|
64
68
|
# Determine final backend based on environment variable and availability
|
|
@@ -66,7 +70,6 @@ if _backend_env == "python":
|
|
|
66
70
|
# Force pure Python mode - disable Rust even if available
|
|
67
71
|
HAS_RUST_BACKEND = False
|
|
68
72
|
_rust_bootstrap_weights = None
|
|
69
|
-
_rust_synthetic_weights = None
|
|
70
73
|
_rust_project_simplex = None
|
|
71
74
|
_rust_solve_ols = None
|
|
72
75
|
_rust_compute_robust_vcov = None
|
|
@@ -82,6 +85,9 @@ if _backend_env == "python":
|
|
|
82
85
|
_rust_compute_time_weights = None
|
|
83
86
|
_rust_compute_noise_level = None
|
|
84
87
|
_rust_sc_weight_fw = None
|
|
88
|
+
_rust_sc_weight_fw_with_convergence = None
|
|
89
|
+
_rust_sc_weight_fw_weighted = None
|
|
90
|
+
_rust_sc_weight_fw_weighted_with_convergence = None
|
|
85
91
|
_rust_backend_info = None
|
|
86
92
|
elif _backend_env == "rust":
|
|
87
93
|
# Force Rust mode - fail if not available
|
|
@@ -115,7 +121,6 @@ __all__ = [
|
|
|
115
121
|
"HAS_RUST_BACKEND",
|
|
116
122
|
"rust_backend_info",
|
|
117
123
|
"_rust_bootstrap_weights",
|
|
118
|
-
"_rust_synthetic_weights",
|
|
119
124
|
"_rust_project_simplex",
|
|
120
125
|
"_rust_solve_ols",
|
|
121
126
|
"_rust_compute_robust_vcov",
|
|
@@ -131,4 +136,7 @@ __all__ = [
|
|
|
131
136
|
"_rust_compute_time_weights",
|
|
132
137
|
"_rust_compute_noise_level",
|
|
133
138
|
"_rust_sc_weight_fw",
|
|
139
|
+
"_rust_sc_weight_fw_with_convergence",
|
|
140
|
+
"_rust_sc_weight_fw_weighted",
|
|
141
|
+
"_rust_sc_weight_fw_weighted_with_convergence",
|
|
134
142
|
]
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"""Runtime accessor for bundled LLM guide files."""
|
|
2
|
+
|
|
2
3
|
from __future__ import annotations
|
|
3
4
|
|
|
4
5
|
from importlib.resources import files
|
|
@@ -7,6 +8,7 @@ _VARIANT_TO_FILE = {
|
|
|
7
8
|
"concise": "llms.txt",
|
|
8
9
|
"full": "llms-full.txt",
|
|
9
10
|
"practitioner": "llms-practitioner.txt",
|
|
11
|
+
"autonomous": "llms-autonomous.txt",
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
|
|
@@ -21,6 +23,10 @@ def get_llm_guide(variant: str = "concise") -> str:
|
|
|
21
23
|
- ``"concise"`` -- compact API reference (llms.txt)
|
|
22
24
|
- ``"full"`` -- complete API documentation (llms-full.txt)
|
|
23
25
|
- ``"practitioner"`` -- 8-step practitioner workflow (llms-practitioner.txt)
|
|
26
|
+
- ``"autonomous"`` -- reference guide for AI-agent use: estimator-support
|
|
27
|
+
matrix, per-design-feature reasoning, post-fit validation index, and
|
|
28
|
+
BR/DR schema (llms-autonomous.txt). Pair with
|
|
29
|
+
:func:`diff_diff.profile_panel` for pre-fit data description.
|
|
24
30
|
|
|
25
31
|
Returns
|
|
26
32
|
-------
|
|
@@ -42,7 +48,5 @@ def get_llm_guide(variant: str = "concise") -> str:
|
|
|
42
48
|
filename = _VARIANT_TO_FILE[variant]
|
|
43
49
|
except (KeyError, TypeError):
|
|
44
50
|
valid = ", ".join(repr(k) for k in _VARIANT_TO_FILE)
|
|
45
|
-
raise ValueError(
|
|
46
|
-
f"Unknown guide variant {variant!r}. Valid options: {valid}."
|
|
47
|
-
) from None
|
|
51
|
+
raise ValueError(f"Unknown guide variant {variant!r}. Valid options: {valid}.") from None
|
|
48
52
|
return files("diff_diff.guides").joinpath(filename).read_text(encoding="utf-8")
|