Skip to content

Add propensity score trimming and partition-specific collinearity checks#32

Merged
marcelortizv merged 4 commits intomainfrom
feature/pscore-trimming
Jan 23, 2026
Merged

Add propensity score trimming and partition-specific collinearity checks#32
marcelortizv merged 4 commits intomainfrom
feature/pscore-trimming

Conversation

@pedrohcgs
Copy link
Collaborator

@pedrohcgs pedrohcgs commented Jan 18, 2026

Summary

  • Add asymmetric propensity score trimming for control units with pscore >= 0.995
  • Add trim_level parameter (default 0.995) to compute_pscore() and compute_pscore_rc() functions
  • Add keep_ps indicator to exclude poor counterfactual controls from ATT estimation
  • Change upper bound from 1 - 1e-16 to 1 - 1e-6 (matches DRDID)
  • Apply trimming to ATT weights but NOT to nuisance parameter estimation
  • Add partition-specific collinearity detection with two-stage checking
  • Add comprehensive test suite including Monte Carlo coverage test

Trimming Logic

Group Condition Included in ATT?
Treated (PA4=1) Always ✓ Yes
Control (PA4=0) ps < 0.995 ✓ Yes
Control (PA4=0) ps >= 0.995 ✗ No (weight = 0)

Why This Matters

Control units with propensity scores very close to 1 are problematic because:

  1. Poor counterfactuals: They are "almost treated" based on covariates
  2. Numerical instability: IPW weights explode since ps/(1-ps) → ∞ as ps → 1

Partition-Specific Collinearity

Added check_partition_collinearity() helper that:

  • Detects covariates collinear only within specific subgroup comparisons (4 vs 3, 4 vs 2, 4 vs 1)
  • Provides informative warnings showing which partitions have issues
  • Uses two-stage checking: global collinearity first, then partition-specific

Reference

DRDID package: R/drdid_panel.R, lines 122-143

- Add asymmetric trimming for control units with pscore >= 0.995
- Add trim_level parameter (default 0.995) to compute_pscore functions
- Add keep_ps indicator to exclude poor counterfactual controls from ATT
- Change upper bound from 1 - 1e-16 to 1 - 1e-6 (matches DRDID)
- Apply trimming to ATT weights but NOT to nuisance estimation

Trimming logic:
- Treated units: always included (keep_ps = TRUE)
- Control units: excluded if pscore >= trim_level (keep_ps = FALSE)

This prevents numerical instability from IPW weights exploding
when ps/(1-ps) approaches infinity for controls with ps near 1.

Reference: DRDID package (drdid_panel.R, lines 122-143)
@pedrohcgs pedrohcgs force-pushed the feature/pscore-trimming branch from f327a65 to feba1b8 Compare January 18, 2026 06:15
Propensity Score Trimming (following DRDID approach):
- Add asymmetric trimming for control units with pscore >= 0.995
- Add trim_level parameter (default 0.995) to compute_pscore functions
- Add keep_ps indicator to exclude poor counterfactual controls from ATT
- Change upper bound from 1 - 1e-16 to 1 - 1e-6 (matches DRDID)
- Apply trimming to ATT weights but NOT to nuisance estimation

Partition-Specific Collinearity Checks:
- Add check_partition_collinearity() helper function
- Detect covariates that are collinear only within specific subgroup comparisons
- Two-stage checking: global collinearity first, then partition-specific
- Informative warnings showing which partitions have collinearity issues

Tests:
- Add 6 unit tests for propensity score trimming functionality
- Add Monte Carlo coverage test (1000 sims, n=2000, 2% tolerance)
- Coverage test DGP triggers trimming (~10 controls per sim with ps >= 0.995)
- Add 6 tests for partition-specific collinearity detection

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@pedrohcgs pedrohcgs changed the title Add propensity score trimming following DRDID approach Add propensity score trimming and partition-specific collinearity checks Jan 18, 2026
@marcelortizv marcelortizv merged commit 6199f5e into main Jan 23, 2026
1 check passed
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.

2 participants