feat(continuous-did): lowest-dose-as-control (control_group="lowest_dose", Remark 3.1)#623
Conversation
…ose", Remark 3.1) Implement CGBS 2024 Remark 3.1 for settings with no untreated group (P(D=0)=0): the lowest-dose group d_L becomes the comparison and the estimand is ATT(d) - ATT(d_L) (with ATT(d_L)=0 the omitted reference). Mechanically a control-group swap -- the D=0 control pool is replaced by the d_L group, so the linear influence-function / bootstrap / event-study / survey machinery is reused unchanged (ee_control already carries the reference-group variance; no new SE plumbing). Both treatment_type= "discrete" and the continuous B-spline path are supported; the discrete ACRT backward-difference reference shifts from 0 to d_L via a new `base` param on saturated_derivative_design_matrix. The continuous path requires a genuine mass point at the minimum dose (P(D=d_L)>0). Results gain a reference_dose field (= d_L); n_treated/n_control metadata gated on the lowest_dose path (byte-stable elsewhere). Fail-closed guards: never-treated units present, a singleton d_L, no treated dose above d_L, dvals <= d_L, or a survey subpopulation zeroing the d_L group all raise; multi-cohort and covariates x lowest_dose raise NotImplementedError (deferred). The never_treated / not_yet_treated / continuous default paths are numerically unchanged. Validation (R-free, in CI): an exact d_L->0 equivalence anchor (relabelling a never_treated panel's D=0 group as a tiny common dose reproduces the never_treated ATT and SE exactly), discrete hand-calc of ATT/ACRT/overall/overall_acrt and the per-level 2x2 SE (~1e-10), continuous mass-point DGP recovery, analytical-vs-bootstrap SE agreement, a pre-period placebo, event-study composition, and MC coverage. Closes TODO Actionable (c) for the CGBS-2024 ContinuousDiD extensions. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LHDijzf8zHXk5T8ahS2mKi
…ion-tree routing Address local review P3s: a direct regression test for the fail-closed guard when a survey subpopulation zeroes the entire lowest-dose reference group, and reword the "Universal Rollout" decision-tree recommendation to make ContinuousDiD(control_group="lowest_dose") vs HeterogeneousAdoptionDiD conditional on whether a lowest-dose mass point exists. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LHDijzf8zHXk5T8ahS2mKi
PR Review: ContinuousDiD
|
…ey weighting (CI P1) The raw lowest-dose mass-point guard (>= 2 units at d_L) runs before survey weights. A subpopulation/domain that keeps exactly one positive-weight d_L unit slipped through the survey guard (which only rejected an all-zero d_L group): with one positive-weight reference unit, mu_0 equals that unit's dY so its ee_control = w*(dY - mu_0) = 0 and the reference contributes zero control-side variance, yielding a finite but effectively unidentified SE. Enforce the same effective >= 2 positive-weight requirement in the survey guard (np.count_nonzero(dL_w > 0) >= 2). Add a regression test for the effective-singleton case; update the zeroed-group test's message match and REGISTRY Note #7 / CHANGELOG wording. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LHDijzf8zHXk5T8ahS2mKi
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment✅ Looks good — no unmitigated P0/P1 findings. Executive Summary
MethodologyNo findings. The affected method is The prior survey effective-singleton issue is fixed at Code QualityNo findings.
PerformanceNo findings. MaintainabilityNo findings. The Tech DebtNo blocking findings. P3 informational: multi-cohort SecurityNo findings. Documentation/TestsNo findings. The new tests cover API propagation, fail-closed guards, event-study composition, PYTHONDONTWRITEBYTECODE=1 pytest -q tests/test_continuous_did.py::TestLowestDoseAPI tests/test_methodology_continuous_did.py::TestLowestDose -p no:cacheproviderbut failed because |
Summary
control_group="lowest_dose") forContinuousDiD: when there is no untreated group (P(D=0)=0), the lowest-dose groupd_Lbecomes the comparison and the estimand isATT(d) - ATT(d_L)(withATT(d_L)=0the omitted reference). Mechanically a control-group swap — the D=0 control pool is replaced by thed_Lgroup, so the linear influence-function / bootstrap / event-study / survey machinery is reused unchanged (ee_controlalready carries the reference-group variance; no new SE plumbing). Bothtreatment_type="discrete"and the continuous B-spline path are supported; the discrete ACRT backward-difference reference shifts from0tod_L(ACRT(d_1)=ATT(d_1)/(d_1-d_L)) via a newbaseparam onsaturated_derivative_design_matrix. The continuous path requires a genuine mass point at the minimum dose (P(D=d_L)>0). Results gain areference_dosefield.d_L, no treated dose aboved_L,dvals <= d_L, or a survey subpopulation zeroing thed_Lgroup all raise; multi-cohort andcovariates=×lowest_doseraiseNotImplementedError(deferred). Thenever_treated/not_yet_treated/ continuous default paths are numerically unchanged.ContinuousDiDextensions; sweeps stale "requires never-treated / Remark 3.1 not implemented" capability claims across the guides, profiler, and practitioner routing.Methodology references
ContinuousDiDlowest-dose-as-control (Remark 3.1)contdidv0.1.0, which does not implement Remark 3.1 (no external R anchor). Documented asdocs/methodology/REGISTRY.md§ ContinuousDiD Note Prepare v0.2.0 release #7. Multi-cohortlowest_dose(needs a within-cohort reference + support-aware cross-cohort aggregation) andcovariates=×lowest_dose(conditional-PT-relative-to-d_Lestimand) are deferred, fail-closed, and tracked inTODO.md.Validation
tests/test_methodology_continuous_did.py::TestLowestDose(exactd_L→0equivalence anchor — relabelling anever_treatedpanel's D=0 group as a tiny common dose reproduces thenever_treatedATT and SE exactly; discrete hand-calc of ATT/ACRT/overall_att/overall_acrtand the per-level 2×2 SE at ~1e-10; continuous mass-point DGP recovery; analytical-vs-bootstrap SE agreement; pre-period placebo; MC coverage) andtests/test_continuous_did.py::TestLowestDoseAPI(transactional params, all fail-closed guards incl. the survey-zeroedd_Lgroup, threshold consistency, metadata/reference_dose, event-study, idempotent refit). Full existing ContinuousDiD suites pass unchanged (byte-stablenever_treated/continuous paths).Security / privacy
🤖 Generated with Claude Code
https://claude.ai/code/session_01LHDijzf8zHXk5T8ahS2mKi