feat: add ChangesInChanges (CiC) + QDiD distributional DiD estimators with qte golden parity#682
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011hismLBFcUbUzvDRq8ruWb
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011hismLBFcUbUzvDRq8ruWb
bd49485 to
06e9cfb
Compare
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment: ✅ Looks goodExecutive Summary
Methodology
No P0/P1 methodology mismatch found. Code Quality
Performance
Maintainability
Tech Debt
Security
Documentation/Tests
|
Athey & Imbens (2006) nonlinear DiD for the 2x2 design with continuous
outcomes: ChangesInChanges (alias CiC) recovers the treated group's full
counterfactual outcome distribution and quantile treatment effects; QDiD
is the paper's additive quantile-DiD comparison estimator.
- Point estimation matches R qte 1.3.1 exactly: CiC via an exact port of
R quantile.default type-1 arithmetic incl. fuzz (bit-exact golden
parity); QDiD via qte's type-7 additive form (REGISTRY Note documents
the finite-sample deviation from the paper's k^QDID transformation)
- Bootstrap-only inference per qte's schemes (panel unit-block / RCS
pooled resample; seedable; n_bootstrap=200; replicate-SD SEs, normal
CIs, sup-t uniform bands at qte's fixed 95% level)
- Diagnostics: eq.-17 interior-range guard (NaN inference outside),
support-violation / heavy-ties / QDiD-non-monotonicity warnings;
joint-NaN inference contract via safe_inference(_batch)
- Golden fixtures: benchmarks/R/generate_qte_golden.R (qte pinned 1.3.1
in requirements.R) -> benchmarks/data/qte_golden.json; parity tests
cover 4 scenarios x {CiC,QDiD} x {panel,RCS} at atol=1e-10, type-1
micro-fixtures at atol=0, seeded-R SE block statistically
- Docs: REGISTRY entry + cross-reference rows, api rst, references,
llms(-full).txt, README/choosing/r_comparison/practitioner catalogs,
estimator count 20 -> 22 (incl. paper.md + new Athey2006 bib entry),
TODO deferral rows (covariates/bounds/analytical-SE/staggered/ATC +
tutorial and practitioner-handler follow-ups)
Deferred and documented per the merged PR-A review stack (#678):
covariates, discrete-outcome bounds, analytical SEs, staggered designs,
treatment-on-controls.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011hismLBFcUbUzvDRq8ruWb
…dation - NaN-ify invalid per-quantile SEs (non-finite or <= 0, e.g. zero-spread degenerate bootstrap columns) before storing quantile_effects, so the stored se honors the joint-NaN contract and uniform_bands() cannot emit finite zero-width bands while pointwise inference is NaN; degenerate constant-cell regression test - Pin _DEFAULT_QUANTILES to R's exact seq(0.05, 0.95, 0.05) doubles (np.arange differs at 5 of 19 indices by one ulp; type-1 order-statistic selection is ulp-sensitive); locked against the fixture probs plus a quantiles=None end-to-end golden parity test - Reject non-finite (inf/-inf) outcome values with a counting ValueError after the NaN drop (dropna keeps inf); +/-inf tests - get_params(deep=True) sklearn-clone-compatible signature on both classes (HAD precedent) + deep-flag equality and strengthened clone tests - Explicit-interaction formulas derive (treatment, time) roles from the main-effect order so 'treated:post' and 'post:treated' are identical (CiC/QDiD are not symmetric in treatment/time); order-invariance test - Add the qdid_rcs seeded SE block to the golden generator and SE parity parametrization (fixture regenerated; point values unchanged) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011hismLBFcUbUzvDRq8ruWb
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011hismLBFcUbUzvDRq8ruWb
06e9cfb to
9cb789c
Compare
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment: ✅ Looks goodExecutive Summary
Methodology
No P0/P1 methodology mismatch found. Code Quality
Performance
Maintainability
Tech Debt
Security
Documentation/Tests
|
Summary
qteparity.ChangesInChanges(aliasCiC): Athey-Imbens (2006) nonlinear DiD - counterfactual distributionF_10(F_00^{-1}(F_01(y)))(Theorem 3.1), plug-in ATT (eq. 36), quantile treatment effects (eq. 18) on a default 19-point grid pinned to R's exactseq(0.05, 0.95, 0.05)doubles. The empirical inverse is an exact port of Rquantile.defaulttype-1 arithmetic including its fuzz handling - the paper's eq. (35)/(A.1) ceiling-order-statistic convention.QDiD: the paper's quantile-DiD comparison estimator, matchingqte::QDiD()exactly (additive type-7 form; the finite-sample deviation from the paper's k^QDID transformation is documented with a labeled REGISTRY Note; population-equivalent, locked by a large-N test vsDifferenceInDifferences).n_bootstrap=200default; replicate-SD SEs, normal CIs, sup-t uniform bands at qte's fixed 95% level with the IQR-scaled critical value). Joint-NaN contract viasafe_inference(_batch)incl. degenerate zero-spread columns; >= 50%-finite replicate gate.makeBalancedPanel, duplicate and time-varying-group errors), non-finite outcome rejection.benchmarks/R/generate_qte_golden.R(qte pinned 1.3.1 inrequirements.R) -> committedbenchmarks/data/qte_golden.json. 4 scenarios (normal/lognormal/small-n synthetic + qte's lalonde with heavy ties) x {CiC, QDiD} x {panel, RCS} at atol=1e-10 - CiC quantile vectors are bit-exact vs R in every scenario; type-1 micro-fixtures (incl. ECDF-composed and near-integer adversarial probs) at atol=0; seeded-R SE blocks (999 iters) compared statistically per repo convention.docs/api/changes_in_changes.rst, references.rst, llms.txt + llms-full.txt entries, README/choosing_estimator/r_comparison/practitioner catalogs, estimator count 20 -> 22 swept across all surfaces (incl. paper.md + new Athey2006 bib entry), TODO deferral rows.Methodology references (required if estimator / math changes)
docs/methodology/papers/athey-imbens-2006-review.md). Reference implementation: Rqte1.3.1 (Callaway),CiC()/QDiD().alpha(qte parity); (4) the 10% duplicate-share ties heuristic is a library operationalization of the continuity assumption.Validation
tests/test_changes_in_changes.py(unit/edge: validation, transactional set_params, sklearn clone, panel hygiene, NaN contracts incl. degenerate bootstrap, seed determinism, all warnings),tests/test_methodology_changes_in_changes.py(eq. A.2 sandwich + Lemma A.1 Galois identities, hand-calculated micro-example, QDiDDiD and CiCDiD population checks, exact monotone-transform equivariance, heterogeneous-QTE recovery),tests/test_changes_in_changes_parity.py(golden point/micro/SE parity with skip-if-absent guard + version pin),tests/test_aliases.py(CiC alias). 188 passing locally (+ full meta-test suite: aliases, agent discoverability, doc-deps integrity, doc snippets).Security / privacy
Generated with Claude Code
🤖 Generated with Claude Code
https://claude.ai/code/session_011hismLBFcUbUzvDRq8ruWb