Skip to content

Add continuous DiD tutorial#178

Merged
igerber merged 6 commits intomainfrom
continuous-did-tutorial
Feb 22, 2026
Merged

Add continuous DiD tutorial#178
igerber merged 6 commits intomainfrom
continuous-did-tutorial

Conversation

@igerber
Copy link
Owner

@igerber igerber commented Feb 22, 2026

Summary

  • Add tutorial notebook docs/tutorials/14_continuous_did.ipynb covering the ContinuousDiD estimator (Callaway, Goodman-Bacon & Sant'Anna 2024)
  • Framed around a job training program example (hours of training → earnings)
  • 31 cells (15 markdown, 16 code), ~29 KB

Tutorial sections

  1. Why continuous treatment needs special methods (binarization loss, TWFE bias, ATT/ACRT estimands)
  2. Data setup with generate_continuous_did_data()
  3. Basic estimation with ContinuousDiD
  4. Dose-response curves (ATT(d) and ACRT(d)) with confidence bands
  5. Event study diagnostics (multi-cohort data, bootstrap CIs)
  6. Advanced features: B-spline configs, control groups, analytical vs bootstrap SEs
  7. Comparison to binary DiD (CallawaySantAnna) showing information loss from binarizing
  8. Results export (to_dataframe at dose-response and group-time levels)
  9. Summary with parameter reference table and citation

Methodology references (required if estimator / math changes)

  • N/A — no methodology changes, tutorial only

Validation

  • Tests added/updated: No test changes (tutorial notebook only)
  • Notebook evidence: Notebook executes end-to-end without errors. ATT_glob bias = -0.13 (< 0.5 threshold), ACRT_glob bias = 0.15 (< 0.3 threshold). Binary vs continuous ATT match (4.5468). All matplotlib guards present.

Security / privacy

  • Confirm no secrets/PII in this PR: Yes

Generated with Claude Code

@github-actions
Copy link

Overall Assessment
⚠️ Needs changes

Executive Summary

  • P1 Methodology: Identification claims for PT vs SPT conflict with the Methodology Registry/continuous-did.md; update the tutorial to distinguish ATT(d|d)/ATT^{loc} from ATT^{glob}/ACRT^{glob} and to state which require SPT. (ContinuousDiD)
  • P2 Methodology/Docs: The tutorial attributes ATT_glob differences to B‑spline estimation, but ATT_glob is computed via binarized mean differences; update the explanation.
  • P3 Docs: “Event study requires multiple cohorts” is too strong; single‑cohort event-time effects are still defined (though less informative). Soften wording.

Methodology

  • P1 Impact: The tutorial says standard PT identifies the binarized ATT and that ATT_glob/ACRT_glob remain valid under standard PT. This contradicts the registry and docs/methodology/continuous-did.md, which state PT identifies ATT(d|d) and ATT^{loc} only; SPT is needed for ATT(d), ACRT(d), ACRT^{glob}, and cross‑dose interpretation (and for ATT_glob to be interpreted as global). Concrete fix: revise the identifying assumptions section and the dose-response interpretation to align with PT vs SPT identification and clarify ATT_glob’s interpretation under PT vs SPT. References: docs/tutorials/14_continuous_did.ipynb:L89-L97, docs/tutorials/14_continuous_did.ipynb:L301-L306.
  • P2 Impact: The tutorial states ATT_glob differences arise because ContinuousDiD uses B‑splines, but ATT_glob is computed as a binarized mean difference; B‑splines are for ATT(d)/ACRT(d). This misstates estimator behavior and could mislead comparisons to Callaway-Sant’Anna. Concrete fix: replace with an explanation that differences may come from weighting/aggregation, control group/base period choices, or sampling noise, not spline smoothing. Reference: docs/tutorials/14_continuous_did.ipynb:L566-L571.

Code Quality
No findings.

Performance
No findings.

Maintainability
No findings.

Tech Debt
No findings.

Security
No findings.

Documentation/Tests

  • P3 Impact: “Event study requires data with multiple cohorts” is overly strict; a single cohort still yields event-time estimates (though diagnostics are weaker). Concrete fix: soften to “works best with multiple cohorts” or explain the tradeoff. Reference: docs/tutorials/14_continuous_did.ipynb:L314-L318.

igerber added a commit that referenced this pull request Feb 22, 2026
Address PR #178 review feedback: correct PT vs SPT identification
claims, fix dose-response interpretation caveat, fix ATT_glob
difference explanation, add assumption caveat to global parameters,
and soften event study cohort requirement.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@igerber
Copy link
Owner Author

igerber commented Feb 22, 2026

/ai-review

@github-actions
Copy link

🔁 AI review rerun (requested by @igerber)

Head SHA: edf4a4d0f9b135fda954c48c4c9555b41f0ae7ff


Overall assessment: ⚠️ Needs changes

Executive summary

  • The new tutorial’s parallel trends discussion conflicts with the Methodology Registry’s Strong Parallel Trends definition and identification scope for ContinuousDiD.
  • The tutorial’s ATT(d) definition implies conditioning on D=d, which disagrees with the Registry’s D>0 definition and the estimator’s documented target parameters.
  • Doc-only change; no code paths, performance, or security issues observed.

Methodology

  • P1 | Impact: The tutorial labels “standard PT” as “untreated potential outcomes evolve identically regardless of treatment dose,” which matches the Registry’s Strong Parallel Trends (SPT) definition, then introduces an extra “no selection into dose based on gains” condition as “strong PT.” This conflicts with the Registry and could mislead users about which assumptions identify the dose-response curve and ACRT parameters. | Fix: Align the assumption labels and statements with the Registry’s SPT definition and identification scope; either remove the extra “selection into dose based on gains” claim or cite and define it explicitly as an additional assumption beyond SPT. | Location: docs/tutorials/14_continuous_did.ipynb:L94-L98; Registry: docs/methodology/REGISTRY.md:L404-L417
  • P1 | Impact: The tutorial defines ATT(d) as “total earnings gain from d hours of training vs. no training,” and later says the estimator identifies effects for units who received dose d. The Registry defines ATT(d) = E[Y_t(d) - Y_t(0) | D > 0] (treated population, not conditional on D=d). This mismatch can cause incorrect interpretation of the estimand. | Fix: Rephrase ATT(d) to match the Registry’s definition and clarify the target population; update the table and related narrative to avoid conditioning on D=d unless that is explicitly intended and supported. | Location: docs/tutorials/14_continuous_did.ipynb:L75-L78,L94-L98; Registry: docs/methodology/REGISTRY.md:L413-L417

Code Quality

  • No findings.

Performance

  • No findings.

Maintainability

  • No findings.

Tech Debt

  • No findings.

Security

  • No findings.

Documentation/Tests

  • No findings.

igerber and others added 3 commits February 22, 2026 12:23
Tutorial covering the ContinuousDiD estimator (Callaway, Goodman-Bacon &
Sant'Anna 2024) with a job training program example. Includes dose-response
curves, event study diagnostics, B-spline configuration, control group
comparison, bootstrap inference, and a binary DiD comparison showing
information loss from binarizing continuous treatment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Address PR #178 review feedback: correct PT vs SPT identification
claims, fix dose-response interpretation caveat, fix ATT_glob
difference explanation, add assumption caveat to global parameters,
and soften event study cohort requirement.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update REGISTRY.md ContinuousDiD section to document both standard PT
and strong PT assumptions (matching continuous-did.md and CGBS 2024
Assumptions 1-2). Annotate each target parameter with which assumption
it requires. Add assumption requirement notes to tutorial estimand table.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@igerber igerber force-pushed the continuous-did-tutorial branch from edf4a4d to 75a6282 Compare February 22, 2026 17:45
@igerber
Copy link
Owner Author

igerber commented Feb 22, 2026

/ai-review

@github-actions
Copy link

🔁 AI review rerun (requested by @igerber)

Head SHA: 75a6282db9f34022caea9b1a7285fce88c7a2cd4


Overall assessment: ⚠️ Needs changes

Executive summary

  • P1: ATT^{glob}/ATT^{loc} identification and naming are inconsistent between the updated Methodology Registry, the core methodology write‑up, and the new tutorial; this can misstate PT vs SPT requirements for users.
  • Documentation-only PR; no code-path or edge-case impacts observed.
  • Tests not run (docs-only change).

Methodology
Affected method: ContinuousDiD (documentation/assumptions).

  • P1 Impact: The registry now labels ATT^{glob} as the binarized DiD identified under PT, while docs/methodology/continuous-did.md defines ATT^{glob} as the global average of ATT(d) (SPT) and ties the binarized formula to SPT. The in-code docstring also describes overall_att as “Binarized overall ATT^{glob},” aligning with the registry but not with the methodology doc. The new tutorial uses the binarized/“PT‑valid” interpretation. This inconsistency can lead users to apply the wrong identifying assumptions or misinterpret ATT_glob. Concrete fix: Reconcile terminology by either (a) updating docs/methodology/REGISTRY.md to label the PT‑identified binarized effect as ATT^{loc} and reserving ATT^{glob} for the SPT‑identified global summary, or (b) updating docs/methodology/continuous-did.md (and the tutorial) to explicitly map the library’s ATT_glob to CGBS’s ATT^{loc}, noting it equals ATT^{glob} only under SPT. Refs: docs/methodology/REGISTRY.md:L408-L429, docs/methodology/continuous-did.md:L119-L126, docs/methodology/continuous-did.md:L245-L248, diff_diff/continuous_did_results.py:L92-L95, docs/tutorials/14_continuous_did.ipynb:L75-L80.

Code Quality
No findings.

Performance
No findings.

Maintainability
No findings.

Tech Debt
No findings.

Security
No findings.

Documentation/Tests
No findings.

The binarized DiD identifies ATT^{loc} under PT, not ATT^{glob}.
ATT^{glob} = ATT^{loc} only under SPT. Update REGISTRY.md to list
both parameters with correct assumption labels, fix overall_att
docstring in continuous_did_results.py, and use correct ATT_loc/
ATT_glob terminology in the tutorial's dose-response interpretation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@igerber
Copy link
Owner Author

igerber commented Feb 22, 2026

/ai-review

@github-actions
Copy link

🔁 AI review rerun (requested by @igerber)

Head SHA: 8bf8839e9ba175348daa413cbccdd3b0809189ad


Overall Assessment: ⚠️ Needs changes

Executive Summary

  • The new tutorial uses ATT_glob to mean the binarized ATT under standard PT, which conflicts with the updated Methodology Registry’s ATT^{loc} vs ATT^{glob} distinction.
  • The “Comparison to Binary DiD” section repeats the same labeling issue and should explicitly say the binarized ATT (ATT^{loc}) is what’s being compared unless SPT holds.
  • The docstring and Registry updates themselves align with continuous-did.md; the main fixes are tutorial terminology and assumption clarity.

Methodology

  • P1 Mismatch between tutorial terminology and the Methodology Registry for identification under PT/SPT. Impact: Users may infer that ATT_glob is identified under standard PT as the global dose-response average, which is only true under SPT; this can lead to incorrect causal interpretation. Fix: Update the tutorial to use ATT^{loc} (binarized ATT) in the estimand table and narrative, or explicitly state “reported as ATT_glob/overall_att in the API; equals ATT^{loc} under PT and ATT^{glob} only under SPT,” and align the comparison-to-binary section with that wording. Affected locations: docs/tutorials/14_continuous_did.ipynb:L75-L80, docs/tutorials/14_continuous_did.ipynb:L229-L233, docs/tutorials/14_continuous_did.ipynb:L573-L573 vs registry definitions in docs/methodology/REGISTRY.md:L408-L430.

Code Quality

  • No issues found in the changed code.

Performance

  • No issues found.

Maintainability

  • No issues found.

Tech Debt

  • No issues found.

Security

  • No issues found.

Documentation/Tests

  • No additional issues found beyond the methodology terminology mismatch noted above.

Update tutorial estimand table, global parameter interpretation, and
binary comparison sections to clarify that the API's ATT_glob/overall_att
identifies ATT_loc under standard PT and equals ATT_glob only under SPT.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@igerber
Copy link
Owner Author

igerber commented Feb 22, 2026

/ai-review

@github-actions
Copy link

🔁 AI review rerun (requested by @igerber)

Head SHA: e1c061683d82dd13b95891f287db9a5875304f83


Overall assessment: ⚠️ Needs changes

Executive summary

  • P1: Tutorial misstates the binarized ATT as a “simple mean difference,” but the implementation uses group/time weighting; this mischaracterizes weighting/aggregation.
  • Methodology Registry updates align with docs/methodology/continuous-did.md; no conflicts found there.
  • No estimator/inference code changes; edge-case checklist not triggered.
  • No tests run/added (doc-only change).

Methodology

  • P1: The tutorial claims both estimators compute the binarized ATT as a simple mean difference. In the implementation, ContinuousDiD aggregates ATT(g,t) with group‑proportional weights (and base period/controls affect weights), and CallawaySantAnna also uses its own weighting scheme. This statement mischaracterizes weighting and can mislead users about why results can differ. Fix: Reword to say both estimators aggregate ATT(g,t) using group-time weights and remove the “simple mean difference” claim; keep the note that differences can arise from weighting/aggregation choices. Location: docs/tutorials/14_continuous_did.ipynb:L567-L571.

Code Quality

  • No findings.

Performance

  • No findings.

Maintainability

  • No findings.

Tech Debt

  • No findings.

Security

  • No findings.

Documentation/Tests

  • No findings.

Tests not run (not requested).

Replace "simple mean difference" with "aggregating group-time effects"
in the binary comparison section, accurately reflecting the weighting
used by both ContinuousDiD and CallawaySantAnna.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@igerber
Copy link
Owner Author

igerber commented Feb 22, 2026

/ai-review

@github-actions
Copy link

🔁 AI review rerun (requested by @igerber)

Head SHA: adcbad41ad9bee4f0fe7a72d825a7c7fb4f7d5f4


Overall assessment: ✅ Looks good

Executive Summary

  • Methodology documentation updates for ContinuousDiD align with docs/methodology/continuous-did.md and the results docstring; no estimator or inference logic changes detected.
  • Tutorial content uses the correct public API and matches the documented identification story (PT vs SPT, ATT/ACRT interpretations).
  • Minor notebook robustness issue: matplotlib style selection may error on older Matplotlib installs.

Methodology
No findings.

Code Quality
No findings.

Performance
No findings.

Maintainability
No findings.

Tech Debt
No findings.

Security
No findings.

Documentation/Tests

  • P3: Notebook style selection can raise OSError if seaborn-v0_8-whitegrid is unavailable in older Matplotlib, which stops the tutorial despite Matplotlib being installed. Impact: tutorial execution fails in some environments. Fix: wrap plt.style.use(...) in try/except OSError (or check plt.style.available) and fall back to a default style. Location: docs/tutorials/14_continuous_did.ipynb:L51-L54.

@igerber igerber merged commit 970b54d into main Feb 22, 2026
10 checks passed
@igerber igerber deleted the continuous-did-tutorial branch February 22, 2026 18:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant