Skip to content

Add CATE model selection via surrogate metrics (R-score, DR-loss) #922

Description

@aman-coder03

Is your feature request related to a problem? Please describe.
when using causalml in practice, i will often train S-learner, T-learner, X-learner, and DR-learner on the same data and have no principled way to pick between them. Standard cross validation does not work here because you never observe both potential outcomes for the same unit, so there's no ground truth to score against.

R-loss that powers the R-learner's training loop (rlearner.py lines 152, 495, 636) is exactly the right idea, but it's only used internally and never exposed as a standalone scoring function. EconML users already have this via econml.score.RScorer . Causalml users currently don't have an equivalent

Describe the solution you'd like
add a CATEModelSelector to causalml.metrics that scores and compares fitted meta-learners using observed-data surrogate metrics, without needing access to true counterfactual outcomes...

metrics worth shipping in a first pass,

  1. R-score (Nie and Wager, 2021): fits residual models for outcome and treatment, then measures how much CATE variance the model explains. Same R-loss already inside BaseRLearner.fit() , just exposed as a standalone function
  2. DR pseudo-outcome loss (Kennedy 2023): constructs doubly-robust pseudo-outcomes and scores the CATE estimator against them. Mahajan et al. (2024) showed DR-based metrics dominate across 78 datasets
  3. Plug-in T-score: uses a T-learner on held-out data as a CATE proxy. Mahajan et al. found this is never dominated across datasets despite being a simple baseline

rough API sketch

from causalml.metrics import CATEModelSelector

selector = CATEModelSelector(
    models={'s': s_learner, 't': t_learner, 'x': x_learner, 'dr': dr_learner},
    metric='dr_loss',  # or 'r_score', 'plug_in_t'
    cv=5,
)
selector.fit(X, treatment, y)

selector.scores_       # {'s': 0.31, 't': 0.47, 'x': 0.61, 'dr': 0.58}
selector.best_model()  # 'x'
selector.plot_scores()

no new heavy dependencies needed. Nuisance models reuse causalml's existing propensity module and sklearn

Describe alternatives you've considered
using EconML's RScorer directly works but requires fitting nuisance components twice across two libraries with no integration between them.
picking by held-out outcome MSE is what most people default to, but outcome MSE doesn't measure CATE accuracy. A model can have low outcome MSE while getting the treatment effect completely wrong.

Additional context
happy to start with just the R-score as a standalone function in causalml.metrics and build the selector wrapper from there, if that's a better way to scope an initial PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions