-
Notifications
You must be signed in to change notification settings - Fork 12
Add unified LOOCV for TROP joint method with Rust acceleration #113
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Implements proper leave-one-out cross-validation for the TROP joint method, matching the twostep method's approach per the paper's Equation 5. Adds Rust backend acceleration for parallel LOOCV grid search and bootstrap variance estimation (5-15x speedup). Changes: - rust/src/trop.rs: Add loocv_grid_search_joint(), bootstrap_trop_variance_joint(), and supporting joint model fitting functions - diff_diff/trop.py: Update _fit_joint() to use LOOCV, add _loocv_score_joint() Python fallback, integrate Rust acceleration for bootstrap variance - diff_diff/_backend.py: Export new Rust functions - docs/methodology/REGISTRY.md: Document unified LOOCV approach for joint method - tests/: Add comprehensive tests for joint method LOOCV and Rust/Python parity Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
Methodology
Documentation/Tests
Code Quality
Performance
Maintainability
Tech Debt
Security
Overall Assessment: Executive Summary
|
Address P1 review feedback: - P1-2: Align nuclear-norm threshold scaling by using eta * lambda_nn for soft-threshold SVD step in Python (matching Rust implementation) - P1-1: Add comprehensive NaN handling in _compute_joint_weights, _solve_joint_no_lowrank, and _solve_joint_with_lowrank Add tests for NaN handling parity between backends. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
/ai-review |
|
🔁 AI review rerun (requested by @igerber) Head SHA: Methodology
Code Quality
Performance
Maintainability
Tech Debt
Security
Documentation/Tests
Open Questions
Overall Assessment
Executive Summary
|
- Fix _solve_joint_with_lowrank to mask delta for NaN observations (ensures NaN Y values don't contribute to gradient step) - Fix jackknife to use true leave-one-out via weight zeroing (removes incorrect imputation with column means) - Handle units with no valid pre-period data by setting delta_unit=0 (previously got max weight due to dist=0) - Document simultaneous adoption assumption for joint method variance - Correct notebook weight normalization statement (not "sum to one") - Add tests for true NaN exclusion and jackknife variation behavior Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
/ai-review |
|
🔁 AI review rerun (requested by @igerber) Head SHA: Methodology
Code Quality
Performance
Maintainability
Tech Debt
Security
Documentation/Tests
Open Questions
Overall Assessment Executive Summary
|
Address PR #113 Round 3 feedback: - rust/src/trop.rs: Change dist from 0.0 to INFINITY when n_valid=0 so delta_unit = exp(-inf) = 0.0 (zero weight) instead of exp(0) = 1.0 (max weight). This matches Python behavior. - tests/test_rust_backend.py: Add two parity tests: - test_trop_joint_no_valid_pre_unit_gets_zero_weight - test_trop_joint_nan_exclusion_rust_python_parity Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
/ai-review |
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall assessment: Executive summary
Methodology
Code Quality
Performance
Maintainability
Tech Debt
Security
Documentation/Tests
|
…ix NaN handling - Add staggered adoption check in _fit_joint() that raises ValueError when units are first treated at different periods - Fix Rust solve_joint NaN weight masking: observations with NaN outcomes now get zero effective weight instead of having values imputed to 0.0 - Fix Rust average_treated initialization: use NaN instead of 0.0 so periods with all-NaN treated data are excluded from unit distance - Update methodology registry to reflect enforced simultaneous adoption - Add test_joint_rejects_staggered_adoption test Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
/ai-review |
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall assessment: Executive Summary
Methodology
Code Quality
Performance
Maintainability
Tech Debt
Security
Documentation/Tests
|
…-pre NaN tests - Fix Python valid_count to use np.isfinite(diff) instead of np.isfinite(Y) When average_treated[t] is NaN, the period should be excluded from both numerator and denominator of RMSE distance calculation - Add test_joint_treated_pre_nan_handling to test_trop.py - Add test_trop_joint_treated_pre_nan_rust_python_parity to test_rust_backend.py - Fix Rust docstring for loocv_grid_search_joint (was incorrectly describing "two-stage coordinate descent", now correctly says "parallel grid search") Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
/ai-review |
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall assessment:
Methodology
Code Quality
Performance
Maintainability
Tech Debt
Security
Documentation/Tests
|
…st reloads - Fix simultaneous-adoption check to use observed periods only, avoiding false positives on unbalanced panels where missing entries were filled as 0 - Add zero-weight guard in Python joint solver matching Rust's behavior - Fix backend parity tests to properly reload trop module using sys.modules Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
/ai-review |
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall assessment: Executive Summary
Methodology
Code Quality
Performance
Maintainability
Tech Debt
Security
Documentation/Tests
|
Fix ValueError in joint method when control_obs exceeds max_loocv_samples without Rust backend. np.random.choice cannot directly sample from a list of tuples - now samples indices first, then indexes into the list (matching the pattern already used in the twostep method). Add test to verify Python-only joint LOOCV subsampling works correctly. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
/ai-review |
3 similar comments
|
/ai-review |
|
/ai-review |
|
/ai-review |
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment: ✅ Looks good Executive Summary
Methodology
Code Quality
Performance
Maintainability
Tech Debt
Security
Documentation/Tests
|
Update version numbers in: - diff_diff/__init__.py - pyproject.toml - rust/Cargo.toml Add CHANGELOG entry for v2.1.9 documenting TROP joint method improvements including unified LOOCV with Rust acceleration and various Rust/Python parity fixes from PR #113. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Summary
loocv_grid_search_joint())bootstrap_trop_variance_joint())_loocv_score_joint()) when Rust unavailable_fit_joint()and_bootstrap_variance_joint()to use Rust when availableMethodology references (required if estimator / math changes)
Validation
tests/test_trop.py: Addedtest_joint_loocv_selects_from_grid,test_joint_loocv_score_internaltests/test_rust_backend.py: AddedTestTROPJointRustBackendclass (4 tests) andTestTROPJointRustVsNumpyclass (2 tests)cargo checkpasses)Security / privacy
Generated with Claude Code