Source code for libuplift.meta.r_learner

"""R-learner."""

import numpy as np

from sklearn.linear_model import LinearRegression

from sklearn.model_selection import cross_val_predict

from .base import UpliftMetaModelBase
from ..base import UpliftRegressorMixin
from ..model_selection import uplift_check_cv

[docs] class RLearnerUpliftRegressor(UpliftRegressorMixin, UpliftMetaModelBase): def __init__(self, base_estimator=LinearRegression(), mean_estimator=None, cv=None): self.mean_estimator = mean_estimator self.cv = cv super().__init__(base_estimator) def _get_model_names_list(self, X=None, y=None, trt=None, y_stratify=None): return ["model_tau"] def _make_cv(self, y, trt, y_stratify): if y_stratify is None: cv_classifier=False else: cv_classifier=True cv_classifier = False # TODO no way to pass y_stratify to cv # inside cross_val_predict self.cv_, y_stratify = uplift_check_cv(self.cv, y_stratify, trt, self.n_trt_, classifier=cv_classifier) self.y_stratify_ = y_stratify # TODO: more elegant way to pass to _iter_training_subsets? def _iter_training_subsets(self, X, y, trt, n_trt, sample_weight, y_stratify=None): if n_trt > 1: raise ValueError("RLearner is only supported for a single treatment.") self._make_cv(y, trt, self.y_stratify_) if self.mean_estimator is not None: mean_estimator = self.mean_estimator else: mean_estimator = self.base_estimator # TODO: cross_val_predict does not support sample_weight # TODO: no way to pass stratified Y y_mean = cross_val_predict(mean_estimator, X, y, cv=self.cv_) y = np.asarray(y, float) # allow classification problems y = y - y_mean # TODO: refactor with other methods mask_c = (trt==0) mask_t = ~mask_c if sample_weight is None: nt = mask_t.sum() nc = mask_c.sum() else: nt = sample_weight[mask_t].sum() nc = sample_weight[mask_c].sum() n = nt + nc w = np.where(mask_t, nt/n, -nc/n) y /= w if sample_weight is None: sample_weight = w*w else: sample_weight = sample_weight * (w*w) yield X, y, sample_weight
[docs] def fit(self, X, y, trt, n_trt=None, sample_weight=None, *, y_stratify=None): self.y_stratify_ = y_stratify # TODO: more elegant way to pass this super().fit(X, y, trt, n_trt, sample_weight=sample_weight, y_stratify=y_stratify) del self.y_stratify_
[docs] def predict(self, X): return self.models_[0][1].predict(X)