Example #1
0
 def test_dml(self):
     #################################
     #  Single treatment and outcome #
     #################################
     X = TestPandasIntegration.df[TestPandasIntegration.features]
     W = TestPandasIntegration.df[TestPandasIntegration.controls]
     Y = TestPandasIntegration.df[TestPandasIntegration.outcome]
     T = TestPandasIntegration.df[TestPandasIntegration.cont_treat]
     # Test LinearDML
     est = LinearDML(model_y=LassoCV(), model_t=LassoCV())
     est.fit(Y, T, X=X, W=W, inference='statsmodels')
     treatment_effects = est.effect(X)
     lb, ub = est.effect_interval(X, alpha=0.05)
     self._check_input_names(
         est.summary())  # Check that names propagate as expected
     # Test re-fit
     X1 = X.rename(columns={c: "{}_1".format(c) for c in X.columns})
     est.fit(Y, T, X=X1, W=W, inference='statsmodels')
     self._check_input_names(est.summary(), feat_comp=X1.columns)
     # Test SparseLinearDML
     est = SparseLinearDML(model_y=LassoCV(), model_t=LassoCV())
     est.fit(Y, T, X=X, W=W, inference='debiasedlasso')
     treatment_effects = est.effect(X)
     lb, ub = est.effect_interval(X, alpha=0.05)
     self._check_input_names(
         est.summary())  # Check that names propagate as expected
     # ForestDML
     est = ForestDML(model_y=GradientBoostingRegressor(),
                     model_t=GradientBoostingRegressor())
     est.fit(Y, T, X=X, W=W, inference='blb')
     treatment_effects = est.effect(X)
     lb, ub = est.effect_interval(X, alpha=0.05)
     ####################################
     #  Mutiple treatments and outcomes #
     ####################################
     Y = TestPandasIntegration.df[TestPandasIntegration.outcome_multi]
     T = TestPandasIntegration.df[TestPandasIntegration.cont_treat_multi]
     # Test LinearDML
     est = LinearDML(model_y=MultiTaskLasso(), model_t=MultiTaskLasso())
     est.fit(Y, T, X=X, W=W, inference='statsmodels')
     self._check_input_names(est.summary(), True,
                             True)  # Check that names propagate as expected
     self._check_popsum_names(
         est.effect_inference(X).population_summary(), True)
     est.fit(Y, T, X=X, W=W,
             inference='bootstrap')  # Check bootstrap as well
     self._check_input_names(est.summary(), True, True)
     self._check_popsum_names(
         est.effect_inference(X).population_summary(), True)
     # Test SparseLinearDML
     est = SparseLinearDML(model_y=MultiTaskLasso(),
                           model_t=MultiTaskLasso())
     est.fit(Y, T, X=X, W=W, inference='debiasedlasso')
     treatment_effects = est.effect(X)
     lb, ub = est.effect_interval(X, alpha=0.05)
     self._check_input_names(est.summary(), True,
                             True)  # Check that names propagate as expected
     self._check_popsum_names(
         est.effect_inference(X).population_summary(), True)
Example #2
0
 def test_dml_random_state(self):
     Y, T, X, W, X_test = TestRandomState._make_data(500, 2)
     for est in [
             NonParamDML(model_y=RandomForestRegressor(n_estimators=10,
                                                       max_depth=4,
                                                       random_state=123),
                         model_t=RandomForestClassifier(n_estimators=10,
                                                        max_depth=4,
                                                        random_state=123),
                         model_final=RandomForestRegressor(
                             max_depth=3,
                             n_estimators=10,
                             min_samples_leaf=100,
                             bootstrap=True,
                             random_state=123),
                         discrete_treatment=True,
                         n_splits=2,
                         random_state=123),
             CausalForestDML(
                 model_y=RandomForestRegressor(n_estimators=10,
                                               max_depth=4,
                                               random_state=123),
                 model_t=RandomForestClassifier(n_estimators=10,
                                                max_depth=4,
                                                random_state=123),
                 n_estimators=8,
                 discrete_treatment=True,
                 cv=2,
                 random_state=123),
             LinearDML(model_y=RandomForestRegressor(n_estimators=10,
                                                     max_depth=4,
                                                     random_state=123),
                       model_t=RandomForestClassifier(n_estimators=10,
                                                      max_depth=4,
                                                      random_state=123),
                       discrete_treatment=True,
                       n_splits=2,
                       random_state=123),
             SparseLinearDML(discrete_treatment=True,
                             n_splits=2,
                             random_state=123),
             KernelDML(discrete_treatment=True,
                       n_splits=2,
                       random_state=123)
     ]:
         TestRandomState._test_random_state(est, X_test, Y, T, X=X, W=W)
Example #3
0
    def test_dml(self):
        """Test setting attributes and refitting"""
        y, T, X, W = self._get_data()

        dml = DML(model_y=LinearRegression(),
                  model_t=LinearRegression(),
                  model_final=StatsModelsLinearRegression(fit_intercept=False),
                  linear_first_stages=False,
                  random_state=123)
        dml.fit(y, T, X=X, W=W)
        with pytest.raises(Exception):
            dml.refit_final()
        dml.fit(y, T, X=X, W=W, cache_values=True)
        dml.model_final = StatsModelsRLM(fit_intercept=False)
        dml.refit_final()
        assert isinstance(dml.model_cate, StatsModelsRLM)
        np.testing.assert_array_equal(dml.model_cate.coef_[1:].flatten(), dml.coef_.flatten())
        lb, ub = dml.model_cate.coef__interval(alpha=0.01)
        lbt, ubt = dml.coef__interval(alpha=0.01)
        np.testing.assert_array_equal(lb[1:].flatten(), lbt.flatten())
        np.testing.assert_array_equal(ub[1:].flatten(), ubt.flatten())
        intcpt = dml.intercept_
        dml.fit_cate_intercept = False
        np.testing.assert_equal(dml.intercept_, intcpt)
        dml.refit_final()
        np.testing.assert_array_equal(dml.model_cate.coef_.flatten(), dml.coef_.flatten())
        lb, ub = dml.model_cate.coef__interval(alpha=0.01)
        lbt, ubt = dml.coef__interval(alpha=0.01)
        np.testing.assert_array_equal(lb.flatten(), lbt.flatten())
        np.testing.assert_array_equal(ub.flatten(), ubt.flatten())
        with pytest.raises(AttributeError):
            dml.intercept_
        with pytest.raises(AttributeError):
            dml.intercept__interval()
        dml.model_final = DebiasedLasso(fit_intercept=False)
        dml.refit_final()
        assert isinstance(dml.model_cate, DebiasedLasso)
        dml.featurizer = PolynomialFeatures(degree=2, include_bias=False)
        dml.model_final = StatsModelsLinearRegression(fit_intercept=False)
        dml.refit_final()
        assert isinstance(dml.featurizer_, PolynomialFeatures)
        dml.fit_cate_intercept = True
        dml.refit_final()
        assert isinstance(dml.featurizer_, Pipeline)
        np.testing.assert_array_equal(dml.coef_.shape, (X.shape[1]**2))
        np.testing.assert_array_equal(dml.coef__interval()[0].shape, (X.shape[1]**2))
        coefpre = dml.coef_
        coefpreint = dml.coef__interval()
        dml.fit(y, T, X=X, W=W)
        np.testing.assert_array_equal(coefpre, dml.coef_)
        np.testing.assert_array_equal(coefpreint[0], dml.coef__interval()[0])
        dml.discrete_treatment = True
        dml.featurizer = None
        dml.linear_first_stages = True
        dml.model_t = LogisticRegression()
        dml.fit(y, T, X=X, W=W)
        newdml = DML(model_y=LinearRegression(),
                     model_t=LogisticRegression(),
                     model_final=StatsModelsLinearRegression(fit_intercept=False),
                     discrete_treatment=True,
                     linear_first_stages=True,
                     random_state=123).fit(y, T, X=X, W=W)
        np.testing.assert_array_equal(dml.coef_, newdml.coef_)
        np.testing.assert_array_equal(dml.coef__interval()[0], newdml.coef__interval()[0])

        ldml = LinearDML(model_y=LinearRegression(),
                         model_t=LinearRegression(),
                         linear_first_stages=False)
        ldml.fit(y, T, X=X, W=W, cache_values=True)
        # can set final model for plain DML, but can't for LinearDML (hardcoded to StatsModelsRegression)
        with pytest.raises(ValueError):
            ldml.model_final = StatsModelsRLM()

        ldml = SparseLinearDML(model_y=LinearRegression(),
                               model_t=LinearRegression(),
                               linear_first_stages=False)
        ldml.fit(y, T, X=X, W=W, cache_values=True)
        # can set final model for plain DML, but can't for LinearDML (hardcoded to StatsModelsRegression)
        with pytest.raises(ValueError):
            ldml.model_final = StatsModelsRLM()
        ldml.alpha = 0.01
        ldml.max_iter = 10
        ldml.tol = 0.01
        ldml.refit_final()
        np.testing.assert_equal(ldml.model_cate.estimators_[0].alpha, 0.01)
        np.testing.assert_equal(ldml.model_cate.estimators_[0].max_iter, 10)
        np.testing.assert_equal(ldml.model_cate.estimators_[0].tol, 0.01)
Example #4
0
    def test_comparison(self):
        def reg():
            return LinearRegression()

        def clf():
            return LogisticRegression()

        y, T, X, true_eff = self._get_data()
        (X_train, X_val, T_train, T_val, Y_train, Y_val, _,
         true_eff_val) = train_test_split(X, T, y, true_eff, test_size=.4)

        models = [
            ('ldml',
             LinearDML(model_y=reg(),
                       model_t=clf(),
                       discrete_treatment=True,
                       linear_first_stages=False,
                       cv=3)),
            ('sldml',
             SparseLinearDML(model_y=reg(),
                             model_t=clf(),
                             discrete_treatment=True,
                             featurizer=PolynomialFeatures(degree=2,
                                                           include_bias=False),
                             linear_first_stages=False,
                             cv=3)),
            ('xlearner',
             XLearner(models=reg(), cate_models=reg(),
                      propensity_model=clf())),
            ('dalearner',
             DomainAdaptationLearner(models=reg(),
                                     final_models=reg(),
                                     propensity_model=clf())),
            ('slearner', SLearner(overall_model=reg())),
            ('tlearner', TLearner(models=reg())),
            ('drlearner',
             DRLearner(model_propensity=clf(),
                       model_regression=reg(),
                       model_final=reg(),
                       cv=3)),
            ('rlearner',
             NonParamDML(model_y=reg(),
                         model_t=clf(),
                         model_final=reg(),
                         discrete_treatment=True,
                         cv=3)),
            ('dml3dlasso',
             DML(model_y=reg(),
                 model_t=clf(),
                 model_final=reg(),
                 discrete_treatment=True,
                 featurizer=PolynomialFeatures(degree=3),
                 linear_first_stages=False,
                 cv=3))
        ]

        models = Parallel(n_jobs=-1, verbose=1)(
            delayed(_fit_model)(name, mdl, Y_train, T_train, X_train)
            for name, mdl in models)

        scorer = RScorer(model_y=reg(),
                         model_t=clf(),
                         discrete_treatment=True,
                         cv=3,
                         mc_iters=2,
                         mc_agg='median')
        scorer.fit(Y_val, T_val, X=X_val)
        rscore = [scorer.score(mdl) for _, mdl in models]
        rootpehe_score = [
            np.sqrt(
                np.mean(
                    (true_eff_val.flatten() - mdl.effect(X_val).flatten())**2))
            for _, mdl in models
        ]
        assert LinearRegression().fit(
            np.array(rscore).reshape(-1, 1),
            np.array(rootpehe_score)).coef_ < 0.5
        mdl, _ = scorer.best_model([mdl for _, mdl in models])
        rootpehe_best = np.sqrt(
            np.mean((true_eff_val.flatten() - mdl.effect(X_val).flatten())**2))
        assert rootpehe_best < 1.2 * np.min(rootpehe_score)
        mdl, _ = scorer.ensemble([mdl for _, mdl in models])
        rootpehe_ensemble = np.sqrt(
            np.mean((true_eff_val.flatten() - mdl.effect(X_val).flatten())**2))
        assert rootpehe_ensemble < 1.2 * np.min(rootpehe_score)
Example #5
0
 def test_dml(self):
     #################################
     #  Single treatment and outcome #
     #################################
     X = TestPandasIntegration.df[TestPandasIntegration.features]
     W = TestPandasIntegration.df[TestPandasIntegration.controls]
     Y = TestPandasIntegration.df[TestPandasIntegration.outcome]
     T = TestPandasIntegration.df[TestPandasIntegration.cont_treat]
     # Test LinearDML
     est = LinearDML(model_y=LassoCV(), model_t=LassoCV())
     est.fit(Y, T, X=X, W=W, inference='statsmodels')
     treatment_effects = est.effect(X)
     lb, ub = est.effect_interval(X, alpha=0.05)
     self._check_input_names(
         est.summary())  # Check that names propagate as expected
     # |--> Test featurizers
     est.featurizer = PolynomialFeatures(degree=2, include_bias=False)
     est.fit(Y, T, X=X, W=W, inference='statsmodels')
     self._check_input_names(
         est.summary(),
         feat_comp=est.original_featurizer.get_feature_names(X.columns))
     est.featurizer = FunctionTransformer()
     est.fit(Y, T, X=X, W=W, inference='statsmodels')
     self._check_input_names(
         est.summary(),
         feat_comp=[
             f"feat(X){i}" for i in range(TestPandasIntegration.n_features)
         ])
     est.featurizer = ColumnTransformer([('passthrough', 'passthrough', [0])
                                         ])
     est.fit(Y, T, X=X, W=W, inference='statsmodels')
     # ColumnTransformer doesn't propagate column names
     self._check_input_names(est.summary(), feat_comp=["x0"])
     # |--> Test re-fit
     est.featurizer = None
     X1 = X.rename(columns={c: "{}_1".format(c) for c in X.columns})
     est.fit(Y, T, X=X1, W=W, inference='statsmodels')
     self._check_input_names(est.summary(), feat_comp=X1.columns)
     # Test SparseLinearDML
     est = SparseLinearDML(model_y=LassoCV(), model_t=LassoCV())
     est.fit(Y, T, X=X, W=W, inference='debiasedlasso')
     treatment_effects = est.effect(X)
     lb, ub = est.effect_interval(X, alpha=0.05)
     self._check_input_names(
         est.summary())  # Check that names propagate as expected
     # Test ForestDML
     est = ForestDML(model_y=GradientBoostingRegressor(),
                     model_t=GradientBoostingRegressor())
     est.fit(Y, T, X=X, W=W, inference='blb')
     treatment_effects = est.effect(X)
     lb, ub = est.effect_interval(X, alpha=0.05)
     ####################################
     #  Mutiple treatments and outcomes #
     ####################################
     Y = TestPandasIntegration.df[TestPandasIntegration.outcome_multi]
     T = TestPandasIntegration.df[TestPandasIntegration.cont_treat_multi]
     # Test LinearDML
     est = LinearDML(model_y=MultiTaskLasso(), model_t=MultiTaskLasso())
     est.fit(Y, T, X=X, W=W, inference='statsmodels')
     self._check_input_names(est.summary(), True,
                             True)  # Check that names propagate as expected
     self._check_popsum_names(
         est.effect_inference(X).population_summary(), True)
     est.fit(Y, T, X=X, W=W,
             inference='bootstrap')  # Check bootstrap as well
     self._check_input_names(est.summary(), True, True)
     self._check_popsum_names(
         est.effect_inference(X).population_summary(), True)
     # Test SparseLinearDML
     est = SparseLinearDML(model_y=MultiTaskLasso(),
                           model_t=MultiTaskLasso())
     est.fit(Y, T, X=X, W=W, inference='debiasedlasso')
     treatment_effects = est.effect(X)
     lb, ub = est.effect_interval(X, alpha=0.05)
     self._check_input_names(est.summary(), True,
                             True)  # Check that names propagate as expected
     self._check_popsum_names(
         est.effect_inference(X).population_summary(), True)