From 8530e268ccf8c2de75b03f94d6bcc1030981665b Mon Sep 17 00:00:00 2001 From: Judith Abecassis Date: Wed, 10 Jul 2024 09:16:41 +0200 Subject: [PATCH 01/84] Input check (#81) enforce input check at the function level to avoid issues with input shape, fix ci with R Co-authored-by: houssamzenati --- .github/workflows/code-cov.yaml | 3 + .github/workflows/tests-with-R.yaml | 5 +- src/med_bench/mediation.py | 87 +++++++------------ src/med_bench/utils/nuisances.py | 21 ++--- src/med_bench/utils/utils.py | 80 +++++++++++++++++ src/tests/estimation/test_exact_estimation.py | 6 +- src/tests/estimation/test_get_estimation.py | 1 - src/tests/utils/test_utils.py | 63 ++++++++++++++ 8 files changed, 191 insertions(+), 75 deletions(-) create mode 100644 src/tests/utils/test_utils.py diff --git a/.github/workflows/code-cov.yaml b/.github/workflows/code-cov.yaml index 8182928..551a319 100644 --- a/.github/workflows/code-cov.yaml +++ b/.github/workflows/code-cov.yaml @@ -39,6 +39,8 @@ jobs: dependencies: 'NA' install-pandoc: false packages: | + Matrix@1.6-5 + MASS@7.3-60 grf causalweight mediation @@ -53,6 +55,7 @@ jobs: - name: Run tests with coverage run: | + export LD_LIBRARY_PATH=$(python -m rpy2.situation LD_LIBRARY_PATH):${LD_LIBRARY_PATH} pytest --cov=med_bench --cov-report=xml - name: Upload coverage to Codecov diff --git a/.github/workflows/tests-with-R.yaml b/.github/workflows/tests-with-R.yaml index 086ddb5..20b15a0 100644 --- a/.github/workflows/tests-with-R.yaml +++ b/.github/workflows/tests-with-R.yaml @@ -39,6 +39,8 @@ jobs: dependencies: 'NA' install-pandoc: false packages: | + Matrix@1.6-5 + MASS@7.3-60 grf causalweight mediation @@ -53,4 +55,5 @@ jobs: - name: Run tests run: | - pytest \ No newline at end of file + export LD_LIBRARY_PATH=$(python -m rpy2.situation LD_LIBRARY_PATH):${LD_LIBRARY_PATH} + pytest diff --git a/src/med_bench/mediation.py b/src/med_bench/mediation.py index 5d2071b..be9e93b 100644 --- a/src/med_bench/mediation.py +++ b/src/med_bench/mediation.py @@ -18,7 +18,7 @@ _estimate_mediator_density, _estimate_treatment_probabilities, _get_classifier, _get_regressor) -from .utils.utils import r_dependency_required +from .utils.utils import r_dependency_required, _check_input ALPHAS = np.logspace(-5, 5, 8) CV_FOLDS = 5 @@ -90,6 +90,9 @@ def mediation_IPW(y, t, m, x, trim, regularization=True, forest=False, int number of used observations (non trimmed) """ + # check input + y, t, m, x = _check_input(y, t, m, x, setting='multidimensional') + # estimate propensities classifier_t_x = _get_classifier(regularization, forest, calibration) classifier_t_xm = _get_classifier(regularization, forest, calibration) @@ -179,12 +182,13 @@ def mediation_coefficient_product(y, t, m, x, interaction=False, alphas = ALPHAS else: alphas = [TINY] - if len(x.shape) == 1: - x = x.reshape(-1, 1) - if len(m.shape) == 1: - m = m.reshape(-1, 1) + + # check input + y, t, m, x = _check_input(y, t, m, x, setting='multidimensional') + if len(t.shape) == 1: t = t.reshape(-1, 1) + coef_t_m = np.zeros(m.shape[1]) for i in range(m.shape[1]): m_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS)\ @@ -248,9 +252,12 @@ def mediation_g_formula(y, t, m, x, interaction=False, forest=False, calibration : str, default=sigmoid calibration mode; for example using a sigmoid function """ + # check input + y, t, m, x = _check_input(y, t, m, x, setting='binary') + # estimate mediator densities classifier_m = _get_classifier(regularization, forest, calibration) - f_00x, f_01x, f_10x, f_11x, _, _ = _estimate_mediator_density(t, m, x, y, + f_00x, f_01x, f_10x, f_11x, _, _ = _estimate_mediator_density(y, t, m, x, crossfit, classifier_m, interaction) @@ -258,7 +265,7 @@ def mediation_g_formula(y, t, m, x, interaction=False, forest=False, # estimate conditional mean outcomes regressor_y = _get_regressor(regularization, forest) mu_00x, mu_01x, mu_10x, mu_11x, _, _ = ( - _estimate_conditional_mean_outcome(t, m, x, y, crossfit, regressor_y, + _estimate_conditional_mean_outcome(y, t, m, x, crossfit, regressor_y, interaction)) # G computation @@ -319,10 +326,9 @@ def alternative_estimator(y, t, m, x, regularization=True): alphas = ALPHAS else: alphas = [TINY] - if len(x.shape) == 1: - x = x.reshape(-1, 1) - if len(m.shape) == 1: - m = m.reshape(-1, 1) + + # check input + y, t, m, x = _check_input(y, t, m, x, setting='multidimensional') treated = (t == 1) # computation of direct effect @@ -433,29 +439,9 @@ def mediation_multiply_robust(y, t, m, x, interaction=False, forest=False, - If x, t, m, or y don't have the same length. - If m is not binary. """ - # Format checking - if len(y) != len(y.ravel()): - raise ValueError("Multidimensional y is not supported") - if len(t) != len(t.ravel()): - raise ValueError("Multidimensional t is not supported") - if len(m) != len(m.ravel()): - raise ValueError("Multidimensional m is not supported") - - n = len(y) - if len(x.shape) == 1: - x.reshape(n, 1) - if len(m.shape) == 1: - m.reshape(n, 1) - - dim_m = m.shape[1] - if n * dim_m != sum(m.ravel() == 1) + sum(m.ravel() == 0): - raise ValueError("m is not binary") + # check input + y, t, m, x = _check_input(y, t, m, x, setting='binary') - y = y.ravel() - t = t.ravel() - m = m.ravel() - if n != len(x) or n != len(m) or n != len(t): - raise ValueError("Inputs don't have the same number of observations") # estimate propensities classifier_t_x = _get_classifier(regularization, forest, calibration) @@ -466,7 +452,7 @@ def mediation_multiply_robust(y, t, m, x, interaction=False, forest=False, # estimate mediator densities classifier_m = _get_classifier(regularization, forest, calibration) f_00x, f_01x, f_10x, f_11x, f_m0x, f_m1x = ( - _estimate_mediator_density(t, m, x, y, crossfit, + _estimate_mediator_density(y, t, m, x, crossfit, classifier_m, interaction)) f = f_00x, f_01x, f_10x, f_11x @@ -474,7 +460,7 @@ def mediation_multiply_robust(y, t, m, x, interaction=False, forest=False, regressor_y = _get_regressor(regularization, forest) regressor_cross_y = _get_regressor(regularization, forest) mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 = ( - _estimate_cross_conditional_mean_outcome(t, m, x, y, crossfit, + _estimate_cross_conditional_mean_outcome(y, t, m, x, crossfit, regressor_y, regressor_cross_y, f, interaction)) @@ -574,7 +560,10 @@ def r_mediate(y, t, m, x, interaction=False): Rstats = rpackages.importr('stats') base = rpackages.importr('base') + # check input + y, t, m, x = _check_input(y, t, m, x, setting='binary') m = m.ravel() + var_names = [[y, 'y'], [t, 't'], [m, 'm'], @@ -629,7 +618,10 @@ def r_mediation_g_estimator(y, t, m, x): plmed = rpackages.importr('plmed') base = rpackages.importr('base') + # check input + y, t, m, x = _check_input(y, t, m, x, setting='binary') m = m.ravel() + var_names = [[y, 'y'], [t, 't'], [m, 'm'], @@ -713,6 +705,9 @@ def r_mediation_dml(y, t, m, x, trim=0.05, order=1): causalweight = rpackages.importr('causalweight') base = rpackages.importr('base') + # check input + y, t, m, x = _check_input(y, t, m, x, setting='multidimensional') + x_r, t_r, m_r, y_r = [base.as_matrix(_convert_array_to_R(uu)) for uu in (x, t, m, y)] res = causalweight.medDML(y_r, t_r, m_r, x_r, trim=trim, order=order) @@ -805,25 +800,9 @@ def mediation_dml(y, t, m, x, forest=False, crossfit=0, trim=0.05, clip=1e-6, - If t or y are multidimensional. - If x, t, m, or y don't have the same length. """ - # check format - if len(y) != len(y.ravel()): - raise ValueError("Multidimensional y is not supported") - - if len(t) != len(t.ravel()): - raise ValueError("Multidimensional t is not supported") - + # check input + y, t, m, x = _check_input(y, t, m, x, setting='multidimensional') n = len(y) - t = t.ravel() - y = y.ravel() - - if n != len(x) or n != len(m) or n != len(t): - raise ValueError("Inputs don't have the same number of observations") - - if len(x.shape) == 1: - x.reshape(n, 1) - - if len(m.shape) == 1: - m.reshape(n, 1) nobs = 0 @@ -850,7 +829,7 @@ def mediation_dml(y, t, m, x, forest=False, crossfit=0, trim=0.05, clip=1e-6, regressor_cross_y = _get_regressor(regularization, forest) mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 = ( - _estimate_cross_conditional_mean_outcome_nesting(t, m, x, y, crossfit, + _estimate_cross_conditional_mean_outcome_nesting(y, t, m, x, crossfit, regressor_y, regressor_cross_y)) diff --git a/src/med_bench/utils/nuisances.py b/src/med_bench/utils/nuisances.py index ded68f0..6878610 100644 --- a/src/med_bench/utils/nuisances.py +++ b/src/med_bench/utils/nuisances.py @@ -119,10 +119,6 @@ def _estimate_treatment_probabilities(t, m, x, crossfit, clf_t_x, clf_t_xm): p_x, p_xm = [np.zeros(n) for h in range(2)] # compute propensity scores - if len(x.shape) == 1: - x = x.reshape(-1, 1) - if len(m.shape) == 1: - m = m.reshape(-1, 1) if len(t.shape) == 1: t = t.reshape(-1, 1) @@ -143,7 +139,7 @@ def _estimate_treatment_probabilities(t, m, x, crossfit, clf_t_x, clf_t_xm): return p_x, p_xm -def _estimate_mediator_density(t, m, x, y, crossfit, clf_m, interaction): +def _estimate_mediator_density(y, t, m, x, crossfit, clf_m, interaction): """ Estimate mediator density f(M|T,X) with train test lists from crossfitting @@ -164,8 +160,6 @@ def _estimate_mediator_density(t, m, x, y, crossfit, clf_m, interaction): probabilities f(M|T=1,X) """ n = len(y) - if len(x.shape) == 1: - x = x.reshape(-1, 1) if len(t.shape) == 1: t = t.reshape(-1, 1) @@ -206,7 +200,7 @@ def _estimate_mediator_density(t, m, x, y, crossfit, clf_m, interaction): return f_00x, f_01x, f_10x, f_11x, f_m0x, f_m1x -def _estimate_conditional_mean_outcome(t, m, x, y, crossfit, reg_y, +def _estimate_conditional_mean_outcome(y, t, m, x, crossfit, reg_y, interaction): """ Estimate conditional mean outcome E[Y|T,M,X] @@ -228,12 +222,7 @@ def _estimate_conditional_mean_outcome(t, m, x, y, crossfit, reg_y, conditional mean outcome estimates E[Y|T=1,M,X] """ n = len(y) - if len(x.shape) == 1: - x = x.reshape(-1, 1) - if len(m.shape) == 1: - mr = m.reshape(-1, 1) - else: - mr = np.copy(m) + mr = np.copy(m) if len(t.shape) == 1: t = t.reshape(-1, 1) @@ -275,7 +264,7 @@ def _estimate_conditional_mean_outcome(t, m, x, y, crossfit, reg_y, return mu_00x, mu_01x, mu_10x, mu_11x, mu_0mx, mu_1mx -def _estimate_cross_conditional_mean_outcome(t, m, x, y, crossfit, reg_y, +def _estimate_cross_conditional_mean_outcome(y, t, m, x, crossfit, reg_y, reg_cross_y, f, interaction): """ Estimate the conditional mean outcome, @@ -397,7 +386,7 @@ def _estimate_cross_conditional_mean_outcome(t, m, x, y, crossfit, reg_y, return mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 -def _estimate_cross_conditional_mean_outcome_nesting(t, m, x, y, crossfit, +def _estimate_cross_conditional_mean_outcome_nesting(y, t, m, x, crossfit, reg_y, reg_cross_y): """ Estimate treatment probabilities and the conditional mean outcome, diff --git a/src/med_bench/utils/utils.py b/src/med_bench/utils/utils.py index ab7f44d..9ec0438 100644 --- a/src/med_bench/utils/utils.py +++ b/src/med_bench/utils/utils.py @@ -1,6 +1,7 @@ import numpy as np import pandas as pd + import subprocess import warnings @@ -158,3 +159,82 @@ def _convert_array_to_R(x): elif len(x.shape) == 2: return robjects.r.matrix(robjects.FloatVector(x.ravel()), nrow=x.shape[0], byrow='TRUE') + + +def _check_input(y, t, m, x, setting): + """ + internal function to check inputs. `_check_input` adjusts the dimension + of the input (matrix or vectors), and raises an error + - if the size of input is not adequate, + - or if the type of input is not supported (cotinuous treatment or + non-binary one-dimensional mediator if the specified setting parameter + is binary) + + Parameters + ---------- + y : array-like, shape (n_samples) + Outcome value for each unit, continuous + + t : array-like, shape (n_samples) + Treatment value for each unit, binary + + m : array-like, shape (n_samples, n_mediators) + Mediator value for each unit, binary and unidimensional + + x : array-like, shape (n_samples, n_features_covariates) + Covariates value for each unit, continuous + + setting : string + ('binary', 'continuous', 'multidimensional') value for the mediator + + Returns + ------- + y_converted : array-like, shape (n_samples,) + Outcome value for each unit, continuous + + t_converted : array-like, shape (n_samples,) + Treatment value for each unit, binary + + m_converted : array-like, shape (n_samples, n_mediators) + Mediator value for each unit, binary and unidimensional + + x_converted : array-like, shape (n_samples, n_features_covariates) + Covariates value for each unit, continuous + """ + # check format + if len(y) != len(y.ravel()): + raise ValueError("Multidimensional y (outcome) is not supported") + + if len(t) != len(t.ravel()): + raise ValueError("Multidimensional t (exposure) is not supported") + + if len(np.unique(t)) != 2: + raise ValueError("Only a binary t (exposure) is supported") + + n = len(y) + t_converted = t.ravel() + y_converted = y.ravel() + + if n != len(x) or n != len(m) or n != len(t): + raise ValueError("Inputs don't have the same number of observations") + + if len(x.shape) == 1: + x_converted = x.reshape(n, 1) + else: + x_converted = x + + if len(m.shape) == 1: + m_converted = m.reshape(n, 1) + else: + m_converted = m + + if (m_converted.shape[1] >1) and (setting != 'multidimensional'): + raise ValueError("Multidimensional m (mediator) is not supported") + + if (setting == 'binary') and (len(np.unique(m)) != 2): + raise ValueError( + "Only a binary one-dimensional m (mediator) is supported") + + return y_converted, t_converted, m_converted, x_converted + + diff --git a/src/tests/estimation/test_exact_estimation.py b/src/tests/estimation/test_exact_estimation.py index 98d2d96..3e4fab1 100644 --- a/src/tests/estimation/test_exact_estimation.py +++ b/src/tests/estimation/test_exact_estimation.py @@ -48,7 +48,7 @@ def x(data): # t is raveled because some estimators fail with (n,1) inputs @pytest.fixture def t(data): - return data[2].ravel() + return data[2] @pytest.fixture @@ -58,7 +58,7 @@ def m(data): @pytest.fixture def y(data): - return data[4].ravel() # same reason as t + return data[4] @pytest.fixture @@ -106,4 +106,4 @@ def effects_chap(x, t, m, y, estimator, config): def test_estimation_exactness(result, effects_chap): - assert np.all(effects_chap == pytest.approx(result, abs=0.01)) + assert np.all(effects_chap == pytest.approx(result, abs=1.e-3)) diff --git a/src/tests/estimation/test_get_estimation.py b/src/tests/estimation/test_get_estimation.py index 2e1adae..9a99b90 100644 --- a/src/tests/estimation/test_get_estimation.py +++ b/src/tests/estimation/test_get_estimation.py @@ -122,7 +122,6 @@ def test_total_is_direct_plus_indirect(effects_chap): effects_chap[2] + effects_chap[3]) -@pytest.mark.xfail def test_robustness_to_ravel_format(data, estimator, config, effects_chap): if "forest" in estimator: pytest.skip("Forest estimator skipped") diff --git a/src/tests/utils/test_utils.py b/src/tests/utils/test_utils.py new file mode 100644 index 0000000..166446f --- /dev/null +++ b/src/tests/utils/test_utils.py @@ -0,0 +1,63 @@ +import pytest +import re +import numpy as np +from numpy.random import default_rng +from scipy.special import expit + +from med_bench.get_simulated_data import simulate_data +from med_bench.utils.utils import _check_input + + +rg = default_rng(5) +n = 5 +dim_x = 3 + +x = rg.standard_normal(n * dim_x).reshape((n, dim_x)) +binary_m_or_t = rg.binomial(1, 0.5, n).reshape(-1, 1) +y = rg.standard_normal(n).reshape(-1, 1) + + +testdata = [ + (x, binary_m_or_t, binary_m_or_t, x, "Multidimensional y (outcome)"), + (y, x, binary_m_or_t, x, "Multidimensional t (exposure)"), + (y, x[0], binary_m_or_t, x, "Only a binary t (exposure)"), + (y, np.vstack([binary_m_or_t, binary_m_or_t]), binary_m_or_t, x, + "same number of observations"), + (y, binary_m_or_t, np.vstack([binary_m_or_t, binary_m_or_t]), x, + "same number of observations"), + (y, binary_m_or_t, binary_m_or_t, np.vstack([x, x]), + "same number of observations"), + # the check should raise when a non-binary mediator is passed while a + # binary mediator is expected (last argument of the input_check function) + (y, binary_m_or_t, x, x, "Multidimensional m (mediator)"), + (y, binary_m_or_t, x[:, 0], x, "a binary one-dimensional m"), + ] +ids = ['outcome dimension', + 'exposure dimension', + 'continuous exposure', + 'number of observations (t)', + 'number of observations (m)', + 'number of observations (x)', + 'mediator dimension', + 'binary mediator'] + +@pytest.mark.parametrize("y, t, m, x, match", testdata, ids=ids) +def test_dim_input(y, t, m, x, match): + with pytest.raises(ValueError, match=re.escape(match)): + _check_input(y, t, m, x, 'binary') + +@pytest.mark.parametrize("y, t, m, x", [(y, binary_m_or_t, binary_m_or_t, x)]) +def test_dim_output(y, t, m, x): + n = len(y) + y_converted, t_converted, m_converted, x_converted = \ + _check_input(y, t, m, x, 'binary') + assert y_converted.shape == (n,) + assert t_converted.shape == (n,) + assert x_converted.shape == x.shape + assert m_converted.shape == m.shape + y_converted, t_converted, m_converted, x_converted = \ + _check_input(y, t, m.ravel(), x[:, 0], 'binary') + assert x_converted.shape == (n, 1) + assert m_converted.shape == (n, 1) + + From e062cbd4daa81aa7c831d20b3f864dee74a341e9 Mon Sep 17 00:00:00 2001 From: brash6 Date: Thu, 1 Aug 2024 18:17:17 +0200 Subject: [PATCH 02/84] Modularized estimators --- src/med_bench/estimation/base.py | 295 ++++++++++++++++++ .../estimation/coefficient_product.py | 93 ++++++ src/med_bench/estimation/dml.py | 181 +++++++++++ src/med_bench/estimation/g_computation.py | 190 +++++++++++ src/med_bench/estimation/ipw.py | 121 +++++++ src/med_bench/estimation/mr.py | 279 +++++++++++++++++ src/med_bench/estimation/tmle.py | 267 ++++++++++++++++ 7 files changed, 1426 insertions(+) create mode 100644 src/med_bench/estimation/base.py create mode 100644 src/med_bench/estimation/coefficient_product.py create mode 100644 src/med_bench/estimation/dml.py create mode 100644 src/med_bench/estimation/g_computation.py create mode 100644 src/med_bench/estimation/ipw.py create mode 100644 src/med_bench/estimation/mr.py create mode 100644 src/med_bench/estimation/tmle.py diff --git a/src/med_bench/estimation/base.py b/src/med_bench/estimation/base.py new file mode 100644 index 0000000..8e03c7a --- /dev/null +++ b/src/med_bench/estimation/base.py @@ -0,0 +1,295 @@ +from abc import ABCMeta, abstractmethod + +import numpy as np + +from sklearn.model_selection import GridSearchCV +from sklearn.base import clone, RegressorMixin, ClassifierMixin + +from med_bench.utils.decorators import fitted +from med_bench.utils.scores import r_risk +from med_bench.utils.utils import _get_interactions + + +class Estimator: + """General abstract class for causal mediation Estimator + """ + __metaclass__ = ABCMeta + def __init__(self, mediator_type : str, regressor : RegressorMixin, classifier : ClassifierMixin, + verbose : bool=True): + """Initialize Estimator base class + + Parameters + ---------- + mediator_type : str + mediator type (binary or continuous) + regressor : RegressorMixin + Scikit-Learn Regressor used for mu estimation + classifier : ClassifierMixin + Scikit-Learn Classifier used for propensity estimation + verbose : bool + will print some logs if True + """ + self.rng = np.random.RandomState(123) + + self.mediator_type = mediator_type + + # TBD inside an Issue + self.regressor = regressor + #self.regressor_params_dict = regressor_params_dict + + self.classifier = classifier + #self.classifier_params_dict = classifier_params_dict + + self._verbose = verbose + self._fitted = False + + + @property + def verbose(self): + return self._verbose + + + @abstractmethod + def fit(self, t, m, x, y): + """Fits nuisance parameters to data + + Parameters + ---------- + t array-like, shape (n_samples) + treatment value for each unit, binary + + m array-like, shape (n_samples) + mediator value for each unit, here m is necessary binary and uni- + dimensional + + x array-like, shape (n_samples, n_features_covariates) + covariates (potential confounders) values + + y array-like, shape (n_samples) + outcome value for each unit, continuous + + """ + pass + + + @abstractmethod + @fitted + def estimate(self, t, m, x, y): + """Estimates causal effect on data + + Parameters + ---------- + t array-like, shape (n_samples) + treatment value for each unit, binary + + m array-like, shape (n_samples) + mediator value for each unit, here m is necessary binary and uni- + dimensional + + x array-like, shape (n_samples, n_features_covariates) + covariates (potential confounders) values + + y array-like, shape (n_samples) + outcome value for each unit, continuous + + nuisances + """ + pass + + + def fit_score_nuisances(self, t, m, x, y, *args, **kwargs): + """ Fits the score of the nuisance parameters + """ + clf_param_grid = {} + reg_param_grid = {} + + classifier_x = GridSearchCV(self.classifier, clf_param_grid) + + self._hat_e = classifier_x.fit(x, t.squeeze()) + + regressor_y = GridSearchCV(self.regressor, reg_param_grid) + + self._hat_m = regressor_y.fit(x, y.squeeze()) + + + @fitted + def score(self, t, m, x, y, hat_tau): + """Predicts score on data samples + + Parameters + ---------- + + hat_tau array-like, shape (n_samples) + estimated risk + """ + + hat_e = self._hat_e.predict_proba(x)[:, 1] + hat_m = self._hat_m.predict(x) + score = r_risk(y.squeeze(), t.squeeze(), hat_m, hat_e, hat_tau) + return score + + + def fit_treatment_propensity_x_nuisance(self, t, x): + """ Fits the nuisance parameter for the propensity P(T=1|X) + """ + self._classifier_t_x = self.classifier.fit(x, t) + + + def fit_treatment_propensity_xm_nuisance(self, t, m, x): + """ Fits the nuisance parameter for the propensity P(T=1|X, M) + """ + xm = np.hstack((x, m)) + self._classifier_t_xm = self.classifier.fit(xm, t) + + + def fit_mediator_nuisance(self, t, m, x): + """ Fits the nuisance parameter for the density f(M=m|T, X) + """ + # estimate mediator densities + clf_param_grid = {} + classifier_m = GridSearchCV(self.classifier, clf_param_grid) + + t_x = _get_interactions(False, t, x) + + # Fit classifier + self._classifier_m = classifier_m.fit(t_x, m.ravel()) + + + def fit_conditional_mean_outcome_nuisance(self, t, m, x, y): + """ Fits the nuisance for the conditional mean outcome for the density f(M=m|T, X) + """ + if len(m.shape) == 1: + mr = m.reshape(-1, 1) + else: + mr = np.copy(m) + x_t_mr = _get_interactions(False, x, t, mr) + + reg_param_grid = {} + + # estimate conditional mean outcomes + regressor_y = GridSearchCV(self.regressor, reg_param_grid) + + self._regressor_y = regressor_y.fit(x_t_mr, y) + + + def fit_cross_conditional_mean_outcome_nuisance(self, t, m, x, y): + """ Fits the cross conditional mean outcome E[E[Y|T=t,M,X]|T=t',X] + """ + + xm = np.hstack((x, m)) + + reg_param_grid = {} + + # estimate conditional mean outcomes + regressor_y = GridSearchCV(self.regressor, reg_param_grid) + + n = t.shape[0] + train = np.arange(n) + ( + mu_1mx_nested, # E[Y|T=1,M,X] predicted on train_nested set + mu_0mx_nested, # E[Y|T=0,M,X] predicted on train_nested set + ) = [np.zeros(n) for _ in range(2)] + + train1 = train[t[train] == 1] + train0 = train[t[train] == 0] + + train_mean, train_nested = np.array_split(train, 2) + # train_mean = train + # train_nested = train + train_mean1 = train_mean[t[train_mean] == 1] + train_mean0 = train_mean[t[train_mean] == 0] + train_nested1 = train_nested[t[train_nested] == 1] + train_nested0 = train_nested[t[train_nested] == 0] + + self.regressors = {} + + # predict E[Y|T=1,M,X] + self.regressors['y_t1_mx'] = clone(regressor_y) + self.regressors['y_t1_mx'].fit(xm[train_mean1], y[train_mean1]) + mu_1mx_nested[train_nested] = self.regressors['y_t1_mx'].predict(xm[train_nested]) + + # predict E[Y|T=0,M,X] + self.regressors['y_t0_mx'] = clone(regressor_y) + self.regressors['y_t0_mx'].fit(xm[train_mean0], y[train_mean0]) + mu_0mx_nested[train_nested] = self.regressors['y_t0_mx'].predict(xm[train_nested]) + + # predict E[E[Y|T=1,M,X]|T=0,X] + self.regressors['y_t1_x_t0'] = clone(regressor_y) + self.regressors['y_t1_x_t0'].fit(x[train_nested0], mu_1mx_nested[train_nested0]) + + # predict E[E[Y|T=0,M,X]|T=1,X] + self.regressors['y_t0_x_t1'] = clone(regressor_y) + self.regressors['y_t0_x_t1'].fit(x[train_nested1], mu_0mx_nested[train_nested1]) + + # predict E[Y|T=1,X] + self.regressors['y_t1_x'] = clone(regressor_y) + self.regressors['y_t1_x'].fit(x[train1], y[train1]) + + # predict E[Y|T=0,X] + self.regressors['y_t0_x'] = clone(regressor_y) + self.regressors['y_t0_x'].fit(x[train0], y[train0]) + + + def fit_cross_conditional_mean_outcome_nuisance_discrete(self, t, m, x, y): + n = len(y) + + # Initialisation + ( + mu_1mx, # E[Y|T=1,M,X] + mu_0mx, # E[Y|T=0,M,X] + ) = [np.zeros(n) for _ in range(2)] + + t0, m0 = np.zeros((n, 1)), np.zeros((n, 1)) + t1, m1 = np.ones((n, 1)), np.ones((n, 1)) + + x_t_m = _get_interactions(False, x, t, m) + x_t1_m = _get_interactions(False, x, t1, m) + x_t0_m = _get_interactions(False, x, t0, m) + + test_index = np.arange(n) + ind_t0 = t[test_index] == 0 + + reg_param_grid = {} + + # estimate conditional mean outcomes + regressor_y = GridSearchCV(self.regressor, reg_param_grid) + + self.regressors = {} + + # mu_tm model fitting + self.regressors['y_t_mx'] = clone(regressor_y).fit(x_t_m, y) + + # predict E[Y|T=t,M,X] + mu_1mx[test_index] = self.regressors['y_t_mx'].predict(x_t1_m[test_index, :]) + mu_0mx[test_index] = self.regressors['y_t_mx'].predict(x_t0_m[test_index, :]) + + for i, b in enumerate(np.unique(m)): + mb = m1 * b + + mu_1bx, mu_0bx = [np.zeros(n) for h in range(2)] + + # predict E[Y|T=t,M=m,X] + mu_0bx[test_index] = self.regressors['y_t_mx'].predict( + _get_interactions(False, x, t0, mb)[test_index, :]) + mu_1bx[test_index] = self.regressors['y_t_mx'].predict( + _get_interactions(False, x, t1, mb)[test_index, :]) + + # E[E[Y|T=1,M=m,X]|T=t,X] model fitting + self.regressors['reg_y_t1m{}_t0'.format(i)] = clone( + regressor_y).fit( + x[test_index, :][ind_t0, :], + mu_1bx[test_index][ind_t0]) + self.regressors['reg_y_t1m{}_t1'.format(i)] = clone( + regressor_y).fit( + x[test_index, :][~ind_t0, :], mu_1bx[test_index][~ind_t0]) + + # E[E[Y|T=0,M=m,X]|T=t,X] model fitting + self.regressors['reg_y_t0m{}_t0'.format(i)] = clone( + regressor_y).fit( + x[test_index, :][ind_t0, :], + mu_0bx[test_index][ind_t0]) + self.regressors['reg_y_t0m{}_t1'.format(i)] = clone( + regressor_y).fit( + x[test_index, :][~ind_t0, :], + mu_0bx[test_index][~ind_t0]) + diff --git a/src/med_bench/estimation/coefficient_product.py b/src/med_bench/estimation/coefficient_product.py new file mode 100644 index 0000000..949354a --- /dev/null +++ b/src/med_bench/estimation/coefficient_product.py @@ -0,0 +1,93 @@ +import numpy as np + +from sklearn.linear_model import RidgeCV + +from med_bench.estimation.base import Estimator +from med_bench.utils.constants import ALPHAS, CV_FOLDS, TINY +from med_bench.utils.decorators import fitted + + +class CoefficientProduct(Estimator): + + def __init__(self, clip : float, trim : float, regularize : bool, **kwargs): + """Coefficient product estimator + + Attributes: + clip (float): clipping the propensities + trim (float): remove propensities which are below the trim threshold + regularize (bool) : regularization parameter + + """ + super().__init__(**kwargs) + self._crossfit = 0 + self._regularize = regularize + self._clip = clip + self._trim = trim + + def fit(self, t, m, x, y): + """Fits nuisance parameters to data + + Parameters + ---------- + t array-like, shape (n_samples) + treatment value for each unit, binary + + m array-like, shape (n_samples) + mediator value for each unit, here m is necessary binary and uni- + dimensional + + x array-like, shape (n_samples, n_features_covariates) + covariates (potential confounders) values + + y array-like, shape (n_samples) + outcome value for each unit, continuous + + """ + self.fit_score_nuisances(t, m, x, y) + # estimate mediator densities + + if self._regularize: + alphas = ALPHAS + else: + alphas = [TINY] + if len(x.shape) == 1: + x = x.reshape(-1, 1) + if len(m.shape) == 1: + m = m.reshape(-1, 1) + if len(t.shape) == 1: + t = t.reshape(-1, 1) + + self._coef_t_m = np.zeros(m.shape[1]) + for i in range(m.shape[1]): + m_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) \ + .fit(np.hstack((x, t)), m[:, i]) + self._coef_t_m[i] = m_reg.coef_[-1] + y_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) \ + .fit(np.hstack((x, t, m)), y.ravel()) + + self._coef_y = y_reg.coef_ + + self._fitted = True + + if self.verbose: + print("Nuisance models fitted") + + + @fitted + def estimate(self, t, m, x, y): + """Estimates causal effect on data + + """ + direct_effect_treated = self._coef_y[x.shape[1]] + direct_effect_control = direct_effect_treated + indirect_effect_treated = sum(self._coef_y[x.shape[1] + 1:] * self._coef_t_m) + indirect_effect_control = indirect_effect_treated + + causal_effects = { + 'total_effect': direct_effect_treated+indirect_effect_control, + 'direct_effect_treated': direct_effect_treated, + 'direct_effect_control': direct_effect_control, + 'indirect_effect_treated': indirect_effect_treated, + 'indirect_effect_control': indirect_effect_control + } + return causal_effects diff --git a/src/med_bench/estimation/dml.py b/src/med_bench/estimation/dml.py new file mode 100644 index 0000000..2444c0e --- /dev/null +++ b/src/med_bench/estimation/dml.py @@ -0,0 +1,181 @@ +import numpy as np + + +from med_bench.estimation.base import Estimator +from med_bench.nuisances.propensities import estimate_treatment_probabilities +from med_bench.nuisances.cross_conditional_outcome import estimate_cross_conditional_mean_outcome_nesting + + +class DoubleMachineLearning(Estimator): + """Implementation of double machine learning + + Parameters + ---------- + settings (dict): dictionnary of parameters + lbda (float): regularization parameter + support_vec_tol (float): tolerance for discarding non-supporting vectors + if |alpha_i| < support_vec_tol * lbda then vector is discarded + verbose (int): in {0, 1} + """ + + def __init__(self, procedure : str, density_estimation_method : str, clip : float, trim : float, normalized : bool, sample_split : int, **kwargs): + super().__init__(**kwargs) + + self._crossfit = 0 + self._procedure = procedure + self._density_estimation_method = density_estimation_method + self._clip = clip + self._trim = trim + self._normalized = normalized + self._sample_split = sample_split + + def resize(self, t, m, x, y): + """Resize data for the right shape + + Parameters + ---------- + t array-like, shape (n_samples) + treatment value for each unit, binary + + m array-like, shape (n_samples) + mediator value for each unit, here m is necessary binary and uni- + dimensional + + x array-like, shape (n_samples, n_features_covariates) + covariates (potential confounders) values + + y array-like, shape (n_samples) + outcome value for each unit, continuous + """ + if len(y) != len(y.ravel()): + raise ValueError("Multidimensional y is not supported") + if len(t) != len(t.ravel()): + raise ValueError("Multidimensional t is not supported") + + n = len(y) + if len(x.shape) == 1: + x.reshape(n, 1) + if len(m.shape) == 1: + m = m.reshape(n, 1) + + if n != len(x) or n != len(m) or n != len(t): + raise ValueError( + "Inputs don't have the same number of observations") + + y = y.ravel() + t = t.ravel() + + return t, m, x, y + + + def fit(self, t, m, x, y): + """Fits nuisance parameters to data + + """ + self.fit_score_nuisances(t, m, x, y) + t, m, x, y = self.resize(t, m, x, y) + + self.fit_treatment_propensity_x_nuisance(t, x) + self.fit_treatment_propensity_xm_nuisance(t, m, x) + self.fit_cross_conditional_mean_outcome_nuisance(t, m, x, y) + self._fitted = True + + if self.verbose: + print("Nuisance models fitted") + + + def estimate(self, t, m, x, y): + """Estimates causal effect on data + + """ + t, m, x, y = self.resize(t, m, x, y) + + p_x, p_xm = estimate_treatment_probabilities(t, + m, + x, + self._crossfit, + self._classifier_t_x, + self._classifier_t_xm) + + + mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 = estimate_cross_conditional_mean_outcome_nesting(m, x, y, self.regressors) + # trimming + not_trimmed = ( + (((1 - p_xm) * p_x) >= self._trim) + * ((1 - p_x) >= self._trim) + * (p_x >= self._trim) + * ((p_xm * (1 - p_x)) >= self._trim) + ) + + var_name = [ + "p_x", + "p_xm", + "mu_1mx", + "mu_0mx", + "E_mu_t1_t0", + "E_mu_t0_t1", + "E_mu_t1_t1", + "E_mu_t0_t0", + ] + for var in var_name: + exec(f"{var} = {var}[not_trimmed]") + nobs = np.sum(not_trimmed) + + # score computing + if self._normalized: + sum_score_m1 = np.mean(t / p_x) + sum_score_m0 = np.mean((1 - t) / (1 - p_x)) + sum_score_t1m0 = np.mean(t * (1 - p_xm) / (p_xm * (1 - p_x))) + sum_score_t0m1 = np.mean((1 - t) * p_xm / ((1 - p_xm) * p_x)) + y1m1 = (t / p_x * (y - E_mu_t1_t1)) / sum_score_m1 + E_mu_t1_t1 + y0m0 = (((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / sum_score_m0 + + E_mu_t0_t0) + y1m0 = ( + (t * (1 - p_xm) / (p_xm * (1 - p_x)) * (y - mu_1mx)) + / sum_score_t1m0 + ( + (1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0)) + / sum_score_m0 + E_mu_t1_t0 + ) + y0m1 = ( + ((1 - t) * p_xm / ((1 - p_xm) * p_x) * (y - mu_0mx)) + / sum_score_t0m1 + + (t / p_x * (mu_0mx - E_mu_t0_t1)) / sum_score_m1 + + E_mu_t0_t1 + ) + else: + y1m1 = t / p_x * (y - E_mu_t1_t1) + E_mu_t1_t1 + y0m0 = (1 - t) / (1 - p_x) * (y - E_mu_t0_t0) + E_mu_t0_t0 + y1m0 = ( + t * (1 - p_xm) / (p_xm * (1 - p_x)) * (y - mu_1mx) + + (1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0) + + E_mu_t1_t0 + ) + y0m1 = ( + (1 - t) * p_xm / ((1 - p_xm) * p_x) * (y - mu_0mx) + + t / p_x * (mu_0mx - E_mu_t0_t1) + + E_mu_t0_t1 + ) + + # mean score computing + eta_t1t1 = np.mean(y1m1) + eta_t0t0 = np.mean(y0m0) + eta_t1t0 = np.mean(y1m0) + eta_t0t1 = np.mean(y0m1) + + # effects computing + total_effect = eta_t1t1 - eta_t0t0 + + direct_effect_treated = eta_t1t1 - eta_t0t1 + direct_effect_control = eta_t1t0 - eta_t0t0 + indirect_effect_treated = eta_t1t1 - eta_t1t0 + indirect_effect_control = eta_t0t1 - eta_t0t0 + + causal_effects = { + 'total_effect': total_effect, + 'direct_effect_treated': direct_effect_treated, + 'direct_effect_control': direct_effect_control, + 'indirect_effect_treated': indirect_effect_treated, + 'indirect_effect_control': indirect_effect_control + } + + return causal_effects diff --git a/src/med_bench/estimation/g_computation.py b/src/med_bench/estimation/g_computation.py new file mode 100644 index 0000000..ae3d20f --- /dev/null +++ b/src/med_bench/estimation/g_computation.py @@ -0,0 +1,190 @@ +import numpy as np + +from sklearn.cluster import KMeans + +from med_bench.estimation.base import Estimator + +from med_bench.utils.decorators import fitted +from med_bench.utils.utils import (is_array_integer) + +from med_bench.nuisances.density import estimate_mediators_probabilities +from med_bench.nuisances.conditional_outcome import estimate_conditional_mean_outcome +from med_bench.nuisances.cross_conditional_outcome import estimate_cross_conditional_mean_outcome_nesting + +class GComputation(Estimator): + """GComputation estimation method class + """ + def __init__(self, crossfit : int, procedure : str, **kwargs): + """Initalization of the GComputation estimation method class + + Parameters + ---------- + crossfit : int + 1 or 0 + procedure : str + nesting or discrete + """ + super().__init__(**kwargs) + + self._crossfit = crossfit + self._procedure = procedure + + def resize(self, t, m, x, y): + """Resize data for the right shape + + Parameters + ---------- + t array-like, shape (n_samples) + treatment value for each unit, binary + + m array-like, shape (n_samples) + mediator value for each unit, here m is necessary binary and uni- + dimensional + + x array-like, shape (n_samples, n_features_covariates) + covariates (potential confounders) values + + y array-like, shape (n_samples) + outcome value for each unit, continuous + """ + if len(y) != len(y.ravel()): + raise ValueError("Multidimensional y is not supported") + if len(t) != len(t.ravel()): + raise ValueError("Multidimensional t is not supported") + + n = len(y) + if len(x.shape) == 1: + x.reshape(n, 1) + if len(m.shape) == 1: + m.reshape(n, 1) + + if n != len(x) or n != len(m) or n != len(t): + raise ValueError( + "Inputs don't have the same number of observations") + + y = y.ravel() + t = t.ravel() + + return t, m, x, y + + + def fit(self, t, m, x, y): + """Fits nuisance parameters to data + + """ + + self.fit_score_nuisances(t, m, x, y) + t, m, x, y = self.resize(t, m, x, y) + + if self._procedure == 'discrete': + if not is_array_integer(m): + self._bucketizer = KMeans(n_clusters=10, random_state=self.rng, + n_init="auto").fit(m) + m = self._bucketizer.predict(m) + self.fit_mediator_nuisance(t, m, x) + self.fit_conditional_mean_outcome_nuisance(t, m, x, y) + + elif self._procedure == 'nesting': + self.fit_cross_conditional_mean_outcome_nuisance(t, m, x, y) + else: + raise NotImplementedError + self._fitted = True + + if self.verbose: + print("Nuisance models fitted") + + def estimate_discrete(self, t, m, x, y): + """Estimates causal effect on data using a discrete summation on + mediators + + """ + + # estimate mediator densities + f_t0, f_t1 = estimate_mediators_probabilities(t, m, x, y, + self._crossfit, + self._classifier_m, + False) + + # estimate conditional mean outcomes + mu_t0, mu_t1, _, _ = ( + estimate_conditional_mean_outcome(t, m, x, y, + self._crossfit, + self._regressor_y, + False)) + + n = len(y) + + direct_effect_treated = 0 + direct_effect_control = 0 + indirect_effect_treated = 0 + indirect_effect_control = 0 + + for f_1bx, f_0bx, mu_1bx, mu_0bx in zip(f_t1, f_t0, mu_t1, mu_t0): + direct_effect_ib = mu_1bx - mu_0bx + direct_effect_treated += direct_effect_ib * f_1bx + direct_effect_control += direct_effect_ib * f_0bx + indirect_effect_ib = f_1bx - f_0bx + indirect_effect_treated += indirect_effect_ib * mu_1bx + indirect_effect_control += indirect_effect_ib * mu_0bx + + direct_effect_treated = direct_effect_treated.sum() / n + direct_effect_control = direct_effect_control.sum() / n + indirect_effect_treated = indirect_effect_treated.sum() / n + indirect_effect_control = indirect_effect_control.sum() / n + + total_effect = direct_effect_control + indirect_effect_treated + + causal_effects = { + 'total_effect': total_effect, + 'direct_effect_treated': direct_effect_treated, + 'direct_effect_control': direct_effect_control, + 'indirect_effect_treated': indirect_effect_treated, + 'indirect_effect_control': indirect_effect_control + } + return causal_effects + + def estimate_nesting(self, t, m, x, y): + + mu_0mx, mu_1mx, y0m0, y0m1, y1m0, y1m1 = estimate_cross_conditional_mean_outcome_nesting(m, x, y, self.regressors) + + # mean score computing + eta_t1t1 = np.mean(y1m1) + eta_t0t0 = np.mean(y0m0) + eta_t1t0 = np.mean(y1m0) + eta_t0t1 = np.mean(y0m1) + + # effects computing + total_effect = eta_t1t1 - eta_t0t0 + + direct_effect_treated = eta_t1t1 - eta_t0t1 + direct_effect_control = eta_t1t0 - eta_t0t0 + indirect_effect_treated = eta_t1t1 - eta_t1t0 + indirect_effect_control = eta_t0t1 - eta_t0t0 + + causal_effects = { + 'total_effect': total_effect, + 'direct_effect_treated': direct_effect_treated, + 'direct_effect_control': direct_effect_control, + 'indirect_effect_treated': indirect_effect_treated, + 'indirect_effect_control': indirect_effect_control + } + + return causal_effects + + @fitted + def estimate(self, t, m, x, y): + """Estimates causal effect on data + + """ + + t, m, x, y = self.resize(t, m, x, y) + + if self._procedure == 'discrete': + if not is_array_integer(m): + m = self._bucketizer.predict(m) + return self.estimate_discrete(t, m, x, y) + + elif self._procedure == 'nesting': + return self.estimate_nesting(t, m, x, y) + + diff --git a/src/med_bench/estimation/ipw.py b/src/med_bench/estimation/ipw.py new file mode 100644 index 0000000..24e3ede --- /dev/null +++ b/src/med_bench/estimation/ipw.py @@ -0,0 +1,121 @@ +import numpy as np + +from med_bench.nuisances.propensities import estimate_treatment_probabilities + +from med_bench.estimation.base import Estimator +from med_bench.utils.decorators import fitted + + +class ImportanceWeighting(Estimator): + + def __init__(self, clip : float, trim : float, **kwargs): + """IPW estimator + + Attributes: + _clip (float): clipping the propensities + _trim (float): remove propensities which are below the trim threshold + + """ + super().__init__(**kwargs) + self._crossfit = 0 + self._clip = clip + self._trim = trim + + def resize(self, t, m, x, y): + """Resize data for the right shape + + Parameters + ---------- + t array-like, shape (n_samples) + treatment value for each unit, binary + + m array-like, shape (n_samples) + mediator value for each unit, here m is necessary binary and uni- + dimensional + + x array-like, shape (n_samples, n_features_covariates) + covariates (potential confounders) values + + y array-like, shape (n_samples) + outcome value for each unit, continuous + """ + if len(y) != len(y.ravel()): + raise ValueError("Multidimensional y is not supported") + if len(t) != len(t.ravel()): + raise ValueError("Multidimensional t is not supported") + + n = len(y) + if len(x.shape) == 1: + x.reshape(n, 1) + if len(m.shape) == 1: + m = m.reshape(n, 1) + + if n != len(x) or n != len(m) or n != len(t): + raise ValueError( + "Inputs don't have the same number of observations") + + y = y.ravel() + t = t.ravel() + + return t, m, x, y + + def fit(self, t, m, x, y): + """Fits nuisance parameters to data + + """ + self.fit_score_nuisances(t, m, x, y) + t, m, x, y = self.resize(t, m, x, y) + + self.fit_treatment_propensity_x_nuisance(t, x) + self.fit_treatment_propensity_xm_nuisance(t, m, x) + + self._fitted = True + + if self.verbose: + print("Nuisance models fitted") + + @fitted + def estimate(self, t, m, x, y): + """Estimates causal effect on data + + """ + t, m, x, y = self.resize(t, m, x, y) + p_x, p_xm = estimate_treatment_probabilities(t, + m, + x, + self._crossfit, + self._classifier_t_x, + self._classifier_t_xm) + + ind = ((p_xm > self._trim) & (p_xm < (1 - self._trim))) + y, t, p_x, p_xm = y[ind], t[ind], p_x[ind], p_xm[ind] + + # note on the names, ytmt' = Y(t, M(t')), the treatment needs to be + # binary but not the mediator + p_x = np.clip(p_x, self._clip, 1 - self._clip) + p_xm = np.clip(p_xm, self._clip, 1 - self._clip) + + # importance weighting + y1m1 = np.sum(y * t / p_x) / np.sum(t / p_x) + y1m0 = np.sum(y * t * (1 - p_xm) / (p_xm * (1 - p_x))) /\ + np.sum(t * (1 - p_xm) / (p_xm * (1 - p_x))) + y0m0 = np.sum(y * (1 - t) / (1 - p_x)) /\ + np.sum((1 - t) / (1 - p_x)) + y0m1 = np.sum(y * (1 - t) * p_xm / ((1 - p_xm) * p_x)) /\ + np.sum((1 - t) * p_xm / ((1 - p_xm) * p_x)) + + total_effect = y1m1 - y0m0 + direct_effect_treated = y1m1 - y0m1 + direct_effect_control = y1m0 - y0m0 + indirect_effect_treated = y1m1 - y1m0 + indirect_effect_control = y0m1 - y0m0 + + causal_effects = { + 'total_effect': total_effect, + 'direct_effect_treated': direct_effect_treated, + 'direct_effect_control': direct_effect_control, + 'indirect_effect_treated': indirect_effect_treated, + 'indirect_effect_control': indirect_effect_control + } + + return causal_effects diff --git a/src/med_bench/estimation/mr.py b/src/med_bench/estimation/mr.py new file mode 100644 index 0000000..dbeb17e --- /dev/null +++ b/src/med_bench/estimation/mr.py @@ -0,0 +1,279 @@ +import numpy as np +from sklearn.cluster import KMeans + +from med_bench.estimation.base import Estimator +from med_bench.utils.decorators import fitted +from med_bench.utils.utils import (is_array_integer) +from med_bench.nuisances.cross_conditional_outcome import estimate_cross_conditional_mean_outcome_discrete, estimate_cross_conditional_mean_outcome_nesting +from med_bench.nuisances.propensities import estimate_treatment_propensity_x, estimate_treatment_probabilities +from med_bench.nuisances.density import estimate_mediator_density, estimate_mediators_probabilities + + +class MultiplyRobust(Estimator): + """Implementation of multiply robust + + Args: + settings (dict): dictionnary of parameters + lbda (float): regularization parameter + support_vec_tol (float): tolerance for discarding non-supporting vectors + if |alpha_i| < support_vec_tol * lbda then vector is discarded + verbose (int): in {0, 1} + """ + + def __init__(self, procedure : str, ratio : str, density_estimation_method : str, clip : float, normalized, **kwargs): + super().__init__(**kwargs) + + self._crossfit = 0 + self._procedure = procedure + self._ratio = ratio + self._density_estimation = density_estimation_method + self._clip = clip + self._normalized = normalized + + def resize(self, t, m, x, y): + """Resize data for the right shape + + Parameters + ---------- + t array-like, shape (n_samples) + treatment value for each unit, binary + + m array-like, shape (n_samples) + mediator value for each unit, here m is necessary binary and uni- + dimensional + + x array-like, shape (n_samples, n_features_covariates) + covariates (potential confounders) values + + y array-like, shape (n_samples) + outcome value for each unit, continuous + """ + if len(y) != len(y.ravel()): + raise ValueError("Multidimensional y is not supported") + if len(t) != len(t.ravel()): + raise ValueError("Multidimensional t is not supported") + + n = len(y) + if len(x.shape) == 1: + x.reshape(n, 1) + if len(m.shape) == 1: + m.reshape(n, 1) + + if n != len(x) or n != len(m) or n != len(t): + raise ValueError( + "Inputs don't have the same number of observations") + + y = y.ravel() + t = t.ravel() + # m = m.ravel() + + return t, m, x, y + + + def fit(self, t, m, x, y): + """Fits nuisance parameters to data + + """ + # bucketize if needed + t, m, x, y = self.resize(t, m, x, y) + + # fit nuisance functions + self.fit_score_nuisances(t, m, x, y) + + if self._ratio == 'density': + self.fit_treatment_propensity_x_nuisance(t, x) + self.fit_mediator_nuisance(t, m, x) + + elif self._ratio == 'propensities': + self.fit_treatment_propensity_x_nuisance(t, x) + self.fit_treatment_propensity_xm_nuisance(t, m, x) + + else: + raise NotImplementedError + + if self._procedure == 'nesting': + self.fit_cross_conditional_mean_outcome_nuisance(t, m, x, y) + + elif self._procedure == 'discrete': + + if not is_array_integer(m): + self._bucketizer = KMeans(n_clusters=10, random_state=self.rng, + n_init="auto").fit(m) + m = self._bucketizer.predict(m) + self.fit_mediator_nuisance(t, m, x) + self.fit_cross_conditional_mean_outcome_nuisance_discrete(t, m, x, y) + + else: + raise NotImplementedError + + self._fitted = True + + if self.verbose: + print("Nuisance models fitted") + + + @fitted + def estimate(self, t, m, x, y): + """Estimates causal effect on data + + """ + # Format checking + t, m, x, y = self.resize(t, m, x, y) + + if self._ratio == 'density': + f_m0x, f_m1x = estimate_mediator_density(t, m, x, y, + self._crossfit, + self._classifier_m, + False) + p_x = estimate_treatment_propensity_x(t, + m, + x, + self._crossfit, + self._classifier_t_x) + ratio_t1_m0 = f_m0x / (p_x * f_m1x) + ratio_t0_m1 = f_m1x / ((1 - p_x) * f_m0x) + + elif self._ratio == 'propensities': + p_x, p_xm = estimate_treatment_probabilities(t, + m, + x, + self._crossfit, + self._classifier_t_x, + self._classifier_t_xm) + ratio_t1_m0 = (1-p_xm) / ((1 - p_x) * p_xm) + ratio_t0_m1 = p_xm / ((1 - p_xm) * p_x) + + if self._procedure == 'nesting': + + + # p_x = estimate_treatment_propensity_x(t, + # m, + # x, + # self._crossfit, + # self._classifier_t_x) + + # _, _, f_m0x, f_m1x = estimate_mediator_density(t, + # m, + # x, + # y, + # self._crossfit, + # self._classifier_m, + # False) + + mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 = ( + estimate_cross_conditional_mean_outcome_nesting(m, x, y, self.regressors)) + + + else: + if not is_array_integer(m): + m = self._bucketizer.predict(m) + + # p_x = estimate_treatment_propensity_x(t, + # m, + # x, + # self._crossfit, + # self._classifier_t_x) + + f_t0, f_t1 = estimate_mediators_probabilities(t, + m, + x, + y, + self._crossfit, + self._classifier_m, + False) + + f = f_t0, f_t1 + mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 = ( + estimate_cross_conditional_mean_outcome_discrete(m, x, y, f, self.regressors)) + + + # clipping + # p_x_clip = p_x != np.clip(p_x, self._clip, 1 - self._clip) + # f_m0x_clip = f_m0x != np.clip(f_m0x, self._clip, 1 - self._clip) + # f_m1x_clip = f_m1x != np.clip(f_m1x, self._clip, 1 - self._clip) + # clipped = p_x_clip + f_m0x_clip + f_m1x_clip + + # var_name = ["t", "y", "p_x", "f_m0x", "f_m1x", "mu_1mx", "mu_0mx"] + # var_name += ["E_mu_t1_t1", "E_mu_t0_t0", "E_mu_t1_t0", "E_mu_t0_t1"] + # n_discarded = 0 + # for var in var_name: + # exec(f"{var} = {var}[~clipped]") + # n_discarded += np.sum(clipped) + + # score computing + if self._normalized: + sum_score_m1 = np.mean(t / p_x) + sum_score_m0 = np.mean((1 - t) / (1 - p_x)) + # sum_score_t1m0 = np.mean((t / p_x) * (f_m0x / f_m1x)) + # sum_score_t0m1 = np.mean((1 - t) / (1 - p_x) * (f_m1x / f_m0x)) + sum_score_t1m0 = np.mean(t * ratio_t1_m0) + sum_score_t0m1 = np.mean((1 - t) * ratio_t0_m1) + + y1m1 = (t / p_x * (y - E_mu_t1_t1)) / sum_score_m1 + E_mu_t1_t1 + y0m0 = (((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / sum_score_m0 + + E_mu_t0_t0) + # y1m0 = ( + # ((t / p_x) * (f_m0x / f_m1x) * ( + # y - mu_1mx)) / sum_score_t1m0 + # + ((1 - t) / (1 - p_x) * ( + # mu_1mx - E_mu_t1_t0)) / sum_score_m0 + # + E_mu_t1_t0 + # ) + y1m0 = ( + (t * ratio_t1_m0 * ( + y - mu_1mx)) / sum_score_t1m0 + + ((1 - t) / (1 - p_x) * ( + mu_1mx - E_mu_t1_t0)) / sum_score_m0 + + E_mu_t1_t0 + ) + # y0m1 = ( + # ((1 - t) / (1 - p_x) * (f_m1x / f_m0x) * (y - mu_0mx)) + # / sum_score_t0m1 + t / p_x * ( + # mu_0mx - E_mu_t0_t1) / sum_score_m1 + # + E_mu_t0_t1 + # ) + y0m1 = ( + ((1 - t) * ratio_t0_m1 * (y - mu_0mx)) + / sum_score_t0m1 + t / p_x * ( + mu_0mx - E_mu_t0_t1) / sum_score_m1 + + E_mu_t0_t1 + ) + else: + y1m1 = t / p_x * (y - E_mu_t1_t1) + E_mu_t1_t1 + y0m0 = (1 - t) / (1 - p_x) * (y - E_mu_t0_t0) + E_mu_t0_t0 + # y1m0 = ( + # (t / p_x) * (f_m0x / f_m1x) * (y - mu_1mx) + # + (1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0) + # + E_mu_t1_t0 + # ) + # y0m1 = ( + # (1 - t) / (1 - p_x) * (f_m1x / f_m0x) * (y - mu_0mx) + # + t / p_x * (mu_0mx - E_mu_t0_t1) + # + E_mu_t0_t1 + # ) + y1m0 = ( + t * ratio_t1_m0 * (y - mu_1mx) + + (1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0) + + E_mu_t1_t0 + ) + y0m1 = ( + (1 - t) * ratio_t0_m1 * (y - mu_0mx) + + t / p_x * (mu_0mx - E_mu_t0_t1) + + E_mu_t0_t1 + ) + + # effects computing + total = np.mean(y1m1 - y0m0) + direct1 = np.mean(y1m1 - y0m1) + direct0 = np.mean(y1m0 - y0m0) + indirect1 = np.mean(y1m1 - y1m0) + indirect0 = np.mean(y0m1 - y0m0) + + causal_effects = { + 'total_effect': total, + 'direct_effect_treated': direct1, + 'direct_effect_control': direct0, + 'indirect_effect_treated': indirect1, + 'indirect_effect_control': indirect0 + } + return causal_effects diff --git a/src/med_bench/estimation/tmle.py b/src/med_bench/estimation/tmle.py new file mode 100644 index 0000000..a8b8028 --- /dev/null +++ b/src/med_bench/estimation/tmle.py @@ -0,0 +1,267 @@ +import numpy as np +from sklearn.base import clone +from sklearn.linear_model import LinearRegression + +from med_bench.estimation.base import Estimator +from med_bench.nuisances.utils import (_get_regressor) + +ALPHA=10 + +from med_bench.utils.decorators import fitted +from med_bench.utils.utils import _get_interactions +from med_bench.nuisances.density import estimate_mediator_density +from med_bench.nuisances.propensities import estimate_treatment_probabilities, estimate_treatment_propensity_x + +class TMLE(Estimator): + """Implementation of targeted maximum likelihood estimator + + Parameters + ---------- + settings (dict): dictionnary of parameters + lbda (float): regularization parameter + support_vec_tol (float): tolerance for discarding non-supporting vectors + if |alpha_i| < support_vec_tol * lbda then vector is discarded + verbose (int): in {0, 1} + """ + def __init__(self, settings, verbose=0): + super(TMLE, self).__init__(settings=settings, verbose=verbose) + + self._crossfit = 0 + self._procedure = self._settings['procedure'] + self._ratio = self._settings['ratio'] + self._density_estimation = 'kde' + self._clip = self._settings['clip'] + self._normalized = self._settings['normalized'] + + def resize(self, t, m, x, y): + """Resize data for the right shape + + Parameters + ---------- + t array-like, shape (n_samples) + treatment value for each unit, binary + + m array-like, shape (n_samples) + mediator value for each unit, here m is necessary binary and uni- + dimensional + + x array-like, shape (n_samples, n_features_covariates) + covariates (potential confounders) values + + y array-like, shape (n_samples) + outcome value for each unit, continuous + """ + if len(y) != len(y.ravel()): + raise ValueError("Multidimensional y is not supported") + if len(t) != len(t.ravel()): + raise ValueError("Multidimensional t is not supported") + + n = len(y) + if len(x.shape) == 1: + x.reshape(n, 1) + if len(m.shape) == 1: + m.reshape(n, 1) + + if n != len(x) or n != len(m) or n != len(t): + raise ValueError( + "Inputs don't have the same number of observations") + + y = y.ravel() + t = t.ravel() + + return t, m, x, y + + + def one_step_correction_direct(self, t, m, x, y): + + n = t.shape[0] + t, m, x, y = self.resize(t, m, x, y) + t0 = np.zeros((n)) + t1 = np.ones((n)) + + # estimate mediator densities + if self._ratio == 'density': + f_m0x, f_m1x = estimate_mediator_density(t, m, x, y, + self._crossfit, + self._classifier_m, + False) + p_x = estimate_treatment_propensity_x(t, + m, + x, + self._crossfit, + self._classifier_t_x) + ratio = f_m0x / (p_x * f_m1x) + + elif self._ratio == 'propensities': + p_x, p_xm = estimate_treatment_probabilities(t, + m, + x, + self._crossfit, + self._classifier_t_x, + self._classifier_t_xm) + ratio = (1-p_xm) / ((1 - p_x) * p_xm) + + + h_corrector = t * ratio - (1 - t)/(1 - p_x) + + x_t_mr = _get_interactions(False, x, t, m) + mu_tmx = self._regressor_y.predict(x_t_mr) + # import pdb; pdb.set_trace() + reg = LinearRegression(fit_intercept=False).fit(h_corrector.reshape(-1, 1), (y-mu_tmx).squeeze()) + epsilon_h = reg.coef_ + # epsilon_h = 0 + print(epsilon_h) + + mu_t0_mx = self._regressor_y.predict(_get_interactions(False, x, t0, m)) + h_corrector_t0 = t0 * ratio - (1 - t0)/(1 - p_x) + mu_t1_mx = self._regressor_y.predict(_get_interactions(False, x, t1, m)) + h_corrector_t1 = t1 * ratio - (1 - t1)/(1 - p_x) + mu_t0_mx_star = mu_t0_mx + epsilon_h * h_corrector_t0 + mu_t1_mx_star = mu_t1_mx + epsilon_h * h_corrector_t1 + + regressor_y = _get_regressor(self._regularize, + self._use_forest) + reg_cross = clone(regressor_y) + reg_cross.fit(x[t==0], (mu_t1_mx_star[t==0] - mu_t0_mx_star[t==0]).squeeze()) + + theta_0 = reg_cross.predict(x) + c_corrector = (1 - t)/(1 - p_x) + reg = LinearRegression(fit_intercept=False).fit(c_corrector.reshape(-1, 1)[t==0], (mu_t1_mx_star[t==0] - y[t==0]-theta_0[t==0]).squeeze()) + epsilon_c = reg.coef_ + + theta_0_star = theta_0 + epsilon_c*c_corrector + theta_0_star = np.mean(theta_0_star) + + return theta_0_star + + + def one_step_correction_indirect(self, t, m, x, y): + + n = t.shape[0] + t, m, x, y = self.resize(t, m, x, y) + t0 = np.zeros((n)) + t1 = np.ones((n)) + + # estimate mediator densities + if self._ratio == 'density': + f_m0x, f_m1x = estimate_mediator_density(t, m, x, y, + self._crossfit, + self._classifier_m, + False) + p_x = estimate_treatment_propensity_x(t, + m, + x, + self._crossfit, + self._classifier_t_x) + ratio = f_m0x / (p_x * f_m1x) + + elif self._ratio == 'propensities': + p_x, p_xm = estimate_treatment_probabilities(t, + m, + x, + self._crossfit, + self._classifier_t_x, + self._classifier_t_xm) + ratio = (1-p_xm) / ((1 - p_x) * p_xm) + + h_corrector = t / p_x - t * ratio + + x_t_mr = _get_interactions(False, x, t, m) + mu_tmx = self._regressor_y.predict(x_t_mr) + reg = LinearRegression(fit_intercept=False).fit(h_corrector.reshape(-1, 1), (y-mu_tmx).squeeze()) + epsilon_h = reg.coef_ + # epsilon_h = 0 + print('indirect', epsilon_h) + + # mu_t0_mx = self._regressor_y.predict(_get_interactions(False, x, t0, m)) + # h_corrector_t0 = t0 * f_t0 / (p_x * f_t1) - (1 - t0)/(1 - p_x) + mu_t1_mx = self._regressor_y.predict(_get_interactions(False, x, t1, m)) + h_corrector_t1 = t1 / p_x - t1 * ratio + # mu_t0_mx_star = mu_t0_mx + epsilon_h * h_corrector_t0 + mu_t1_mx_star = mu_t1_mx + epsilon_h * h_corrector_t1 + + + regressor_y = _get_regressor(self._regularize, + self._use_forest) + + + + # reg_cross.fit(x, (mu_t1_mx_star).squeeze()) + + # omega_t = reg_cross.predict(x) + # c_corrector = (2*t - 1)/p_x[:, None] + # reg = LinearRegression(fit_intercept=False).fit(c_corrector.reshape(-1, 1)[t==0], (mu_t1_mx_star - omega_t).squeeze()) + # epsilon_c = reg.coef_ + + + + reg_cross = clone(regressor_y) + reg_cross.fit(x[t==0], mu_t1_mx_star[t==0]) + omega_t0x = reg_cross.predict(x) + c_corrector_t0 = (2*t0 - 1) / p_x[:, None] + + reg = LinearRegression(fit_intercept=False).fit(c_corrector_t0[t==0], (mu_t1_mx_star[t==0]-omega_t0x[t==0]).squeeze()) + epsilon_c_t0 = reg.coef_ + # epsilon_c_t0 = 0 + omega_t0x_star = omega_t0x + epsilon_c_t0*c_corrector_t0 + + reg_cross = clone(regressor_y) + reg_cross.fit(x[t==1], y[t==1]) + omega_t1x = reg_cross.predict(x) + c_corrector_t1 = (2*t1 - 1) / p_x[:,None] + reg = LinearRegression(fit_intercept=False).fit(c_corrector_t1[t==1], (y[t==1]-omega_t1x[t==1]).squeeze()) + epsilon_c_t1 = reg.coef_ + # epsilon_c_t1 = 0 + omega_t1x_star = omega_t1x + epsilon_c_t1*c_corrector_t1 + delta_1 = np.mean(omega_t1x_star - omega_t0x_star) + + + return delta_1 + + + def fit(self, t, m, x, y): + """Fits nuisance parameters to data + + """ + # bucketize if needed + t, m, x, y = self.resize(t, m, x, y) + + # fit nuisance functions + self.fit_score_nuisances(t, m, x, y) + + self.fit_treatment_propensity_x_nuisance(t, x) + self.fit_conditional_mean_outcome_nuisance(t, m, x, y) + + if self._ratio == 'density': + self.fit_mediator_nuisance(t, m, x) + + elif self._ratio == 'propensities': + self.fit_treatment_propensity_xm_nuisance(t, m, x) + + self._fitted = True + + if self.verbose: + print("Nuisance models fitted") + + + @fitted + def estimate(self, t, m, x, y): + """Estimates causal effect on data + + """ + theta_0 = self.one_step_correction_direct(t, m, x, y) + delta_1 = self.one_step_correction_indirect(t, m, x, y) + total_effect = theta_0 + delta_1 + direct_effect_treated = np.copy(theta_0) + direct_effect_control = theta_0 + indirect_effect_treated = delta_1 + indirect_effect_control = np.copy(delta_1) + + causal_effects = { + 'total_effect': total_effect, + 'direct_effect_treated': direct_effect_treated, + 'direct_effect_control': direct_effect_control, + 'indirect_effect_treated': indirect_effect_treated, + 'indirect_effect_control': indirect_effect_control + } + return causal_effects From ea383556d38f4125fd2476a95aa224671fbc71cf Mon Sep 17 00:00:00 2001 From: brash6 Date: Thu, 1 Aug 2024 18:17:33 +0200 Subject: [PATCH 03/84] nuisances functions --- .../nuisances/conditional_outcome.py | 79 +++++ .../nuisances/cross_conditional_outcome.py | 224 +++++++++++++ src/med_bench/nuisances/density.py | 315 ++++++++++++++++++ src/med_bench/nuisances/propensities.py | 77 +++++ src/med_bench/nuisances/utils.py | 83 +++++ 5 files changed, 778 insertions(+) create mode 100644 src/med_bench/nuisances/conditional_outcome.py create mode 100644 src/med_bench/nuisances/cross_conditional_outcome.py create mode 100644 src/med_bench/nuisances/density.py create mode 100644 src/med_bench/nuisances/propensities.py create mode 100644 src/med_bench/nuisances/utils.py diff --git a/src/med_bench/nuisances/conditional_outcome.py b/src/med_bench/nuisances/conditional_outcome.py new file mode 100644 index 0000000..5df10ad --- /dev/null +++ b/src/med_bench/nuisances/conditional_outcome.py @@ -0,0 +1,79 @@ +""" +the objective of this script is to provide nuisance estimators +for mediation in causal inference +""" + +import numpy as np + +from med_bench.utils.utils import _get_train_test_lists, _get_interactions + + +def estimate_conditional_mean_outcome(t, m, x, y, crossfit, reg_y, + interaction, fit=False): + """ + Estimate conditional mean outcome E[Y|T,M,X] + with train test lists from crossfitting + + Returns + ------- + mu_t0: list + contains array-like, shape (n_samples) conditional mean outcome estimates E[Y|T=0,M=m,X] + mu_t1, list + contains array-like, shape (n_samples) conditional mean outcome estimates E[Y|T=1,M=m,X] + mu_m0x, array-like, shape (n_samples) + conditional mean outcome estimates E[Y|T=0,M,X] + mu_m1x, array-like, shape (n_samples) + conditional mean outcome estimates E[Y|T=1,M,X] + """ + n = len(y) + if len(x.shape) == 1: + x = x.reshape(-1, 1) + if len(m.shape) == 1: + mr = m.reshape(-1, 1) + else: + mr = np.copy(m) + if len(t.shape) == 1: + t = t.reshape(-1, 1) + + t0 = np.zeros((n, 1)) + t1 = np.ones((n, 1)) + m1 = np.ones((n, 1)) + + train_test_list = _get_train_test_lists(crossfit, n, x) + + mu_1mx, mu_0mx = [np.zeros(n) for _ in range(2)] + mu_t1, mu_t0 = [], [] + + m1 = np.ones((n, 1)) + + x_t_mr = _get_interactions(interaction, x, t, mr) + + x_t1_m = _get_interactions(interaction, x, t1, m) + x_t0_m = _get_interactions(interaction, x, t0, m) + + for train_index, test_index in train_test_list: + + # mu_tm model fitting + if fit == True: + reg_y = reg_y.fit(x_t_mr[train_index, :], y[train_index]) + + # predict E[Y|T=t,M,X] + mu_0mx[test_index] = reg_y.predict(x_t0_m[test_index, :]).squeeze() + mu_1mx[test_index] = reg_y.predict(x_t1_m[test_index, :]).squeeze() + + for i, b in enumerate(np.unique(m)): + mu_1bx, mu_0bx = [np.zeros(n) for h in range(2)] + mb = m1 * b + + # predict E[Y|T=t,M=m,X] + mu_0bx[test_index] = reg_y.predict( + _get_interactions(interaction, x, t0, mb)[test_index, + :]).squeeze() + mu_1bx[test_index] = reg_y.predict( + _get_interactions(interaction, x, t1, mb)[test_index, + :]).squeeze() + + mu_t0.append(mu_0bx) + mu_t1.append(mu_1bx) + + return mu_t0, mu_t1, mu_0mx, mu_1mx \ No newline at end of file diff --git a/src/med_bench/nuisances/cross_conditional_outcome.py b/src/med_bench/nuisances/cross_conditional_outcome.py new file mode 100644 index 0000000..9d7c3bd --- /dev/null +++ b/src/med_bench/nuisances/cross_conditional_outcome.py @@ -0,0 +1,224 @@ +""" +the objective of this script is to provide nuisance estimators +for mediation in causal inference +""" + +import numpy as np + +from sklearn.base import clone + +from med_bench.utils.utils import _get_train_test_lists, _get_interactions + +def estimate_cross_conditional_mean_outcome_discrete(m, x, y, f, regressors): + """ + Estimate the conditional mean outcome, + the cross conditional mean outcome + + Returns + ------- + mu_m0x, array-like, shape (n_samples) + conditional mean outcome estimates E[Y|T=0,M,X] + mu_m1x, array-like, shape (n_samples) + conditional mean outcome estimates E[Y|T=1,M,X] + E_mu_t0_t0, array-like, shape (n_samples) + cross conditional mean outcome estimates E[E[Y|T=0,M,X]|T=0,X] + E_mu_t0_t1, array-like, shape (n_samples) + cross conditional mean outcome estimates E[E[Y|T=0,M,X]|T=1,X] + E_mu_t1_t0, array-like, shape (n_samples) + cross conditional mean outcome estimates E[E[Y|T=1,M,X]|T=0,X] + E_mu_t1_t1, array-like, shape (n_samples) + cross conditional mean outcome estimates E[E[Y|T=1,M,X]|T=1,X] + """ + n = len(y) + + # Initialisation + ( + mu_1mx, # E[Y|T=1,M,X] + mu_0mx, # E[Y|T=0,M,X] + E_mu_t0_t0, # E[E[Y|T=0,M,X]|T=0,X] + E_mu_t0_t1, # E[E[Y|T=0,M,X]|T=1,X] + E_mu_t1_t0, # E[E[Y|T=1,M,X]|T=0,X] + E_mu_t1_t1, # E[E[Y|T=1,M,X]|T=1,X] + ) = [np.zeros(n) for _ in range(6)] + + t0, m0 = np.zeros((n, 1)), np.zeros((n, 1)) + t1, m1 = np.ones((n, 1)), np.ones((n, 1)) + + x_t1_m = _get_interactions(False, x, t1, m) + x_t0_m = _get_interactions(False, x, t0, m) + + f_t0, f_t1 = f + + # Index declaration + test_index = np.arange(n) + + # predict E[Y|T=t,M,X] + mu_1mx[test_index] = regressors['y_t_mx'].predict(x_t1_m[test_index, :]) + mu_0mx[test_index] = regressors['y_t_mx'].predict(x_t0_m[test_index, :]) + + for i, b in enumerate(np.unique(m)): + + # f(M=m|T=t,X) + f_0bx, f_1bx = f_t0[i], f_t1[i] + + # predict E[E[Y|T=1,M=m,X]|T=t,X] + E_mu_t1_t0[test_index] += regressors['reg_y_t1m{}_t0'.format(i)].predict( + x[test_index, :]) * \ + f_0bx[test_index] + E_mu_t1_t1[test_index] += regressors['reg_y_t1m{}_t1'.format(i)].predict( + x[test_index, :]) * \ + f_1bx[test_index] + + # predict E[E[Y|T=0,M=m,X]|T=t,X] + E_mu_t0_t0[test_index] += regressors['reg_y_t0m{}_t0'.format(i)].predict( + x[test_index, :]) * \ + f_0bx[test_index] + E_mu_t0_t1[test_index] += regressors['reg_y_t0m{}_t1'.format(i)].predict( + x[test_index, :]) * \ + f_1bx[test_index] + + return mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 + + +def estimate_cross_conditional_mean_outcome(t, m, x, y, crossfit, + reg_y, + reg_cross_y, f, + interaction): + """ + Estimate the conditional mean outcome, + the cross conditional mean outcome + + Returns + ------- + mu_m0x, array-like, shape (n_samples) + conditional mean outcome estimates E[Y|T=0,M,X] + mu_m1x, array-like, shape (n_samples) + conditional mean outcome estimates E[Y|T=1,M,X] + E_mu_t0_t0, array-like, shape (n_samples) + cross conditional mean outcome estimates E[E[Y|T=0,M,X]|T=0,X] + E_mu_t0_t1, array-like, shape (n_samples) + cross conditional mean outcome estimates E[E[Y|T=0,M,X]|T=1,X] + E_mu_t1_t0, array-like, shape (n_samples) + cross conditional mean outcome estimates E[E[Y|T=1,M,X]|T=0,X] + E_mu_t1_t1, array-like, shape (n_samples) + cross conditional mean outcome estimates E[E[Y|T=1,M,X]|T=1,X] + """ + n = len(y) + + # Initialisation + ( + mu_1mx, # E[Y|T=1,M,X] + mu_0mx, # E[Y|T=0,M,X] + E_mu_t0_t0, # E[E[Y|T=0,M,X]|T=0,X] + E_mu_t0_t1, # E[E[Y|T=0,M,X]|T=1,X] + E_mu_t1_t0, # E[E[Y|T=1,M,X]|T=0,X] + E_mu_t1_t1, # E[E[Y|T=1,M,X]|T=1,X] + ) = [np.zeros(n) for _ in range(6)] + + t0, m0 = np.zeros((n, 1)), np.zeros((n, 1)) + t1, m1 = np.ones((n, 1)), np.ones((n, 1)) + + train_test_list = _get_train_test_lists(crossfit, n, x) + + x_t_m = _get_interactions(interaction, x, t, m) + x_t1_m = _get_interactions(interaction, x, t1, m) + x_t0_m = _get_interactions(interaction, x, t0, m) + + f_t0, f_t1 = f + + # Cross-fitting loop + for train_index, test_index in train_test_list: + # Index declaration + ind_t0 = t[test_index] == 0 + + # mu_tm model fitting + reg_y = reg_y.fit(x_t_m[train_index, :], y[train_index]) + + # predict E[Y|T=t,M,X] + mu_1mx[test_index] = reg_y.predict(x_t1_m[test_index, :]) + mu_0mx[test_index] = reg_y.predict(x_t0_m[test_index, :]) + + for i, b in enumerate(np.unique(m)): + mb = m1 * b + + mu_1bx, mu_0bx, f_0bx, f_1bx = [np.zeros(n) for h in range(4)] + + # f(M=m|T=t,X) + f_0bx, f_1bx = f_t0[i], f_t1[i] + + # predict E[Y|T=t,M=m,X] + mu_0bx[test_index] = reg_y.predict( + _get_interactions(interaction, x, t0, mb)[test_index, :]) + mu_1bx[test_index] = reg_y.predict( + _get_interactions(interaction, x, t1, mb)[test_index, :]) + + # E[E[Y|T=1,M=m,X]|T=t,X] model fitting + reg_y_t1mb_t0 = clone(reg_cross_y).fit(x[test_index, :][ind_t0, :], + mu_1bx[test_index][ind_t0]) + reg_y_t1mb_t1 = clone(reg_cross_y).fit( + x[test_index, :][~ind_t0, :], mu_1bx[test_index][~ind_t0]) + + # predict E[E[Y|T=1,M=m,X]|T=t,X] + E_mu_t1_t0[test_index] += reg_y_t1mb_t0.predict(x[test_index, :]) * \ + f_0bx[test_index] + E_mu_t1_t1[test_index] += reg_y_t1mb_t1.predict(x[test_index, :]) * \ + f_1bx[test_index] + + # E[E[Y|T=0,M=m,X]|T=t,X] model fitting + reg_y_t0mb_t0 = clone(reg_cross_y).fit(x[test_index, :][ind_t0, :], + mu_0bx[test_index][ind_t0]) + reg_y_t0mb_t1 = clone(reg_cross_y).fit( + x[test_index, :][~ind_t0, :], mu_0bx[test_index][~ind_t0]) + + # predict E[E[Y|T=0,M=m,X]|T=t,X] + E_mu_t0_t0[test_index] += reg_y_t0mb_t0.predict(x[test_index, :]) * \ + f_0bx[test_index] + E_mu_t0_t1[test_index] += reg_y_t0mb_t1.predict(x[test_index, :]) * \ + f_1bx[test_index] + + return mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 + + +def estimate_cross_conditional_mean_outcome_nesting(m, x, y, regressors): + """ + Estimate the conditional mean outcome, + the cross conditional mean outcome + + Returns + ------- + mu_m0x, array-like, shape (n_samples) + conditional mean outcome estimates E[Y|T=0,M,X] + mu_m1x, array-like, shape (n_samples) + conditional mean outcome estimates E[Y|T=1,M,X] + mu_0x, array-like, shape (n_samples) + cross conditional mean outcome estimates E[E[Y|T=0,M,X]|T=0,X] + E_mu_t0_t1, array-like, shape (n_samples) + cross conditional mean outcome estimates E[E[Y|T=0,M,X]|T=1,X] + E_mu_t1_t0, array-like, shape (n_samples) + cross conditional mean outcome estimates E[E[Y|T=1,M,X]|T=0,X] + mu_1x, array-like, shape (n_samples) + cross conditional mean outcome estimates E[E[Y|T=1,M,X]|T=1,X] + """ + n = len(y) + + xm = np.hstack((x, m)) + + # predict E[Y|T=1,M,X] + mu_1mx = regressors['y_t1_mx'].predict(xm) + + # predict E[Y|T=0,M,X] + mu_0mx = regressors['y_t0_mx'].predict(xm) + + # predict E[E[Y|T=1,M,X]|T=0,X] + E_mu_t1_t0 = regressors['y_t1_x_t0'].predict(x) + + # predict E[E[Y|T=0,M,X]|T=1,X] + E_mu_t0_t1 = regressors['y_t0_x_t1'].predict(x) + + # predict E[Y|T=1,X] + mu_1x = regressors['y_t1_x'].predict(x) + + # predict E[Y|T=0,X] + mu_0x = regressors['y_t0_x'].predict(x) + + return mu_0mx, mu_1mx, mu_0x, E_mu_t0_t1, E_mu_t1_t0, mu_1x \ No newline at end of file diff --git a/src/med_bench/nuisances/density.py b/src/med_bench/nuisances/density.py new file mode 100644 index 0000000..1843ed7 --- /dev/null +++ b/src/med_bench/nuisances/density.py @@ -0,0 +1,315 @@ +""" +the objective of this script is to provide nuisance estimators +for mediation in causal inference +""" + +import numpy as np + +from sklearn.base import clone + +from med_bench.utils.utils import _get_train_test_lists, _get_interactions +from sklearn.neighbors import NearestNeighbors, KernelDensity +from sklearn.base import BaseEstimator +from joblib import Parallel, delayed + +def estimate_mediator_density(t, m, x, y, crossfit, clf_m, + interaction, fit=False): + """ + Estimate mediator density f(M|T,X) + with train test lists from crossfitting + + Returns + ------- + f_t0: list + contains array-like, shape (n_samples) probabilities f(M=m|T=0,X) + f_t1, list + contains array-like, shape (n_samples) probabilities f(M=m|T=1,X) + f_m0x, array-like, shape (n_samples) + probabilities f(M|T=0,X) + f_m1x, array-like, shape (n_samples) + probabilities f(M|T=1,X) + """ + # if not is_array_integer(m): + # return estimate_mediator_density_kde(t, m, x, y, crossfit, interaction) + # else: + return estimate_mediator_probability(t, m, x, y, crossfit, clf_m, + interaction, fit=False) + + +def estimate_mediators_probabilities(t, m, x, y, crossfit, clf_m, + interaction, fit=False): + """ + Estimate mediator density f(M|T,X) + with train test lists from crossfitting + + Returns + ------- + f_t0: list + contains array-like, shape (n_samples) probabilities f(M=m|T=0,X) + f_t1, list + contains array-like, shape (n_samples) probabilities f(M=m|T=1,X) + """ + n = len(y) + if len(x.shape) == 1: + x = x.reshape(-1, 1) + + if len(t.shape) == 1: + t = t.reshape(-1, 1) + + t0 = np.zeros((n, 1)) + t1 = np.ones((n, 1)) + + m = m.ravel() + + train_test_list = _get_train_test_lists(crossfit, n, x) + + f_t1, f_t0 = [], [] + + t_x = _get_interactions(interaction, t, x) + t0_x = _get_interactions(interaction, t0, x) + t1_x = _get_interactions(interaction, t1, x) + + for train_index, test_index in train_test_list: + + + # f_mtx model fitting + if fit == True: + clf_m = clf_m.fit(t_x[train_index, :], m[train_index]) + + fm_0 = clf_m.predict_proba(t0_x[test_index, :]) + fm_1 = clf_m.predict_proba(t1_x[test_index, :]) + + + for i, b in enumerate(np.unique(m)): + f_0bx, f_1bx = [np.zeros(n) for h in range(2)] + + # predict f(M=m|T=t,X) + f_0bx[test_index] = fm_0[:, i] + f_1bx[test_index] = fm_1[:, i] + + f_t0.append(f_0bx) + f_t1.append(f_1bx) + + return f_t0, f_t1 + +def estimate_mediator_probability(t, m, x, y, crossfit, clf_m, + interaction, fit=False): + """ + Estimate mediator density f(M|T,X) + with train test lists from crossfitting + + Returns + ------- + f_m0x, array-like, shape (n_samples) + probabilities f(M|T=0,X) + f_m1x, array-like, shape (n_samples) + probabilities f(M|T=1,X) + """ + n = len(y) + if len(x.shape) == 1: + x = x.reshape(-1, 1) + + if len(t.shape) == 1: + t = t.reshape(-1, 1) + + t0 = np.zeros((n, 1)) + t1 = np.ones((n, 1)) + + m = m.ravel() + + train_test_list = _get_train_test_lists(crossfit, n, x) + + f_m0x, f_m1x = [np.zeros(n) for h in range(2)] + + t_x = _get_interactions(interaction, t, x) + t0_x = _get_interactions(interaction, t0, x) + t1_x = _get_interactions(interaction, t1, x) + + for train_index, test_index in train_test_list: + + test_ind = np.arange(len(test_index)) + + # f_mtx model fitting + if fit == True: + clf_m = clf_m.fit(t_x[train_index, :], m[train_index]) + + fm_0 = clf_m.predict_proba(t0_x[test_index, :]) + fm_1 = clf_m.predict_proba(t1_x[test_index, :]) + + # predict f(M|T=t,X) + f_m0x[test_index] = fm_0[test_ind, m[test_index]] + f_m1x[test_index] = fm_1[test_ind, m[test_index]] + + for i, b in enumerate(np.unique(m)): + f_0bx, f_1bx = [np.zeros(n) for h in range(2)] + + # predict f(M=m|T=t,X) + f_0bx[test_index] = fm_0[:, i] + f_1bx[test_index] = fm_1[:, i] + + return f_m0x, f_m1x + +class ConditionalNearestNeighborsKDE(BaseEstimator): + """Conditional Kernel Density Estimation using nearest neighbors. + + This class implements a Conditional Kernel Density Estimation by applying + the Kernel Density Estimation algorithm after a nearest neighbors search. + + It allows the use of user-specified nearest neighbor and kernel density + estimators or, if not provided, defaults will be used. + + Parameters + ---------- + nn_estimator : NearestNeighbors instance, default=None + A pre-configured instance of a `~sklearn.neighbors.NearestNeighbors` class + to use for finding nearest neighbors. If not specified, a + `~sklearn.neighbors.NearestNeighbors` instance with `n_neighbors=100` + will be used. + + kde_estimator : KernelDensity instance, default=None + A pre-configured instance of a `~sklearn.neighbors.KernelDensity` class + to use for estimating the kernel density. If not specified, a + `~sklearn.neighbors.KernelDensity` instance with `bandwidth="scott"` + will be used. + """ + + def __init__(self, nn_estimator=None, kde_estimator=None): + self.nn_estimator = nn_estimator + self.kde_estimator = kde_estimator + + def fit(self, X, y=None): + if self.nn_estimator is None: + self.nn_estimator_ = NearestNeighbors(n_neighbors=100) + else: + self.nn_estimator_ = clone(self.nn_estimator) + self.nn_estimator_.fit(X, y) + self.y_train_ = y + return self + + def predict(self, X): + """Predict the conditional density estimation of new samples. + + The predicted density of the target for each sample in X is returned. + + Parameters + ---------- + X : array-like of shape (n_samples, n_features) + Vector to be estimated, where `n_samples` is the number of samples + and `n_features` is the number of features. + + Returns + ------- + kernel_density_list : list of len n_samples of KernelDensity instances + Estimated conditional density estimations in the form of + `~sklearn.neighbors.KernelDensity` instances. + """ + _, ind_X = self.nn_estimator_.kneighbors(X) + if self.kde_estimator is None: + kernel_density_list = [ + KernelDensity(bandwidth="scott").fit( + self.y_train_[ind].reshape(-1, 1)) + for ind in ind_X + ] + else: + kernel_density_list = [ + clone(self.kde_estimator).fit( + self.y_train_[ind].reshape(-1, 1)) + for ind in ind_X + ] + return kernel_density_list + + def pdf(self, y, x): + + ckde_preds = self.predict(x) + + def _evaluate_individual(y_, cde_pred): + # The score_samples and score methods returns stuff on log scale, + # so we have to exp it. + expected_value = np.exp(cde_pred.score(y_.reshape(-1, 1))) + return expected_value + + individual_predictions = Parallel(n_jobs=-1)( + delayed(_evaluate_individual)(y_, cde_pred) + for y_, cde_pred in zip(y, ckde_preds) + ) + + return individual_predictions + +# def estimate_mediator_density_kde(t, m, x, y, crossfit, interaction): +# """ +# Estimate mediator density f(M|T,X) +# with train test lists from crossfitting + +# Returns +# ------- +# f_m0x, array-like, shape (n_samples) +# probabilities f(M|T=0,X) +# f_m1x, array-like, shape (n_samples) +# probabilities f(M|T=1,X) +# """ +# n = len(y) +# if len(x.shape) == 1: +# x = x.reshape(-1, 1) + +# if len(t.shape) == 1: +# t = t.reshape(-1, 1) + +# t0 = np.zeros((n, 1)) +# t1 = np.ones((n, 1)) + + +# train_test_list = _get_train_test_lists(crossfit, n, x) + +# f_m0x, f_m1x = [np.zeros(n) for _ in range(2)] + +# t_x = _get_interactions(interaction, t, x) +# t0_x = _get_interactions(interaction, t0, x) +# t1_x = _get_interactions(interaction, t1, x) + +# for train_index, test_index in train_test_list: + +# # f_mtx model fitting +# ckde_m = ConditionalNearestNeighborsKDE().fit(t_x[train_index, :], +# m[train_index, :]) + +# # predict f(M|T=t,X) +# f_m0x[test_index] = ckde_m.pdf(m[test_index, :], t0_x[test_index, :]) +# f_m1x[test_index] = ckde_m.pdf(m[test_index, :], t1_x[test_index, :]) + +# return f_m0x, f_m1x + +def estimate_mediator_density_kde(t, m, x, y, crossfit, ckde_m, interaction): + """ + Estimate mediator density f(M|T,X) + with train test lists from crossfitting + + Returns + ------- + f_m0x, array-like, shape (n_samples) + probabilities f(M|T=0,X) + f_m1x, array-like, shape (n_samples) + probabilities f(M|T=1,X) + """ + n = len(y) + if len(x.shape) == 1: + x = x.reshape(-1, 1) + + if len(t.shape) == 1: + t = t.reshape(-1, 1) + + t0 = np.zeros((n, 1)) + t1 = np.ones((n, 1)) + + + f_m0x, f_m1x = [np.zeros(n) for _ in range(2)] + + t_x = _get_interactions(interaction, t, x) + t0_x = _get_interactions(interaction, t0, x) + t1_x = _get_interactions(interaction, t1, x) + + + # predict f(M|T=t,X) + f_m0x = ckde_m.pdf(m, t0_x) + f_m1x = ckde_m.pdf(m, t1_x) + + return f_m0x, f_m1x \ No newline at end of file diff --git a/src/med_bench/nuisances/propensities.py b/src/med_bench/nuisances/propensities.py new file mode 100644 index 0000000..1d5b9e4 --- /dev/null +++ b/src/med_bench/nuisances/propensities.py @@ -0,0 +1,77 @@ +""" +the objective of this script is to provide nuisance estimators +for mediation in causal inference +""" + +import numpy as np + + +from med_bench.utils.utils import _get_train_test_lists + + +def estimate_treatment_propensity_x(t, m, x, crossfit, clf_t_x): + """ + Estimate treatment probabilities P(T=1|X) with train + test lists from crossfitting + + Returns + ------- + p_x : array-like, shape (n_samples) + probabilities P(T=1|X) + p_xm : array-like, shape (n_samples) + probabilities P(T=1|X, M) + """ + n = len(t) + + p_x, p_xm = [np.zeros(n) for h in range(2)] + # compute propensity scores + if len(x.shape) == 1: + x = x.reshape(-1, 1) + if len(m.shape) == 1: + m = m.reshape(-1, 1) + if len(t.shape) == 1: + t = t.reshape(-1, 1) + + train_test_list = _get_train_test_lists(crossfit, n, x) + + for train_index, test_index in train_test_list: + + # predict P(T=1|X), P(T=1|X, M) + p_x[test_index] = clf_t_x.predict_proba(x[test_index, :])[:, 1] + + return p_x + +def estimate_treatment_probabilities(t, m, x, crossfit, clf_t_x, clf_t_xm, fit=False): + """ + Estimate treatment probabilities P(T=1|X) and P(T=1|X, M) with train + test lists from crossfitting + + Returns + ------- + p_x : array-like, shape (n_samples) + probabilities P(T=1|X) + p_xm : array-like, shape (n_samples) + probabilities P(T=1|X, M) + """ + n = len(t) + + p_x, p_xm = [np.zeros(n) for h in range(2)] + # compute propensity scores + if len(x.shape) == 1: + x = x.reshape(-1, 1) + if len(m.shape) == 1: + m = m.reshape(-1, 1) + if len(t.shape) == 1: + t = t.reshape(-1, 1) + + train_test_list = _get_train_test_lists(crossfit, n, x) + + xm = np.hstack((x, m)) + + for train_index, test_index in train_test_list: + + # predict P(T=1|X), P(T=1|X, M) + p_x[test_index] = clf_t_x.predict_proba(x[test_index, :])[:, 1] + p_xm[test_index] = clf_t_xm.predict_proba(xm[test_index, :])[:, 1] + + return p_x, p_xm \ No newline at end of file diff --git a/src/med_bench/nuisances/utils.py b/src/med_bench/nuisances/utils.py new file mode 100644 index 0000000..96eee0c --- /dev/null +++ b/src/med_bench/nuisances/utils.py @@ -0,0 +1,83 @@ +""" +the objective of this script is to provide nuisance estimators +for mediation in causal inference +""" + +import numpy as np + +from sklearn.calibration import CalibratedClassifierCV +from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor +from sklearn.linear_model import LogisticRegressionCV, RidgeCV + +from med_bench.utils.constants import ALPHAS, CV_FOLDS, TINY + + +def _get_regularization_parameters(regularization): + """ + Obtain regularization parameters + + Returns + ------- + cs : list + each of the values in Cs describes the inverse of regularization + strength for predictors + alphas : list + alpha values to try in ridge models + """ + if regularization: + alphas = ALPHAS + cs = ALPHAS + else: + alphas = [TINY] + cs = [np.inf] + + return cs, alphas + + +def _get_classifier(regularization, forest, calibration, random_state=42): + """ + Obtain context classifiers to estimate treatment probabilities. + + Returns + ------- + clf : classifier on contexts, etc. for predicting P(T=1|X), + P(T=1|X, M) or f(M|T,X) + """ + cs, _ = _get_regularization_parameters(regularization) + + if not forest: + clf = LogisticRegressionCV(random_state=random_state, Cs=cs, + cv=CV_FOLDS) + else: + clf = RandomForestClassifier(random_state=random_state, + n_estimators=100, min_samples_leaf=10) + if calibration in {"sigmoid", "isotonic"}: + clf = CalibratedClassifierCV(clf, method=calibration) + + return clf + + +def _get_regressor(regularization, forest, random_state=42): + """ + Obtain regressors to estimate conditional mean outcomes. + + Returns + ------- + reg : regressor on contexts, etc. for predicting E[Y|T,M,X], etc. + """ + _, alphas = _get_regularization_parameters(regularization) + + if not forest: + reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) + else: + reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10) + + return reg + + + + + + + + From 6d78313142fa950f924a4971ff21b7f397be42c8 Mon Sep 17 00:00:00 2001 From: brash6 Date: Thu, 1 Aug 2024 18:17:47 +0200 Subject: [PATCH 04/84] some new constants --- src/med_bench/utils/constants.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/med_bench/utils/constants.py b/src/med_bench/utils/constants.py index 417f993..33a2433 100644 --- a/src/med_bench/utils/constants.py +++ b/src/med_bench/utils/constants.py @@ -156,3 +156,7 @@ def get_tolerance_array(tolerance_size: str) -> np.array: ) ) ) + +ALPHAS = np.logspace(-5, 5, 8) +CV_FOLDS = 5 +TINY = 1.e-12 From 124873ede97191adc6e3bbafc7bc4ff871c5f970 Mon Sep 17 00:00:00 2001 From: brash6 Date: Thu, 1 Aug 2024 18:18:24 +0200 Subject: [PATCH 05/84] some new utils functions --- src/med_bench/utils/utils.py | 109 ++++++++++++++++++++++++++++++++++- 1 file changed, 108 insertions(+), 1 deletion(-) diff --git a/src/med_bench/utils/utils.py b/src/med_bench/utils/utils.py index 9ec0438..8f4223f 100644 --- a/src/med_bench/utils/utils.py +++ b/src/med_bench/utils/utils.py @@ -1,9 +1,11 @@ import numpy as np import pandas as pd +from sklearn.cluster import KMeans +from sklearn.model_selection import train_test_split +from sklearn.model_selection import KFold import subprocess -import warnings def check_r_dependencies(): @@ -238,3 +240,108 @@ def _check_input(y, t, m, x, setting): return y_converted, t_converted, m_converted, x_converted +def is_array_integer(array): + if array.shape[1]>1: + return False + return all(list((array == array.astype(int)).squeeze())) + + +def str_to_bool(string): + if bool(string) == string: + return string + elif string == 'True': + return True + elif string == 'False': + return False + else: + raise ValueError # evil ValueError that doesn't tell you what the wrong value was + + +def bucketize_mediators(m, n_buckets=10, random_state=42): + kmeans = KMeans(n_clusters=n_buckets, random_state=random_state, n_init="auto").fit(m) + return kmeans.predict(m) + + +def train_test_split_data(causal_data, test_size=0.33, random_state=42): + x, t, m, y = causal_data + x_train, x_test, t_train, t_test, m_train, m_test, y_train, y_test = ( + train_test_split(x, + t, + m, + y, + test_size=test_size, + random_state=random_state)) + causal_data_train = x_train, t_train, m_train, y_train + causal_data_test = x_test, t_test, m_test, y_test + return causal_data_train, causal_data_test + +def _get_train_test_lists(crossfit, n, x): + """ + Obtain train and test folds + + Returns + ------- + train_test_list : list + indexes with train and test indexes + """ + if crossfit < 2: + train_test_list = [[np.arange(n), np.arange(n)]] + else: + kf = KFold(n_splits=crossfit) + train_test_list = list() + for train_index, test_index in kf.split(x): + train_test_list.append([train_index, test_index]) + return train_test_list + +def _get_interactions(interaction, *args): + """ + this function provides interaction terms between different groups of + variables (confounders, treatment, mediators) + + Parameters + ---------- + interaction : boolean + whether to compute interaction terms + + *args : flexible, one or several arrays + blocks of variables between which interactions should be + computed + + + Returns + -------- + array_like + interaction terms + + Examples + -------- + >>> x = np.arange(6).reshape(3, 2) + >>> t = np.ones((3, 1)) + >>> m = 2 * np.ones((3, 1)) + >>> get_interactions(False, x, t, m) + array([[0., 1., 1., 2.], + [2., 3., 1., 2.], + [4., 5., 1., 2.]]) + >>> get_interactions(True, x, t, m) + array([[ 0., 1., 1., 2., 0., 1., 0., 2., 2.], + [ 2., 3., 1., 2., 2., 3., 4., 6., 2.], + [ 4., 5., 1., 2., 4., 5., 8., 10., 2.]]) + """ + variables = list(args) + for index, var in enumerate(variables): + if len(var.shape) == 1: + variables[index] = var.reshape(-1,1) + pre_inter_variables = np.hstack(variables) + if not interaction: + return pre_inter_variables + new_cols = list() + for i, var in enumerate(variables[:]): + for j, var2 in enumerate(variables[i+1:]): + for ii in range(var.shape[1]): + for jj in range(var2.shape[1]): + new_cols.append((var[:, ii] * var2[:, jj]).reshape(-1, 1)) + new_vars = np.hstack(new_cols) + result = np.hstack((pre_inter_variables, new_vars)) + return result + + From 84c185d02e860eec355f16e9556cf6e0c8fc6a2e Mon Sep 17 00:00:00 2001 From: brash6 Date: Thu, 1 Aug 2024 18:18:50 +0200 Subject: [PATCH 06/84] useful decorators --- src/med_bench/utils/decorators.py | 53 +++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/med_bench/utils/decorators.py diff --git a/src/med_bench/utils/decorators.py b/src/med_bench/utils/decorators.py new file mode 100644 index 0000000..9e0b286 --- /dev/null +++ b/src/med_bench/utils/decorators.py @@ -0,0 +1,53 @@ +import time + + +def timeit(func): + def timed(*args, **kwargs): + ts = time.time() + result = func(*args, **kwargs) + te = time.time() + + if 'log_time' in kwargs: + name = kwargs.get('log_name', func.__name__.upper()) + kwargs['log_time'][name] = int((te - ts) * 1000) + else: + print('%r %2.2f ms' % (func.__name__, (te - ts) * 1000)) + return result + return timed + + +def accepts(*types): + def check_accepts(func): + assert len(types) == func.__code__.co_argcount - 1 + + def wrapper(self, *args, **kwargs): + for (a, t) in zip(args, types): + assert isinstance(a, t), \ + "arg %r does not match %s" % (a, t) + return func(self, *args, **kwargs) + wrapper.__name__ = func.__name__ + return wrapper + return check_accepts + + +def accepts_(*types): + def check_accepts(func): + assert len(types) == func.__code__.co_argcount + + def wrapper(*args, **kwargs): + for (a, t) in zip(args, types): + assert isinstance(a, t), \ + "arg %r does not match %s" % (a, t) + return func(*args, **kwargs) + wrapper.__name__ = func.__name__ + return wrapper + return check_accepts + + +def fitted(func): + def wrapper(self, *args, **kwargs): + if self._fitted: + return func(self, *args, **kwargs) + else: + raise RuntimeError("Model not fitted yet") + return wrapper \ No newline at end of file From b13147e56faf2c274f702ba1ef3858dd451abb23 Mon Sep 17 00:00:00 2001 From: brash6 Date: Thu, 1 Aug 2024 18:19:04 +0200 Subject: [PATCH 07/84] useful estimator loader to be uysed in the future --- src/med_bench/utils/loader.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/med_bench/utils/loader.py diff --git a/src/med_bench/utils/loader.py b/src/med_bench/utils/loader.py new file mode 100644 index 0000000..d30f5e2 --- /dev/null +++ b/src/med_bench/utils/loader.py @@ -0,0 +1,22 @@ +from med_bench.estimation.ipw import ImportanceWeighting +from med_bench.estimation.g_computation import GComputation +from med_bench.estimation.dml import DoubleMachineLearning +from med_bench.estimation.mr import MultiplyRobust +from med_bench.estimation.tmle import TMLE + + +def get_estimator_by_name(settings): + if settings['estimator'] == 'ipw': + return ImportanceWeighting + elif settings['estimator'] == 'g_computation': + return GComputation + elif settings['estimator'] == 'linear': + return Linear + elif settings['estimator'] == 'mr': + return MultiplyRobust + elif settings['estimator'] == 'dml': + return DoubleMachineLearning + elif settings['estimator'] == 'tmle': + return TMLE + else: + raise NotImplementedError \ No newline at end of file From 5e88fc1266160e76657556f3d609aeafa1928c71 Mon Sep 17 00:00:00 2001 From: brash6 Date: Thu, 1 Aug 2024 18:19:16 +0200 Subject: [PATCH 08/84] still messy nuisances.py file --- src/med_bench/utils/nuisances.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/med_bench/utils/nuisances.py b/src/med_bench/utils/nuisances.py index 6878610..cccad08 100644 --- a/src/med_bench/utils/nuisances.py +++ b/src/med_bench/utils/nuisances.py @@ -12,7 +12,7 @@ from .utils import check_r_dependencies, _get_interactions if check_r_dependencies(): - from .utils import _convert_array_to_R + pass ALPHAS = np.logspace(-5, 5, 8) From 3e4a9954563db83bfe89198243068b401f6dd877 Mon Sep 17 00:00:00 2001 From: brash6 Date: Thu, 1 Aug 2024 18:19:26 +0200 Subject: [PATCH 09/84] some scoring functions --- src/med_bench/utils/scores.py | 45 +++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 src/med_bench/utils/scores.py diff --git a/src/med_bench/utils/scores.py b/src/med_bench/utils/scores.py new file mode 100644 index 0000000..02521e0 --- /dev/null +++ b/src/med_bench/utils/scores.py @@ -0,0 +1,45 @@ +import numpy as np + +def ipw_risk(y, t, hat_y, hat_e, trimming=None): + if trimming is not None: + clipped_hat_e = np.clip(hat_e, trimming, 1 - trimming) + else: + clipped_hat_e = hat_e + ipw_weights = t / clipped_hat_e + (1 - t) / (1 - clipped_hat_e) + return np.sum(((y - hat_y) ** 2) * ipw_weights) / len(y) + + +def r_risk(y, t, hat_m, hat_e, hat_tau): + return np.mean(((y - hat_m) - (t - hat_e) * hat_tau) ** 2) + + +def u_risk(y, t, hat_m, hat_e, hat_tau): + return np.mean(((y - hat_m) / (t - hat_e) - hat_tau) ** 2) + + +def w_risk(y, t, hat_e, hat_tau, trimming=None): + if trimming is not None: + clipped_hat_e = np.clip(hat_e, trimming, 1 - trimming) + else: + clipped_hat_e = hat_e + pseudo_outcome = (y * (t - clipped_hat_e)) / ( + clipped_hat_e * (1 - clipped_hat_e)) + return np.mean((pseudo_outcome - hat_tau) ** 2) + + +def ipw_r_risk(y, t, hat_mu_0, hat_mu_1, hat_e, hat_m, trimming=None): + if trimming is not None: + clipped_hat_e = np.clip(hat_e, trimming, 1 - trimming) + else: + clipped_hat_e = hat_e + ipw_weights = t / clipped_hat_e + (1 - t) / (1 - clipped_hat_e) + hat_tau = hat_mu_1 - hat_mu_0 + + return np.sum( + (((y - hat_m) - (t - hat_e) * (hat_tau)) ** 2) * ipw_weights) / len(y) + + +def ipw_r_risk_oracle(y, t, hat_mu_0, hat_mu_1, e, mu_1, mu_0): + m = mu_0 * (1 - e) + mu_1 * e + return ipw_r_risk(y=y, t=t, hat_mu_0=hat_mu_0, hat_mu_1=hat_mu_1, hat_e=e, + hat_m=m) From f100116480b4bf4a151bf60a4fc76dfc602c645b Mon Sep 17 00:00:00 2001 From: brash6 Date: Thu, 1 Aug 2024 18:19:42 +0200 Subject: [PATCH 10/84] experiment file to try estimators (to be enhanced) --- src/med_bench/experiment.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/med_bench/experiment.py diff --git a/src/med_bench/experiment.py b/src/med_bench/experiment.py new file mode 100644 index 0000000..5a465fb --- /dev/null +++ b/src/med_bench/experiment.py @@ -0,0 +1,37 @@ +from numpy.random import default_rng +from sklearn.ensemble import RandomForestClassifier +from sklearn.linear_model import RidgeCV +from sklearn.model_selection import train_test_split + +from med_bench.estimation.coefficient_product import CoefficientProduct +from med_bench.get_simulated_data import simulate_data +from med_bench.nuisances.utils import _get_regularization_parameters +from med_bench.utils.constants import CV_FOLDS + +if __name__ == "__main__": + print("get simulated data") + (x, t, m, y, + theta_1_delta_0, theta_1, theta_0, delta_1, delta_0, + p_t, th_p_t_mx) = simulate_data(n=1000, rg=default_rng(321)) + + (x_train, x_test, t_train, t_test, + m_train, m_test, y_train, y_test) = train_test_split(x, t, m, y, test_size=0.33, random_state=42) + + cs, alphas = _get_regularization_parameters(regularization=True) + + clf = RandomForestClassifier(random_state=42, n_estimators=100, min_samples_leaf=10) + + reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) + + coef_prod_estimator = CoefficientProduct(mediator_type="binary", regressor=reg, classifier=clf, clip=0.01, trim=0.01, regularize=True) + + coef_prod_estimator.fit(t_train, m_train, x_train, y_train) + causal_effects = coef_prod_estimator.estimate(t_test, m_test, x_test, y_test) + + r_risk_score = coef_prod_estimator.score(t_test, m_test, x_test, y_test, causal_effects['total_effect']) + + print('R risk score: {}'.format(r_risk_score)) + print('Total effect error: {}'.format(abs(causal_effects['total_effect']-theta_1_delta_0))) + print('Direct effect error: {}'.format(abs(causal_effects['direct_effect_control']-theta_0))) + print('Indirect effect error: {}'.format(abs(causal_effects['indirect_effect_treated']-delta_1))) + From 90b7184b0307a1dd0e97d1c2e1877b177931b7fd Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 23 Oct 2024 15:45:00 +0200 Subject: [PATCH 11/84] remove unused class variables --- src/med_bench/estimation/coefficient_product.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/med_bench/estimation/coefficient_product.py b/src/med_bench/estimation/coefficient_product.py index 949354a..ee9fe6b 100644 --- a/src/med_bench/estimation/coefficient_product.py +++ b/src/med_bench/estimation/coefficient_product.py @@ -9,20 +9,16 @@ class CoefficientProduct(Estimator): - def __init__(self, clip : float, trim : float, regularize : bool, **kwargs): + def __init__(self, regularize: bool, **kwargs): """Coefficient product estimator Attributes: - clip (float): clipping the propensities - trim (float): remove propensities which are below the trim threshold regularize (bool) : regularization parameter """ super().__init__(**kwargs) self._crossfit = 0 self._regularize = regularize - self._clip = clip - self._trim = trim def fit(self, t, m, x, y): """Fits nuisance parameters to data @@ -72,7 +68,6 @@ def fit(self, t, m, x, y): if self.verbose: print("Nuisance models fitted") - @fitted def estimate(self, t, m, x, y): """Estimates causal effect on data @@ -80,7 +75,8 @@ def estimate(self, t, m, x, y): """ direct_effect_treated = self._coef_y[x.shape[1]] direct_effect_control = direct_effect_treated - indirect_effect_treated = sum(self._coef_y[x.shape[1] + 1:] * self._coef_t_m) + indirect_effect_treated = sum( + self._coef_y[x.shape[1] + 1:] * self._coef_t_m) indirect_effect_control = indirect_effect_treated causal_effects = { From c828524ee81a6f0f9938484458dcf662c62706d1 Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 23 Oct 2024 16:35:00 +0200 Subject: [PATCH 12/84] enhance base file --- src/med_bench/estimation/base.py | 66 +++++++++++++++++++------------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/src/med_bench/estimation/base.py b/src/med_bench/estimation/base.py index 8e03c7a..86e6a78 100644 --- a/src/med_bench/estimation/base.py +++ b/src/med_bench/estimation/base.py @@ -14,14 +14,15 @@ class Estimator: """General abstract class for causal mediation Estimator """ __metaclass__ = ABCMeta - def __init__(self, mediator_type : str, regressor : RegressorMixin, classifier : ClassifierMixin, - verbose : bool=True): + + def __init__(self, mediator_type: str, regressor: RegressorMixin, classifier: ClassifierMixin, + verbose: bool = True): """Initialize Estimator base class Parameters ---------- mediator_type : str - mediator type (binary or continuous) + mediator type (binary or continuous, continuous only can be multidimensional) regressor : RegressorMixin Scikit-Learn Regressor used for mu estimation classifier : ClassifierMixin @@ -31,24 +32,21 @@ def __init__(self, mediator_type : str, regressor : RegressorMixin, classifier : """ self.rng = np.random.RandomState(123) + assert mediator_type in [ + 'binary', 'continuous'], "mediator_type must be 'binary' or 'continuous'" self.mediator_type = mediator_type - # TBD inside an Issue self.regressor = regressor - #self.regressor_params_dict = regressor_params_dict self.classifier = classifier - #self.classifier_params_dict = classifier_params_dict self._verbose = verbose self._fitted = False - @property def verbose(self): return self._verbose - @abstractmethod def fit(self, t, m, x, y): """Fits nuisance parameters to data @@ -71,7 +69,6 @@ def fit(self, t, m, x, y): """ pass - @abstractmethod @fitted def estimate(self, t, m, x, y): @@ -96,10 +93,10 @@ def estimate(self, t, m, x, y): """ pass - - def fit_score_nuisances(self, t, m, x, y, *args, **kwargs): + def _fit_nuisance(self, t, m, x, y, *args, **kwargs): """ Fits the score of the nuisance parameters """ + # How do we want to specify gridsearch parameters ? As a function param, a constant or hardcoded here ? clf_param_grid = {} reg_param_grid = {} @@ -111,38 +108,40 @@ def fit_score_nuisances(self, t, m, x, y, *args, **kwargs): self._hat_m = regressor_y.fit(x, y.squeeze()) + return self @fitted - def score(self, t, m, x, y, hat_tau): + def score(self, t, m, x, y, tau_): """Predicts score on data samples Parameters ---------- - hat_tau array-like, shape (n_samples) + tau_ array-like, shape (n_samples) estimated risk """ hat_e = self._hat_e.predict_proba(x)[:, 1] hat_m = self._hat_m.predict(x) - score = r_risk(y.squeeze(), t.squeeze(), hat_m, hat_e, hat_tau) + score = r_risk(y.squeeze(), t.squeeze(), hat_m, hat_e, tau_) return score - - def fit_treatment_propensity_x_nuisance(self, t, x): + def _fit_treatment_propensity_x_nuisance(self, t, x): """ Fits the nuisance parameter for the propensity P(T=1|X) """ self._classifier_t_x = self.classifier.fit(x, t) + return self - def fit_treatment_propensity_xm_nuisance(self, t, m, x): + def _fit_treatment_propensity_xm_nuisance(self, t, m, x): """ Fits the nuisance parameter for the propensity P(T=1|X, M) """ xm = np.hstack((x, m)) self._classifier_t_xm = self.classifier.fit(xm, t) + return self - def fit_mediator_nuisance(self, t, m, x): + def _fit_mediator_nuisance(self, t, m, x): """ Fits the nuisance parameter for the density f(M=m|T, X) """ # estimate mediator densities @@ -154,8 +153,9 @@ def fit_mediator_nuisance(self, t, m, x): # Fit classifier self._classifier_m = classifier_m.fit(t_x, m.ravel()) + return self - def fit_conditional_mean_outcome_nuisance(self, t, m, x, y): + def _fit_conditional_mean_outcome_nuisance(self, t, m, x, y): """ Fits the nuisance for the conditional mean outcome for the density f(M=m|T, X) """ if len(m.shape) == 1: @@ -171,8 +171,9 @@ def fit_conditional_mean_outcome_nuisance(self, t, m, x, y): self._regressor_y = regressor_y.fit(x_t_mr, y) + return self - def fit_cross_conditional_mean_outcome_nuisance(self, t, m, x, y): + def _fit_cross_conditional_mean_outcome_nuisance(self, t, m, x, y): """ Fits the cross conditional mean outcome E[E[Y|T=t,M,X]|T=t',X] """ @@ -206,20 +207,24 @@ def fit_cross_conditional_mean_outcome_nuisance(self, t, m, x, y): # predict E[Y|T=1,M,X] self.regressors['y_t1_mx'] = clone(regressor_y) self.regressors['y_t1_mx'].fit(xm[train_mean1], y[train_mean1]) - mu_1mx_nested[train_nested] = self.regressors['y_t1_mx'].predict(xm[train_nested]) + mu_1mx_nested[train_nested] = self.regressors['y_t1_mx'].predict( + xm[train_nested]) # predict E[Y|T=0,M,X] self.regressors['y_t0_mx'] = clone(regressor_y) self.regressors['y_t0_mx'].fit(xm[train_mean0], y[train_mean0]) - mu_0mx_nested[train_nested] = self.regressors['y_t0_mx'].predict(xm[train_nested]) + mu_0mx_nested[train_nested] = self.regressors['y_t0_mx'].predict( + xm[train_nested]) # predict E[E[Y|T=1,M,X]|T=0,X] self.regressors['y_t1_x_t0'] = clone(regressor_y) - self.regressors['y_t1_x_t0'].fit(x[train_nested0], mu_1mx_nested[train_nested0]) + self.regressors['y_t1_x_t0'].fit( + x[train_nested0], mu_1mx_nested[train_nested0]) # predict E[E[Y|T=0,M,X]|T=1,X] self.regressors['y_t0_x_t1'] = clone(regressor_y) - self.regressors['y_t0_x_t1'].fit(x[train_nested1], mu_0mx_nested[train_nested1]) + self.regressors['y_t0_x_t1'].fit( + x[train_nested1], mu_0mx_nested[train_nested1]) # predict E[Y|T=1,X] self.regressors['y_t1_x'] = clone(regressor_y) @@ -229,8 +234,12 @@ def fit_cross_conditional_mean_outcome_nuisance(self, t, m, x, y): self.regressors['y_t0_x'] = clone(regressor_y) self.regressors['y_t0_x'].fit(x[train0], y[train0]) + return self - def fit_cross_conditional_mean_outcome_nuisance_discrete(self, t, m, x, y): + def _fit_cross_conditional_mean_outcome_nuisance_discrete(self, t, m, x, y): + """ + Fits the cross conditional mean outcome E[E[Y|T=t,M,X]|T=t',X] discrete + """ n = len(y) # Initialisation @@ -260,8 +269,10 @@ def fit_cross_conditional_mean_outcome_nuisance_discrete(self, t, m, x, y): self.regressors['y_t_mx'] = clone(regressor_y).fit(x_t_m, y) # predict E[Y|T=t,M,X] - mu_1mx[test_index] = self.regressors['y_t_mx'].predict(x_t1_m[test_index, :]) - mu_0mx[test_index] = self.regressors['y_t_mx'].predict(x_t0_m[test_index, :]) + mu_1mx[test_index] = self.regressors['y_t_mx'].predict( + x_t1_m[test_index, :]) + mu_0mx[test_index] = self.regressors['y_t_mx'].predict( + x_t0_m[test_index, :]) for i, b in enumerate(np.unique(m)): mb = m1 * b @@ -293,3 +304,4 @@ def fit_cross_conditional_mean_outcome_nuisance_discrete(self, t, m, x, y): x[test_index, :][~ind_t0, :], mu_0bx[test_index][~ind_t0]) + return self From 5bc00b4ecc3588e26cde09e95122a62862ec3735 Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 23 Oct 2024 22:57:27 +0200 Subject: [PATCH 13/84] rename experiment.y into example.py file --- src/med_bench/{experiment.py => example.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/med_bench/{experiment.py => example.py} (100%) diff --git a/src/med_bench/experiment.py b/src/med_bench/example.py similarity index 100% rename from src/med_bench/experiment.py rename to src/med_bench/example.py From 81263ee2993ce7065f4e2551905f4cd0693c97d7 Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 23 Oct 2024 22:58:17 +0200 Subject: [PATCH 14/84] apply refactoring PR comments --- src/med_bench/estimation/base.py | 321 +++++++++++++++++- src/med_bench/estimation/dml.py | 181 ---------- src/med_bench/estimation/g_computation.py | 190 ----------- src/med_bench/estimation/ipw.py | 121 ------- ...ct.py => mediation_coefficient_product.py} | 3 +- src/med_bench/estimation/mediation_dml.py | 131 +++++++ .../estimation/mediation_g_computation.py | 134 ++++++++ src/med_bench/estimation/mediation_ipw.py | 78 +++++ .../estimation/{mr.py => mediation_mr.py} | 146 ++------ src/med_bench/estimation/mediation_tmle.py | 203 +++++++++++ src/med_bench/estimation/tmle.py | 267 --------------- 11 files changed, 898 insertions(+), 877 deletions(-) delete mode 100644 src/med_bench/estimation/dml.py delete mode 100644 src/med_bench/estimation/g_computation.py delete mode 100644 src/med_bench/estimation/ipw.py rename src/med_bench/estimation/{coefficient_product.py => mediation_coefficient_product.py} (98%) create mode 100644 src/med_bench/estimation/mediation_dml.py create mode 100644 src/med_bench/estimation/mediation_g_computation.py create mode 100644 src/med_bench/estimation/mediation_ipw.py rename src/med_bench/estimation/{mr.py => mediation_mr.py} (54%) create mode 100644 src/med_bench/estimation/mediation_tmle.py delete mode 100644 src/med_bench/estimation/tmle.py diff --git a/src/med_bench/estimation/base.py b/src/med_bench/estimation/base.py index 86e6a78..54a99db 100644 --- a/src/med_bench/estimation/base.py +++ b/src/med_bench/estimation/base.py @@ -7,7 +7,7 @@ from med_bench.utils.decorators import fitted from med_bench.utils.scores import r_risk -from med_bench.utils.utils import _get_interactions +from med_bench.utils.utils import _get_interactions, _get_train_test_lists class Estimator: @@ -93,6 +93,44 @@ def estimate(self, t, m, x, y): """ pass + def _resize(self, t, m, x, y): + """Resize data for the right shape + + Parameters + ---------- + t array-like, shape (n_samples) + treatment value for each unit, binary + + m array-like, shape (n_samples) + mediator value for each unit, here m is necessary binary and uni- + dimensional + + x array-like, shape (n_samples, n_features_covariates) + covariates (potential confounders) values + + y array-like, shape (n_samples) + outcome value for each unit, continuous + """ + if len(y) != len(y.ravel()): + raise ValueError("Multidimensional y is not supported") + if len(t) != len(t.ravel()): + raise ValueError("Multidimensional t is not supported") + + n = len(y) + if len(x.shape) == 1: + x.reshape(n, 1) + if len(m.shape) == 1: + m = m.reshape(n, 1) + + if n != len(x) or n != len(m) or n != len(t): + raise ValueError( + "Inputs don't have the same number of observations") + + y = y.ravel() + t = t.ravel() + + return t, m, x, y + def _fit_nuisance(self, t, m, x, y, *args, **kwargs): """ Fits the score of the nuisance parameters """ @@ -305,3 +343,284 @@ def _fit_cross_conditional_mean_outcome_nuisance_discrete(self, t, m, x, y): mu_0bx[test_index][~ind_t0]) return self + + def _estimate_mediator_probability(self, t, m, x, y): + """ + Estimate mediator density f(M|T,X) + with train test lists from crossfitting + + Returns + ------- + f_m0x, array-like, shape (n_samples) + probabilities f(M|T=0,X) + f_m1x, array-like, shape (n_samples) + probabilities f(M|T=1,X) + """ + n = len(y) + if len(x.shape) == 1: + x = x.reshape(-1, 1) + + if len(t.shape) == 1: + t = t.reshape(-1, 1) + + t0 = np.zeros((n, 1)) + t1 = np.ones((n, 1)) + + m = m.ravel() + + train_test_list = _get_train_test_lists(self._crossfit, n, x) + + f_m0x, f_m1x = [np.zeros(n) for h in range(2)] + + t_x = _get_interactions(False, t, x) + t0_x = _get_interactions(False, t0, x) + t1_x = _get_interactions(False, t1, x) + + for _, test_index in train_test_list: + + test_ind = np.arange(len(test_index)) + + fm_0 = self._classifier_m.predict_proba(t0_x[test_index, :]) + fm_1 = self._classifier_m.predict_proba(t1_x[test_index, :]) + + # predict f(M|T=t,X) + f_m0x[test_index] = fm_0[test_ind, m[test_index]] + f_m1x[test_index] = fm_1[test_ind, m[test_index]] + + for i, b in enumerate(np.unique(m)): + f_0bx, f_1bx = [np.zeros(n) for h in range(2)] + + # predict f(M=m|T=t,X) + f_0bx[test_index] = fm_0[:, i] + f_1bx[test_index] = fm_1[:, i] + + return f_m0x, f_m1x + + def _estimate_mediators_probabilities(self, t, m, x, y): + """ + Estimate mediator density f(M|T,X) + with train test lists from crossfitting + + Returns + ------- + f_t0: list + contains array-like, shape (n_samples) probabilities f(M=m|T=0,X) + f_t1, list + contains array-like, shape (n_samples) probabilities f(M=m|T=1,X) + """ + n = len(y) + if len(x.shape) == 1: + x = x.reshape(-1, 1) + + if len(t.shape) == 1: + t = t.reshape(-1, 1) + + t0 = np.zeros((n, 1)) + t1 = np.ones((n, 1)) + + m = m.ravel() + + train_test_list = _get_train_test_lists(self._crossfit, n, x) + + f_t1, f_t0 = [], [] + + t_x = _get_interactions(False, t, x) + t0_x = _get_interactions(False, t0, x) + t1_x = _get_interactions(False, t1, x) + + for _, test_index in train_test_list: + + fm_0 = self._classifier_m.predict_proba(t0_x[test_index, :]) + fm_1 = self._classifier_m.predict_proba(t1_x[test_index, :]) + + for i, b in enumerate(np.unique(m)): + f_0bx, f_1bx = [np.zeros(n) for h in range(2)] + + # predict f(M=m|T=t,X) + f_0bx[test_index] = fm_0[:, i] + f_1bx[test_index] = fm_1[:, i] + + f_t0.append(f_0bx) + f_t1.append(f_1bx) + + return f_t0, f_t1 + + def _estimate_treatment_propensity_x(self, t, m, x): + """ + Estimate treatment probabilities P(T=1|X) with train + test lists from crossfitting + + Returns + ------- + p_x : array-like, shape (n_samples) + probabilities P(T=1|X) + p_xm : array-like, shape (n_samples) + probabilities P(T=1|X, M) + """ + n = len(t) + + p_x, p_xm = [np.zeros(n) for h in range(2)] + # compute propensity scores + if len(x.shape) == 1: + x = x.reshape(-1, 1) + if len(m.shape) == 1: + m = m.reshape(-1, 1) + if len(t.shape) == 1: + t = t.reshape(-1, 1) + + train_test_list = _get_train_test_lists(self._crossfit, n, x) + + for _, test_index in train_test_list: + + # predict P(T=1|X), P(T=1|X, M) + p_x[test_index] = self._classifier_t_x.predict_proba(x[test_index, :])[ + :, 1] + + return p_x + + def _estimate_treatment_probabilities(self, t, m, x): + """ + Estimate treatment probabilities P(T=1|X) and P(T=1|X, M) with train + test lists from crossfitting + + Returns + ------- + p_x : array-like, shape (n_samples) + probabilities P(T=1|X) + p_xm : array-like, shape (n_samples) + probabilities P(T=1|X, M) + """ + n = len(t) + + p_x, p_xm = [np.zeros(n) for h in range(2)] + # compute propensity scores + if len(x.shape) == 1: + x = x.reshape(-1, 1) + if len(m.shape) == 1: + m = m.reshape(-1, 1) + if len(t.shape) == 1: + t = t.reshape(-1, 1) + + train_test_list = _get_train_test_lists(self._crossfit, n, x) + + xm = np.hstack((x, m)) + + for _, test_index in train_test_list: + + # predict P(T=1|X), P(T=1|X, M) + p_x[test_index] = self._classifier_t_x.predict_proba(x[test_index, :])[ + :, 1] + p_xm[test_index] = self._classifier_t_xm.predict_proba(xm[test_index, :])[ + :, 1] + + return p_x, p_xm + + def _estimate_conditional_mean_outcome(self, t, m, x, y): + """ + Estimate conditional mean outcome E[Y|T,M,X] + with train test lists from crossfitting + + Returns + ------- + mu_t0: list + contains array-like, shape (n_samples) conditional mean outcome estimates E[Y|T=0,M=m,X] + mu_t1, list + contains array-like, shape (n_samples) conditional mean outcome estimates E[Y|T=1,M=m,X] + mu_m0x, array-like, shape (n_samples) + conditional mean outcome estimates E[Y|T=0,M,X] + mu_m1x, array-like, shape (n_samples) + conditional mean outcome estimates E[Y|T=1,M,X] + """ + n = len(y) + if len(x.shape) == 1: + x = x.reshape(-1, 1) + if len(m.shape) == 1: + mr = m.reshape(-1, 1) + else: + mr = np.copy(m) + if len(t.shape) == 1: + t = t.reshape(-1, 1) + + t0 = np.zeros((n, 1)) + t1 = np.ones((n, 1)) + m1 = np.ones((n, 1)) + + train_test_list = _get_train_test_lists(self._crossfit, n, x) + + mu_1mx, mu_0mx = [np.zeros(n) for _ in range(2)] + mu_t1, mu_t0 = [], [] + + m1 = np.ones((n, 1)) + + x_t_mr = _get_interactions(False, x, t, mr) + x_t1_m = _get_interactions(False, x, t1, m) + x_t0_m = _get_interactions(False, x, t0, m) + + for _, test_index in train_test_list: + + # predict E[Y|T=t,M,X] + mu_0mx[test_index] = self._regressor_y.predict( + x_t0_m[test_index, :]).squeeze() + mu_1mx[test_index] = self._regressor_y.predict( + x_t1_m[test_index, :]).squeeze() + + for i, b in enumerate(np.unique(m)): + mu_1bx, mu_0bx = [np.zeros(n) for h in range(2)] + mb = m1 * b + + # predict E[Y|T=t,M=m,X] + mu_0bx[test_index] = self._regressor_y.predict( + _get_interactions(False, x, t0, mb)[test_index, + :]).squeeze() + mu_1bx[test_index] = self._regressor_y.predict( + _get_interactions(False, x, t1, mb)[test_index, + :]).squeeze() + + mu_t0.append(mu_0bx) + mu_t1.append(mu_1bx) + + return mu_t0, mu_t1, mu_0mx, mu_1mx + + def _estimate_cross_conditional_mean_outcome_nesting(self, m, x, y): + """ + Estimate the conditional mean outcome, + the cross conditional mean outcome + + Returns + ------- + mu_m0x, array-like, shape (n_samples) + conditional mean outcome estimates E[Y|T=0,M,X] + mu_m1x, array-like, shape (n_samples) + conditional mean outcome estimates E[Y|T=1,M,X] + mu_0x, array-like, shape (n_samples) + cross conditional mean outcome estimates E[E[Y|T=0,M,X]|T=0,X] + E_mu_t0_t1, array-like, shape (n_samples) + cross conditional mean outcome estimates E[E[Y|T=0,M,X]|T=1,X] + E_mu_t1_t0, array-like, shape (n_samples) + cross conditional mean outcome estimates E[E[Y|T=1,M,X]|T=0,X] + mu_1x, array-like, shape (n_samples) + cross conditional mean outcome estimates E[E[Y|T=1,M,X]|T=1,X] + """ + n = len(y) + + xm = np.hstack((x, m)) + + # predict E[Y|T=1,M,X] + mu_1mx = self.regressors['y_t1_mx'].predict(xm) + + # predict E[Y|T=0,M,X] + mu_0mx = self.regressors['y_t0_mx'].predict(xm) + + # predict E[E[Y|T=1,M,X]|T=0,X] + E_mu_t1_t0 = self.regressors['y_t1_x_t0'].predict(x) + + # predict E[E[Y|T=0,M,X]|T=1,X] + E_mu_t0_t1 = self.regressors['y_t0_x_t1'].predict(x) + + # predict E[Y|T=1,X] + mu_1x = self.regressors['y_t1_x'].predict(x) + + # predict E[Y|T=0,X] + mu_0x = self.regressors['y_t0_x'].predict(x) + + return mu_0mx, mu_1mx, mu_0x, E_mu_t0_t1, E_mu_t1_t0, mu_1x diff --git a/src/med_bench/estimation/dml.py b/src/med_bench/estimation/dml.py deleted file mode 100644 index 2444c0e..0000000 --- a/src/med_bench/estimation/dml.py +++ /dev/null @@ -1,181 +0,0 @@ -import numpy as np - - -from med_bench.estimation.base import Estimator -from med_bench.nuisances.propensities import estimate_treatment_probabilities -from med_bench.nuisances.cross_conditional_outcome import estimate_cross_conditional_mean_outcome_nesting - - -class DoubleMachineLearning(Estimator): - """Implementation of double machine learning - - Parameters - ---------- - settings (dict): dictionnary of parameters - lbda (float): regularization parameter - support_vec_tol (float): tolerance for discarding non-supporting vectors - if |alpha_i| < support_vec_tol * lbda then vector is discarded - verbose (int): in {0, 1} - """ - - def __init__(self, procedure : str, density_estimation_method : str, clip : float, trim : float, normalized : bool, sample_split : int, **kwargs): - super().__init__(**kwargs) - - self._crossfit = 0 - self._procedure = procedure - self._density_estimation_method = density_estimation_method - self._clip = clip - self._trim = trim - self._normalized = normalized - self._sample_split = sample_split - - def resize(self, t, m, x, y): - """Resize data for the right shape - - Parameters - ---------- - t array-like, shape (n_samples) - treatment value for each unit, binary - - m array-like, shape (n_samples) - mediator value for each unit, here m is necessary binary and uni- - dimensional - - x array-like, shape (n_samples, n_features_covariates) - covariates (potential confounders) values - - y array-like, shape (n_samples) - outcome value for each unit, continuous - """ - if len(y) != len(y.ravel()): - raise ValueError("Multidimensional y is not supported") - if len(t) != len(t.ravel()): - raise ValueError("Multidimensional t is not supported") - - n = len(y) - if len(x.shape) == 1: - x.reshape(n, 1) - if len(m.shape) == 1: - m = m.reshape(n, 1) - - if n != len(x) or n != len(m) or n != len(t): - raise ValueError( - "Inputs don't have the same number of observations") - - y = y.ravel() - t = t.ravel() - - return t, m, x, y - - - def fit(self, t, m, x, y): - """Fits nuisance parameters to data - - """ - self.fit_score_nuisances(t, m, x, y) - t, m, x, y = self.resize(t, m, x, y) - - self.fit_treatment_propensity_x_nuisance(t, x) - self.fit_treatment_propensity_xm_nuisance(t, m, x) - self.fit_cross_conditional_mean_outcome_nuisance(t, m, x, y) - self._fitted = True - - if self.verbose: - print("Nuisance models fitted") - - - def estimate(self, t, m, x, y): - """Estimates causal effect on data - - """ - t, m, x, y = self.resize(t, m, x, y) - - p_x, p_xm = estimate_treatment_probabilities(t, - m, - x, - self._crossfit, - self._classifier_t_x, - self._classifier_t_xm) - - - mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 = estimate_cross_conditional_mean_outcome_nesting(m, x, y, self.regressors) - # trimming - not_trimmed = ( - (((1 - p_xm) * p_x) >= self._trim) - * ((1 - p_x) >= self._trim) - * (p_x >= self._trim) - * ((p_xm * (1 - p_x)) >= self._trim) - ) - - var_name = [ - "p_x", - "p_xm", - "mu_1mx", - "mu_0mx", - "E_mu_t1_t0", - "E_mu_t0_t1", - "E_mu_t1_t1", - "E_mu_t0_t0", - ] - for var in var_name: - exec(f"{var} = {var}[not_trimmed]") - nobs = np.sum(not_trimmed) - - # score computing - if self._normalized: - sum_score_m1 = np.mean(t / p_x) - sum_score_m0 = np.mean((1 - t) / (1 - p_x)) - sum_score_t1m0 = np.mean(t * (1 - p_xm) / (p_xm * (1 - p_x))) - sum_score_t0m1 = np.mean((1 - t) * p_xm / ((1 - p_xm) * p_x)) - y1m1 = (t / p_x * (y - E_mu_t1_t1)) / sum_score_m1 + E_mu_t1_t1 - y0m0 = (((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / sum_score_m0 - + E_mu_t0_t0) - y1m0 = ( - (t * (1 - p_xm) / (p_xm * (1 - p_x)) * (y - mu_1mx)) - / sum_score_t1m0 + ( - (1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0)) - / sum_score_m0 + E_mu_t1_t0 - ) - y0m1 = ( - ((1 - t) * p_xm / ((1 - p_xm) * p_x) * (y - mu_0mx)) - / sum_score_t0m1 - + (t / p_x * (mu_0mx - E_mu_t0_t1)) / sum_score_m1 - + E_mu_t0_t1 - ) - else: - y1m1 = t / p_x * (y - E_mu_t1_t1) + E_mu_t1_t1 - y0m0 = (1 - t) / (1 - p_x) * (y - E_mu_t0_t0) + E_mu_t0_t0 - y1m0 = ( - t * (1 - p_xm) / (p_xm * (1 - p_x)) * (y - mu_1mx) - + (1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0) - + E_mu_t1_t0 - ) - y0m1 = ( - (1 - t) * p_xm / ((1 - p_xm) * p_x) * (y - mu_0mx) - + t / p_x * (mu_0mx - E_mu_t0_t1) - + E_mu_t0_t1 - ) - - # mean score computing - eta_t1t1 = np.mean(y1m1) - eta_t0t0 = np.mean(y0m0) - eta_t1t0 = np.mean(y1m0) - eta_t0t1 = np.mean(y0m1) - - # effects computing - total_effect = eta_t1t1 - eta_t0t0 - - direct_effect_treated = eta_t1t1 - eta_t0t1 - direct_effect_control = eta_t1t0 - eta_t0t0 - indirect_effect_treated = eta_t1t1 - eta_t1t0 - indirect_effect_control = eta_t0t1 - eta_t0t0 - - causal_effects = { - 'total_effect': total_effect, - 'direct_effect_treated': direct_effect_treated, - 'direct_effect_control': direct_effect_control, - 'indirect_effect_treated': indirect_effect_treated, - 'indirect_effect_control': indirect_effect_control - } - - return causal_effects diff --git a/src/med_bench/estimation/g_computation.py b/src/med_bench/estimation/g_computation.py deleted file mode 100644 index ae3d20f..0000000 --- a/src/med_bench/estimation/g_computation.py +++ /dev/null @@ -1,190 +0,0 @@ -import numpy as np - -from sklearn.cluster import KMeans - -from med_bench.estimation.base import Estimator - -from med_bench.utils.decorators import fitted -from med_bench.utils.utils import (is_array_integer) - -from med_bench.nuisances.density import estimate_mediators_probabilities -from med_bench.nuisances.conditional_outcome import estimate_conditional_mean_outcome -from med_bench.nuisances.cross_conditional_outcome import estimate_cross_conditional_mean_outcome_nesting - -class GComputation(Estimator): - """GComputation estimation method class - """ - def __init__(self, crossfit : int, procedure : str, **kwargs): - """Initalization of the GComputation estimation method class - - Parameters - ---------- - crossfit : int - 1 or 0 - procedure : str - nesting or discrete - """ - super().__init__(**kwargs) - - self._crossfit = crossfit - self._procedure = procedure - - def resize(self, t, m, x, y): - """Resize data for the right shape - - Parameters - ---------- - t array-like, shape (n_samples) - treatment value for each unit, binary - - m array-like, shape (n_samples) - mediator value for each unit, here m is necessary binary and uni- - dimensional - - x array-like, shape (n_samples, n_features_covariates) - covariates (potential confounders) values - - y array-like, shape (n_samples) - outcome value for each unit, continuous - """ - if len(y) != len(y.ravel()): - raise ValueError("Multidimensional y is not supported") - if len(t) != len(t.ravel()): - raise ValueError("Multidimensional t is not supported") - - n = len(y) - if len(x.shape) == 1: - x.reshape(n, 1) - if len(m.shape) == 1: - m.reshape(n, 1) - - if n != len(x) or n != len(m) or n != len(t): - raise ValueError( - "Inputs don't have the same number of observations") - - y = y.ravel() - t = t.ravel() - - return t, m, x, y - - - def fit(self, t, m, x, y): - """Fits nuisance parameters to data - - """ - - self.fit_score_nuisances(t, m, x, y) - t, m, x, y = self.resize(t, m, x, y) - - if self._procedure == 'discrete': - if not is_array_integer(m): - self._bucketizer = KMeans(n_clusters=10, random_state=self.rng, - n_init="auto").fit(m) - m = self._bucketizer.predict(m) - self.fit_mediator_nuisance(t, m, x) - self.fit_conditional_mean_outcome_nuisance(t, m, x, y) - - elif self._procedure == 'nesting': - self.fit_cross_conditional_mean_outcome_nuisance(t, m, x, y) - else: - raise NotImplementedError - self._fitted = True - - if self.verbose: - print("Nuisance models fitted") - - def estimate_discrete(self, t, m, x, y): - """Estimates causal effect on data using a discrete summation on - mediators - - """ - - # estimate mediator densities - f_t0, f_t1 = estimate_mediators_probabilities(t, m, x, y, - self._crossfit, - self._classifier_m, - False) - - # estimate conditional mean outcomes - mu_t0, mu_t1, _, _ = ( - estimate_conditional_mean_outcome(t, m, x, y, - self._crossfit, - self._regressor_y, - False)) - - n = len(y) - - direct_effect_treated = 0 - direct_effect_control = 0 - indirect_effect_treated = 0 - indirect_effect_control = 0 - - for f_1bx, f_0bx, mu_1bx, mu_0bx in zip(f_t1, f_t0, mu_t1, mu_t0): - direct_effect_ib = mu_1bx - mu_0bx - direct_effect_treated += direct_effect_ib * f_1bx - direct_effect_control += direct_effect_ib * f_0bx - indirect_effect_ib = f_1bx - f_0bx - indirect_effect_treated += indirect_effect_ib * mu_1bx - indirect_effect_control += indirect_effect_ib * mu_0bx - - direct_effect_treated = direct_effect_treated.sum() / n - direct_effect_control = direct_effect_control.sum() / n - indirect_effect_treated = indirect_effect_treated.sum() / n - indirect_effect_control = indirect_effect_control.sum() / n - - total_effect = direct_effect_control + indirect_effect_treated - - causal_effects = { - 'total_effect': total_effect, - 'direct_effect_treated': direct_effect_treated, - 'direct_effect_control': direct_effect_control, - 'indirect_effect_treated': indirect_effect_treated, - 'indirect_effect_control': indirect_effect_control - } - return causal_effects - - def estimate_nesting(self, t, m, x, y): - - mu_0mx, mu_1mx, y0m0, y0m1, y1m0, y1m1 = estimate_cross_conditional_mean_outcome_nesting(m, x, y, self.regressors) - - # mean score computing - eta_t1t1 = np.mean(y1m1) - eta_t0t0 = np.mean(y0m0) - eta_t1t0 = np.mean(y1m0) - eta_t0t1 = np.mean(y0m1) - - # effects computing - total_effect = eta_t1t1 - eta_t0t0 - - direct_effect_treated = eta_t1t1 - eta_t0t1 - direct_effect_control = eta_t1t0 - eta_t0t0 - indirect_effect_treated = eta_t1t1 - eta_t1t0 - indirect_effect_control = eta_t0t1 - eta_t0t0 - - causal_effects = { - 'total_effect': total_effect, - 'direct_effect_treated': direct_effect_treated, - 'direct_effect_control': direct_effect_control, - 'indirect_effect_treated': indirect_effect_treated, - 'indirect_effect_control': indirect_effect_control - } - - return causal_effects - - @fitted - def estimate(self, t, m, x, y): - """Estimates causal effect on data - - """ - - t, m, x, y = self.resize(t, m, x, y) - - if self._procedure == 'discrete': - if not is_array_integer(m): - m = self._bucketizer.predict(m) - return self.estimate_discrete(t, m, x, y) - - elif self._procedure == 'nesting': - return self.estimate_nesting(t, m, x, y) - - diff --git a/src/med_bench/estimation/ipw.py b/src/med_bench/estimation/ipw.py deleted file mode 100644 index 24e3ede..0000000 --- a/src/med_bench/estimation/ipw.py +++ /dev/null @@ -1,121 +0,0 @@ -import numpy as np - -from med_bench.nuisances.propensities import estimate_treatment_probabilities - -from med_bench.estimation.base import Estimator -from med_bench.utils.decorators import fitted - - -class ImportanceWeighting(Estimator): - - def __init__(self, clip : float, trim : float, **kwargs): - """IPW estimator - - Attributes: - _clip (float): clipping the propensities - _trim (float): remove propensities which are below the trim threshold - - """ - super().__init__(**kwargs) - self._crossfit = 0 - self._clip = clip - self._trim = trim - - def resize(self, t, m, x, y): - """Resize data for the right shape - - Parameters - ---------- - t array-like, shape (n_samples) - treatment value for each unit, binary - - m array-like, shape (n_samples) - mediator value for each unit, here m is necessary binary and uni- - dimensional - - x array-like, shape (n_samples, n_features_covariates) - covariates (potential confounders) values - - y array-like, shape (n_samples) - outcome value for each unit, continuous - """ - if len(y) != len(y.ravel()): - raise ValueError("Multidimensional y is not supported") - if len(t) != len(t.ravel()): - raise ValueError("Multidimensional t is not supported") - - n = len(y) - if len(x.shape) == 1: - x.reshape(n, 1) - if len(m.shape) == 1: - m = m.reshape(n, 1) - - if n != len(x) or n != len(m) or n != len(t): - raise ValueError( - "Inputs don't have the same number of observations") - - y = y.ravel() - t = t.ravel() - - return t, m, x, y - - def fit(self, t, m, x, y): - """Fits nuisance parameters to data - - """ - self.fit_score_nuisances(t, m, x, y) - t, m, x, y = self.resize(t, m, x, y) - - self.fit_treatment_propensity_x_nuisance(t, x) - self.fit_treatment_propensity_xm_nuisance(t, m, x) - - self._fitted = True - - if self.verbose: - print("Nuisance models fitted") - - @fitted - def estimate(self, t, m, x, y): - """Estimates causal effect on data - - """ - t, m, x, y = self.resize(t, m, x, y) - p_x, p_xm = estimate_treatment_probabilities(t, - m, - x, - self._crossfit, - self._classifier_t_x, - self._classifier_t_xm) - - ind = ((p_xm > self._trim) & (p_xm < (1 - self._trim))) - y, t, p_x, p_xm = y[ind], t[ind], p_x[ind], p_xm[ind] - - # note on the names, ytmt' = Y(t, M(t')), the treatment needs to be - # binary but not the mediator - p_x = np.clip(p_x, self._clip, 1 - self._clip) - p_xm = np.clip(p_xm, self._clip, 1 - self._clip) - - # importance weighting - y1m1 = np.sum(y * t / p_x) / np.sum(t / p_x) - y1m0 = np.sum(y * t * (1 - p_xm) / (p_xm * (1 - p_x))) /\ - np.sum(t * (1 - p_xm) / (p_xm * (1 - p_x))) - y0m0 = np.sum(y * (1 - t) / (1 - p_x)) /\ - np.sum((1 - t) / (1 - p_x)) - y0m1 = np.sum(y * (1 - t) * p_xm / ((1 - p_xm) * p_x)) /\ - np.sum((1 - t) * p_xm / ((1 - p_xm) * p_x)) - - total_effect = y1m1 - y0m0 - direct_effect_treated = y1m1 - y0m1 - direct_effect_control = y1m0 - y0m0 - indirect_effect_treated = y1m1 - y1m0 - indirect_effect_control = y0m1 - y0m0 - - causal_effects = { - 'total_effect': total_effect, - 'direct_effect_treated': direct_effect_treated, - 'direct_effect_control': direct_effect_control, - 'indirect_effect_treated': indirect_effect_treated, - 'indirect_effect_control': indirect_effect_control - } - - return causal_effects diff --git a/src/med_bench/estimation/coefficient_product.py b/src/med_bench/estimation/mediation_coefficient_product.py similarity index 98% rename from src/med_bench/estimation/coefficient_product.py rename to src/med_bench/estimation/mediation_coefficient_product.py index ee9fe6b..b9449b0 100644 --- a/src/med_bench/estimation/coefficient_product.py +++ b/src/med_bench/estimation/mediation_coefficient_product.py @@ -1,5 +1,4 @@ import numpy as np - from sklearn.linear_model import RidgeCV from med_bench.estimation.base import Estimator @@ -39,7 +38,7 @@ def fit(self, t, m, x, y): outcome value for each unit, continuous """ - self.fit_score_nuisances(t, m, x, y) + self._fit_nuisance(t, m, x, y) # estimate mediator densities if self._regularize: diff --git a/src/med_bench/estimation/mediation_dml.py b/src/med_bench/estimation/mediation_dml.py new file mode 100644 index 0000000..44438e4 --- /dev/null +++ b/src/med_bench/estimation/mediation_dml.py @@ -0,0 +1,131 @@ +import numpy as np + +from med_bench.estimation.base import Estimator + + +class DoubleMachineLearning(Estimator): + """Implementation of double machine learning + + Parameters + ---------- + alpha (float): regularization parameter + support_vec_tol (float): tolerance for discarding non-supporting vectors + if |alpha_i| < support_vec_tol * alpha then vector is discarded + """ + + def __init__(self, procedure: str, clip: float, trim: float, normalized: bool, **kwargs): + super().__init__(**kwargs) + + self._crossfit = 0 + self._procedure = procedure + self._clip = clip + self._trim = trim + self._normalized = normalized + + def fit(self, t, m, x, y): + """Fits nuisance parameters to data + + """ + self._fit_nuisance(t, m, x, y) + t, m, x, y = self._resize(t, m, x, y) + + self._fit_treatment_propensity_x_nuisance(t, x) + self._fit_treatment_propensity_xm_nuisance(t, m, x) + self._fit_cross_conditional_mean_outcome_nuisance(t, m, x, y) + self._fitted = True + + if self.verbose: + print("Nuisance models fitted") + + def estimate(self, t, m, x, y): + """Estimates causal effect on data + + """ + t, m, x, y = self._resize(t, m, x, y) + + p_x, p_xm = self._estimate_treatment_probabilities(t, + m, + x) + + mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 = self._estimate_cross_conditional_mean_outcome_nesting( + m, x, y) + + not_trimmed = ( + (((1 - p_xm) * p_x) >= self._trim) + * ((1 - p_x) >= self._trim) + * (p_x >= self._trim) + * ((p_xm * (1 - p_x)) >= self._trim) + ) + + var_name = [ + "p_x", + "p_xm", + "mu_1mx", + "mu_0mx", + "E_mu_t1_t0", + "E_mu_t0_t1", + "E_mu_t1_t1", + "E_mu_t0_t0", + ] + for var in var_name: + exec(f"{var} = {var}[not_trimmed]") + nobs = np.sum(not_trimmed) + + # score computing + if self._normalized: + sum_score_m1 = np.mean(t / p_x) + sum_score_m0 = np.mean((1 - t) / (1 - p_x)) + sum_score_t1m0 = np.mean(t * (1 - p_xm) / (p_xm * (1 - p_x))) + sum_score_t0m1 = np.mean((1 - t) * p_xm / ((1 - p_xm) * p_x)) + y1m1 = (t / p_x * (y - E_mu_t1_t1)) / sum_score_m1 + E_mu_t1_t1 + y0m0 = (((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / sum_score_m0 + + E_mu_t0_t0) + y1m0 = ( + (t * (1 - p_xm) / (p_xm * (1 - p_x)) * (y - mu_1mx)) + / sum_score_t1m0 + ( + (1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0)) + / sum_score_m0 + E_mu_t1_t0 + ) + y0m1 = ( + ((1 - t) * p_xm / ((1 - p_xm) * p_x) * (y - mu_0mx)) + / sum_score_t0m1 + + (t / p_x * (mu_0mx - E_mu_t0_t1)) / sum_score_m1 + + E_mu_t0_t1 + ) + else: + y1m1 = t / p_x * (y - E_mu_t1_t1) + E_mu_t1_t1 + y0m0 = (1 - t) / (1 - p_x) * (y - E_mu_t0_t0) + E_mu_t0_t0 + y1m0 = ( + t * (1 - p_xm) / (p_xm * (1 - p_x)) * (y - mu_1mx) + + (1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0) + + E_mu_t1_t0 + ) + y0m1 = ( + (1 - t) * p_xm / ((1 - p_xm) * p_x) * (y - mu_0mx) + + t / p_x * (mu_0mx - E_mu_t0_t1) + + E_mu_t0_t1 + ) + + # mean score computing + eta_t1t1 = np.mean(y1m1) + eta_t0t0 = np.mean(y0m0) + eta_t1t0 = np.mean(y1m0) + eta_t0t1 = np.mean(y0m1) + + # effects computing + total_effect = eta_t1t1 - eta_t0t0 + + direct_effect_treated = eta_t1t1 - eta_t0t1 + direct_effect_control = eta_t1t0 - eta_t0t0 + indirect_effect_treated = eta_t1t1 - eta_t1t0 + indirect_effect_control = eta_t0t1 - eta_t0t0 + + causal_effects = { + 'total_effect': total_effect, + 'direct_effect_treated': direct_effect_treated, + 'direct_effect_control': direct_effect_control, + 'indirect_effect_treated': indirect_effect_treated, + 'indirect_effect_control': indirect_effect_control + } + + return causal_effects diff --git a/src/med_bench/estimation/mediation_g_computation.py b/src/med_bench/estimation/mediation_g_computation.py new file mode 100644 index 0000000..1e2bf3c --- /dev/null +++ b/src/med_bench/estimation/mediation_g_computation.py @@ -0,0 +1,134 @@ +import numpy as np +from sklearn.cluster import KMeans + +from med_bench.estimation.base import Estimator +from med_bench.utils.decorators import fitted +from med_bench.utils.utils import is_array_integer + + +class GComputation(Estimator): + """GComputation estimation method class + """ + + def __init__(self, crossfit: int, procedure: str, **kwargs): + """Initalization of the GComputation estimation method class + + Parameters + ---------- + crossfit : int + Any integer value greater than 0. + procedure : str + nesting or discrete + """ + super().__init__(**kwargs) + + self._crossfit = crossfit + self._procedure = procedure + + def fit(self, t, m, x, y): + """Fits nuisance parameters to data + + """ + + self._fit_nuisance(t, m, x, y) + t, m, x, y = self._resize(t, m, x, y) + + if self._procedure == 'nesting': + self._fit_cross_conditional_mean_outcome_nuisance(t, m, x, y) + else: + raise NotImplementedError + self._fitted = True + + if self.verbose: + print("Nuisance models fitted") + + return self + + def _estimate_discrete(self, t, m, x, y): + """Estimates causal effect on data using a discrete summation on + mediators + + """ + + # estimate mediator densities + f_t0, f_t1 = self._estimate_mediators_probabilities(t, m, x, y) + + # estimate conditional mean outcomes + mu_t0, mu_t1, _, _ = ( + self._estimate_conditional_mean_outcome(t, m, x, y)) + + n = len(y) + + direct_effect_treated = 0 + direct_effect_control = 0 + indirect_effect_treated = 0 + indirect_effect_control = 0 + + for f_1bx, f_0bx, mu_1bx, mu_0bx in zip(f_t1, f_t0, mu_t1, mu_t0): + direct_effect_ib = mu_1bx - mu_0bx + direct_effect_treated += direct_effect_ib * f_1bx + direct_effect_control += direct_effect_ib * f_0bx + indirect_effect_ib = f_1bx - f_0bx + indirect_effect_treated += indirect_effect_ib * mu_1bx + indirect_effect_control += indirect_effect_ib * mu_0bx + + direct_effect_treated = direct_effect_treated.sum() / n + direct_effect_control = direct_effect_control.sum() / n + indirect_effect_treated = indirect_effect_treated.sum() / n + indirect_effect_control = indirect_effect_control.sum() / n + + total_effect = direct_effect_control + indirect_effect_treated + + causal_effects = { + 'total_effect': total_effect, + 'direct_effect_treated': direct_effect_treated, + 'direct_effect_control': direct_effect_control, + 'indirect_effect_treated': indirect_effect_treated, + 'indirect_effect_control': indirect_effect_control + } + return causal_effects + + def _estimate_nesting(self, t, m, x, y): + + mu_0mx, mu_1mx, y0m0, y0m1, y1m0, y1m1 = self._estimate_cross_conditional_mean_outcome_nesting( + m, x, y) + + # mean score computing + eta_t1t1 = np.mean(y1m1) + eta_t0t0 = np.mean(y0m0) + eta_t1t0 = np.mean(y1m0) + eta_t0t1 = np.mean(y0m1) + + # effects computing + total_effect = eta_t1t1 - eta_t0t0 + + direct_effect_treated = eta_t1t1 - eta_t0t1 + direct_effect_control = eta_t1t0 - eta_t0t0 + indirect_effect_treated = eta_t1t1 - eta_t1t0 + indirect_effect_control = eta_t0t1 - eta_t0t0 + + causal_effects = { + 'total_effect': total_effect, + 'direct_effect_treated': direct_effect_treated, + 'direct_effect_control': direct_effect_control, + 'indirect_effect_treated': indirect_effect_treated, + 'indirect_effect_control': indirect_effect_control + } + + return causal_effects + + @fitted + def estimate(self, t, m, x, y): + """Estimates causal effect on data + + """ + + t, m, x, y = self._resize(t, m, x, y) + + if self._procedure == 'discrete': + if not is_array_integer(m): + m = self._bucketizer.predict(m) + return self._estimate_discrete(t, m, x, y) + + elif self._procedure == 'nesting': + return self._estimate_nesting(t, m, x, y) diff --git a/src/med_bench/estimation/mediation_ipw.py b/src/med_bench/estimation/mediation_ipw.py new file mode 100644 index 0000000..7d657e9 --- /dev/null +++ b/src/med_bench/estimation/mediation_ipw.py @@ -0,0 +1,78 @@ +import numpy as np + +from med_bench.estimation.base import Estimator +from med_bench.utils.decorators import fitted + + +class ImportanceWeighting(Estimator): + + def __init__(self, clip: float, trim: float, **kwargs): + """IPW estimator + + Attributes: + _clip (float): clipping the propensities + _trim (float): remove propensities which are below the trim threshold + + """ + super().__init__(**kwargs) + self._crossfit = 0 + self._clip = clip + self._trim = trim + + def fit(self, t, m, x, y): + """Fits nuisance parameters to data + + """ + self._fit_nuisance(t, m, x, y) + t, m, x, y = self._resize(t, m, x, y) + + self._fit_treatment_propensity_x_nuisance(t, x) + self._fit_treatment_propensity_xm_nuisance(t, m, x) + + self._fitted = True + + if self.verbose: + print("Nuisance models fitted") + + return self + + @fitted + def estimate(self, t, m, x, y): + """Estimates causal effect on data + + """ + t, m, x, y = self.resize(t, m, x, y) + p_x, p_xm = self._estimate_treatment_probabilities(t, m, x) + + ind = ((p_xm > self._trim) & (p_xm < (1 - self._trim))) + y, t, p_x, p_xm = y[ind], t[ind], p_x[ind], p_xm[ind] + + # note on the names, ytmt' = Y(t, M(t')), the treatment needs to be + # binary but not the mediator + p_x = np.clip(p_x, self._clip, 1 - self._clip) + p_xm = np.clip(p_xm, self._clip, 1 - self._clip) + + # importance weighting + y1m1 = np.sum(y * t / p_x) / np.sum(t / p_x) + y1m0 = np.sum(y * t * (1 - p_xm) / (p_xm * (1 - p_x))) /\ + np.sum(t * (1 - p_xm) / (p_xm * (1 - p_x))) + y0m0 = np.sum(y * (1 - t) / (1 - p_x)) /\ + np.sum((1 - t) / (1 - p_x)) + y0m1 = np.sum(y * (1 - t) * p_xm / ((1 - p_xm) * p_x)) /\ + np.sum((1 - t) * p_xm / ((1 - p_xm) * p_x)) + + total_effect = y1m1 - y0m0 + direct_effect_treated = y1m1 - y0m1 + direct_effect_control = y1m0 - y0m0 + indirect_effect_treated = y1m1 - y1m0 + indirect_effect_control = y0m1 - y0m0 + + causal_effects = { + 'total_effect': total_effect, + 'direct_effect_treated': direct_effect_treated, + 'direct_effect_control': direct_effect_control, + 'indirect_effect_treated': indirect_effect_treated, + 'indirect_effect_control': indirect_effect_control + } + + return causal_effects diff --git a/src/med_bench/estimation/mr.py b/src/med_bench/estimation/mediation_mr.py similarity index 54% rename from src/med_bench/estimation/mr.py rename to src/med_bench/estimation/mediation_mr.py index dbeb17e..a7d993c 100644 --- a/src/med_bench/estimation/mr.py +++ b/src/med_bench/estimation/mediation_mr.py @@ -20,7 +20,7 @@ class MultiplyRobust(Estimator): verbose (int): in {0, 1} """ - def __init__(self, procedure : str, ratio : str, density_estimation_method : str, clip : float, normalized, **kwargs): + def __init__(self, procedure: str, ratio: str, density_estimation_method: str, clip: float, normalized, **kwargs): super().__init__(**kwargs) self._crossfit = 0 @@ -30,79 +30,30 @@ def __init__(self, procedure : str, ratio : str, density_estimation_method : str self._clip = clip self._normalized = normalized - def resize(self, t, m, x, y): - """Resize data for the right shape - - Parameters - ---------- - t array-like, shape (n_samples) - treatment value for each unit, binary - - m array-like, shape (n_samples) - mediator value for each unit, here m is necessary binary and uni- - dimensional - - x array-like, shape (n_samples, n_features_covariates) - covariates (potential confounders) values - - y array-like, shape (n_samples) - outcome value for each unit, continuous - """ - if len(y) != len(y.ravel()): - raise ValueError("Multidimensional y is not supported") - if len(t) != len(t.ravel()): - raise ValueError("Multidimensional t is not supported") - - n = len(y) - if len(x.shape) == 1: - x.reshape(n, 1) - if len(m.shape) == 1: - m.reshape(n, 1) - - if n != len(x) or n != len(m) or n != len(t): - raise ValueError( - "Inputs don't have the same number of observations") - - y = y.ravel() - t = t.ravel() - # m = m.ravel() - - return t, m, x, y - - def fit(self, t, m, x, y): """Fits nuisance parameters to data """ # bucketize if needed - t, m, x, y = self.resize(t, m, x, y) + t, m, x, y = self._resize(t, m, x, y) # fit nuisance functions - self.fit_score_nuisances(t, m, x, y) + self._fit_nuisance(t, m, x, y) if self._ratio == 'density': - self.fit_treatment_propensity_x_nuisance(t, x) - self.fit_mediator_nuisance(t, m, x) + self._fit_treatment_propensity_x_nuisance(t, x) + self._fit_mediator_nuisance(t, m, x) elif self._ratio == 'propensities': - self.fit_treatment_propensity_x_nuisance(t, x) - self.fit_treatment_propensity_xm_nuisance(t, m, x) + self._fit_treatment_propensity_x_nuisance(t, x) + self._fit_treatment_propensity_xm_nuisance(t, m, x) else: raise NotImplementedError - - if self._procedure == 'nesting': - self.fit_cross_conditional_mean_outcome_nuisance(t, m, x, y) - elif self._procedure == 'discrete': + if self._procedure == 'nesting': + self._fit_cross_conditional_mean_outcome_nuisance(t, m, x, y) - if not is_array_integer(m): - self._bucketizer = KMeans(n_clusters=10, random_state=self.rng, - n_init="auto").fit(m) - m = self._bucketizer.predict(m) - self.fit_mediator_nuisance(t, m, x) - self.fit_cross_conditional_mean_outcome_nuisance_discrete(t, m, x, y) - else: raise NotImplementedError @@ -111,6 +62,7 @@ def fit(self, t, m, x, y): if self.verbose: print("Nuisance models fitted") + return self @fitted def estimate(self, t, m, x, y): @@ -119,32 +71,20 @@ def estimate(self, t, m, x, y): """ # Format checking t, m, x, y = self.resize(t, m, x, y) - + if self._ratio == 'density': - f_m0x, f_m1x = estimate_mediator_density(t, m, x, y, - self._crossfit, - self._classifier_m, - False) - p_x = estimate_treatment_propensity_x(t, - m, - x, - self._crossfit, - self._classifier_t_x) + f_m0x, f_m1x = self._estimate_mediator_probability(t, m, x, y) + + p_x = self._estimate_treatment_propensity_x(t, m, x) ratio_t1_m0 = f_m0x / (p_x * f_m1x) ratio_t0_m1 = f_m1x / ((1 - p_x) * f_m0x) elif self._ratio == 'propensities': - p_x, p_xm = estimate_treatment_probabilities(t, - m, - x, - self._crossfit, - self._classifier_t_x, - self._classifier_t_xm) + p_x, p_xm = self._estimate_treatment_probabilities(t, m, x) ratio_t1_m0 = (1-p_xm) / ((1 - p_x) * p_xm) ratio_t0_m1 = p_xm / ((1 - p_xm) * p_x) if self._procedure == 'nesting': - # p_x = estimate_treatment_propensity_x(t, # m, @@ -161,31 +101,7 @@ def estimate(self, t, m, x, y): # False) mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 = ( - estimate_cross_conditional_mean_outcome_nesting(m, x, y, self.regressors)) - - - else: - if not is_array_integer(m): - m = self._bucketizer.predict(m) - - # p_x = estimate_treatment_propensity_x(t, - # m, - # x, - # self._crossfit, - # self._classifier_t_x) - - f_t0, f_t1 = estimate_mediators_probabilities(t, - m, - x, - y, - self._crossfit, - self._classifier_m, - False) - - f = f_t0, f_t1 - mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 = ( - estimate_cross_conditional_mean_outcome_discrete(m, x, y, f, self.regressors)) - + self._estimate_cross_conditional_mean_outcome_nesting(m, x, y)) # clipping # p_x_clip = p_x != np.clip(p_x, self._clip, 1 - self._clip) @@ -220,11 +136,11 @@ def estimate(self, t, m, x, y): # + E_mu_t1_t0 # ) y1m0 = ( - (t * ratio_t1_m0 * ( - y - mu_1mx)) / sum_score_t1m0 - + ((1 - t) / (1 - p_x) * ( - mu_1mx - E_mu_t1_t0)) / sum_score_m0 - + E_mu_t1_t0 + (t * ratio_t1_m0 * ( + y - mu_1mx)) / sum_score_t1m0 + + ((1 - t) / (1 - p_x) * ( + mu_1mx - E_mu_t1_t0)) / sum_score_m0 + + E_mu_t1_t0 ) # y0m1 = ( # ((1 - t) / (1 - p_x) * (f_m1x / f_m0x) * (y - mu_0mx)) @@ -233,10 +149,10 @@ def estimate(self, t, m, x, y): # + E_mu_t0_t1 # ) y0m1 = ( - ((1 - t) * ratio_t0_m1 * (y - mu_0mx)) - / sum_score_t0m1 + t / p_x * ( - mu_0mx - E_mu_t0_t1) / sum_score_m1 - + E_mu_t0_t1 + ((1 - t) * ratio_t0_m1 * (y - mu_0mx)) + / sum_score_t0m1 + t / p_x * ( + mu_0mx - E_mu_t0_t1) / sum_score_m1 + + E_mu_t0_t1 ) else: y1m1 = t / p_x * (y - E_mu_t1_t1) + E_mu_t1_t1 @@ -252,14 +168,14 @@ def estimate(self, t, m, x, y): # + E_mu_t0_t1 # ) y1m0 = ( - t * ratio_t1_m0 * (y - mu_1mx) - + (1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0) - + E_mu_t1_t0 + t * ratio_t1_m0 * (y - mu_1mx) + + (1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0) + + E_mu_t1_t0 ) y0m1 = ( - (1 - t) * ratio_t0_m1 * (y - mu_0mx) - + t / p_x * (mu_0mx - E_mu_t0_t1) - + E_mu_t0_t1 + (1 - t) * ratio_t0_m1 * (y - mu_0mx) + + t / p_x * (mu_0mx - E_mu_t0_t1) + + E_mu_t0_t1 ) # effects computing diff --git a/src/med_bench/estimation/mediation_tmle.py b/src/med_bench/estimation/mediation_tmle.py new file mode 100644 index 0000000..31ce0e7 --- /dev/null +++ b/src/med_bench/estimation/mediation_tmle.py @@ -0,0 +1,203 @@ +import numpy as np +from sklearn.base import clone +from sklearn.linear_model import LinearRegression + +from med_bench.estimation.base import Estimator +from med_bench.nuisances.utils import _get_regressor +from med_bench.utils.utils import _get_interactions +from med_bench.utils.decorators import fitted + +ALPHA = 10 + + +class TMLE(Estimator): + """Implementation of targeted maximum likelihood estimator + + Parameters + ---------- + settings (dict): dictionnary of parameters + lbda (float): regularization parameter + support_vec_tol (float): tolerance for discarding non-supporting vectors + if |alpha_i| < support_vec_tol * lbda then vector is discarded + verbose (int): in {0, 1} + """ + + def __init__(self, procedure, ratio, clip, normalized, **kwargs): + super().__init__(**kwargs) + + self._crossfit = 0 + self._procedure = procedure + self._ratio = ratio + self._clip = clip + self._normalized = normalized + + def _one_step_correction_direct(self, t, m, x, y): + + n = t.shape[0] + t, m, x, y = self.resize(t, m, x, y) + t0 = np.zeros((n)) + t1 = np.ones((n)) + + # estimate mediator densities + if self._ratio == 'density': + f_m0x, f_m1x = self._estimate_mediator_probability(t, m, x, y) + p_x = self._estimate_treatment_propensity_x(t, m, x) + ratio = f_m0x / (p_x * f_m1x) + + elif self._ratio == 'propensities': + p_x, p_xm = self._estimate_treatment_probabilities(t, m, x) + ratio = (1-p_xm) / ((1 - p_x) * p_xm) + + h_corrector = t * ratio - (1 - t)/(1 - p_x) + + x_t_mr = _get_interactions(False, x, t, m) + mu_tmx = self._regressor_y.predict(x_t_mr) + # import pdb; pdb.set_trace() + reg = LinearRegression(fit_intercept=False).fit( + h_corrector.reshape(-1, 1), (y-mu_tmx).squeeze()) + epsilon_h = reg.coef_ + # epsilon_h = 0 + print(epsilon_h) + + mu_t0_mx = self._regressor_y.predict( + _get_interactions(False, x, t0, m)) + h_corrector_t0 = t0 * ratio - (1 - t0)/(1 - p_x) + mu_t1_mx = self._regressor_y.predict( + _get_interactions(False, x, t1, m)) + h_corrector_t1 = t1 * ratio - (1 - t1)/(1 - p_x) + mu_t0_mx_star = mu_t0_mx + epsilon_h * h_corrector_t0 + mu_t1_mx_star = mu_t1_mx + epsilon_h * h_corrector_t1 + + regressor_y = _get_regressor(self._regularize, + self._use_forest) + reg_cross = clone(regressor_y) + reg_cross.fit(x[t == 0], (mu_t1_mx_star[t == 0] - + mu_t0_mx_star[t == 0]).squeeze()) + + theta_0 = reg_cross.predict(x) + c_corrector = (1 - t)/(1 - p_x) + reg = LinearRegression(fit_intercept=False).fit( + c_corrector.reshape(-1, 1)[t == 0], (mu_t1_mx_star[t == 0] - y[t == 0]-theta_0[t == 0]).squeeze()) + epsilon_c = reg.coef_ + + theta_0_star = theta_0 + epsilon_c*c_corrector + theta_0_star = np.mean(theta_0_star) + + return theta_0_star + + def _one_step_correction_indirect(self, t, m, x, y): + + n = t.shape[0] + t, m, x, y = self.resize(t, m, x, y) + t0 = np.zeros((n)) + t1 = np.ones((n)) + + # estimate mediator densities + if self._ratio == 'density': + f_m0x, f_m1x = self._estimate_mediator_probability(t, m, x, y) + p_x = self._estimate_treatment_propensity_x(t, m, x) + ratio = f_m0x / (p_x * f_m1x) + + elif self._ratio == 'propensities': + p_x, p_xm = self._estimate_treatment_probabilities(t, m, x) + ratio = (1-p_xm) / ((1 - p_x) * p_xm) + + h_corrector = t / p_x - t * ratio + + x_t_mr = _get_interactions(False, x, t, m) + mu_tmx = self._regressor_y.predict(x_t_mr) + reg = LinearRegression(fit_intercept=False).fit( + h_corrector.reshape(-1, 1), (y-mu_tmx).squeeze()) + epsilon_h = reg.coef_ + # epsilon_h = 0 + print('indirect', epsilon_h) + + # mu_t0_mx = self._regressor_y.predict(_get_interactions(False, x, t0, m)) + # h_corrector_t0 = t0 * f_t0 / (p_x * f_t1) - (1 - t0)/(1 - p_x) + mu_t1_mx = self._regressor_y.predict( + _get_interactions(False, x, t1, m)) + h_corrector_t1 = t1 / p_x - t1 * ratio + # mu_t0_mx_star = mu_t0_mx + epsilon_h * h_corrector_t0 + mu_t1_mx_star = mu_t1_mx + epsilon_h * h_corrector_t1 + + regressor_y = _get_regressor(self._regularize, + self._use_forest) + + # reg_cross.fit(x, (mu_t1_mx_star).squeeze()) + + # omega_t = reg_cross.predict(x) + # c_corrector = (2*t - 1)/p_x[:, None] + # reg = LinearRegression(fit_intercept=False).fit(c_corrector.reshape(-1, 1)[t==0], (mu_t1_mx_star - omega_t).squeeze()) + # epsilon_c = reg.coef_ + + reg_cross = clone(regressor_y) + reg_cross.fit(x[t == 0], mu_t1_mx_star[t == 0]) + omega_t0x = reg_cross.predict(x) + c_corrector_t0 = (2*t0 - 1) / p_x[:, None] + + reg = LinearRegression(fit_intercept=False).fit( + c_corrector_t0[t == 0], (mu_t1_mx_star[t == 0]-omega_t0x[t == 0]).squeeze()) + epsilon_c_t0 = reg.coef_ + # epsilon_c_t0 = 0 + omega_t0x_star = omega_t0x + epsilon_c_t0*c_corrector_t0 + + reg_cross = clone(regressor_y) + reg_cross.fit(x[t == 1], y[t == 1]) + omega_t1x = reg_cross.predict(x) + c_corrector_t1 = (2*t1 - 1) / p_x[:, None] + reg = LinearRegression(fit_intercept=False).fit( + c_corrector_t1[t == 1], (y[t == 1]-omega_t1x[t == 1]).squeeze()) + epsilon_c_t1 = reg.coef_ + # epsilon_c_t1 = 0 + omega_t1x_star = omega_t1x + epsilon_c_t1*c_corrector_t1 + delta_1 = np.mean(omega_t1x_star - omega_t0x_star) + + return delta_1 + + def fit(self, t, m, x, y): + """Fits nuisance parameters to data + + """ + # bucketize if needed + t, m, x, y = self._resize(t, m, x, y) + + # fit nuisance functions + self._fit_nuisance(t, m, x, y) + + self._fit_treatment_propensity_x_nuisance(t, x) + self._fit_conditional_mean_outcome_nuisance(t, m, x, y) + + if self._ratio == 'density': + self._fit_mediator_nuisance(t, m, x) + + elif self._ratio == 'propensities': + self._fit_treatment_propensity_xm_nuisance(t, m, x) + + self._fitted = True + + if self.verbose: + print("Nuisance models fitted") + + return self + + @fitted + def estimate(self, t, m, x, y): + """Estimates causal effect on data + + """ + theta_0 = self._one_step_correction_direct(t, m, x, y) + delta_1 = self._one_step_correction_indirect(t, m, x, y) + total_effect = theta_0 + delta_1 + direct_effect_treated = np.copy(theta_0) + direct_effect_control = theta_0 + indirect_effect_treated = delta_1 + indirect_effect_control = np.copy(delta_1) + + causal_effects = { + 'total_effect': total_effect, + 'direct_effect_treated': direct_effect_treated, + 'direct_effect_control': direct_effect_control, + 'indirect_effect_treated': indirect_effect_treated, + 'indirect_effect_control': indirect_effect_control + } + return causal_effects diff --git a/src/med_bench/estimation/tmle.py b/src/med_bench/estimation/tmle.py deleted file mode 100644 index a8b8028..0000000 --- a/src/med_bench/estimation/tmle.py +++ /dev/null @@ -1,267 +0,0 @@ -import numpy as np -from sklearn.base import clone -from sklearn.linear_model import LinearRegression - -from med_bench.estimation.base import Estimator -from med_bench.nuisances.utils import (_get_regressor) - -ALPHA=10 - -from med_bench.utils.decorators import fitted -from med_bench.utils.utils import _get_interactions -from med_bench.nuisances.density import estimate_mediator_density -from med_bench.nuisances.propensities import estimate_treatment_probabilities, estimate_treatment_propensity_x - -class TMLE(Estimator): - """Implementation of targeted maximum likelihood estimator - - Parameters - ---------- - settings (dict): dictionnary of parameters - lbda (float): regularization parameter - support_vec_tol (float): tolerance for discarding non-supporting vectors - if |alpha_i| < support_vec_tol * lbda then vector is discarded - verbose (int): in {0, 1} - """ - def __init__(self, settings, verbose=0): - super(TMLE, self).__init__(settings=settings, verbose=verbose) - - self._crossfit = 0 - self._procedure = self._settings['procedure'] - self._ratio = self._settings['ratio'] - self._density_estimation = 'kde' - self._clip = self._settings['clip'] - self._normalized = self._settings['normalized'] - - def resize(self, t, m, x, y): - """Resize data for the right shape - - Parameters - ---------- - t array-like, shape (n_samples) - treatment value for each unit, binary - - m array-like, shape (n_samples) - mediator value for each unit, here m is necessary binary and uni- - dimensional - - x array-like, shape (n_samples, n_features_covariates) - covariates (potential confounders) values - - y array-like, shape (n_samples) - outcome value for each unit, continuous - """ - if len(y) != len(y.ravel()): - raise ValueError("Multidimensional y is not supported") - if len(t) != len(t.ravel()): - raise ValueError("Multidimensional t is not supported") - - n = len(y) - if len(x.shape) == 1: - x.reshape(n, 1) - if len(m.shape) == 1: - m.reshape(n, 1) - - if n != len(x) or n != len(m) or n != len(t): - raise ValueError( - "Inputs don't have the same number of observations") - - y = y.ravel() - t = t.ravel() - - return t, m, x, y - - - def one_step_correction_direct(self, t, m, x, y): - - n = t.shape[0] - t, m, x, y = self.resize(t, m, x, y) - t0 = np.zeros((n)) - t1 = np.ones((n)) - - # estimate mediator densities - if self._ratio == 'density': - f_m0x, f_m1x = estimate_mediator_density(t, m, x, y, - self._crossfit, - self._classifier_m, - False) - p_x = estimate_treatment_propensity_x(t, - m, - x, - self._crossfit, - self._classifier_t_x) - ratio = f_m0x / (p_x * f_m1x) - - elif self._ratio == 'propensities': - p_x, p_xm = estimate_treatment_probabilities(t, - m, - x, - self._crossfit, - self._classifier_t_x, - self._classifier_t_xm) - ratio = (1-p_xm) / ((1 - p_x) * p_xm) - - - h_corrector = t * ratio - (1 - t)/(1 - p_x) - - x_t_mr = _get_interactions(False, x, t, m) - mu_tmx = self._regressor_y.predict(x_t_mr) - # import pdb; pdb.set_trace() - reg = LinearRegression(fit_intercept=False).fit(h_corrector.reshape(-1, 1), (y-mu_tmx).squeeze()) - epsilon_h = reg.coef_ - # epsilon_h = 0 - print(epsilon_h) - - mu_t0_mx = self._regressor_y.predict(_get_interactions(False, x, t0, m)) - h_corrector_t0 = t0 * ratio - (1 - t0)/(1 - p_x) - mu_t1_mx = self._regressor_y.predict(_get_interactions(False, x, t1, m)) - h_corrector_t1 = t1 * ratio - (1 - t1)/(1 - p_x) - mu_t0_mx_star = mu_t0_mx + epsilon_h * h_corrector_t0 - mu_t1_mx_star = mu_t1_mx + epsilon_h * h_corrector_t1 - - regressor_y = _get_regressor(self._regularize, - self._use_forest) - reg_cross = clone(regressor_y) - reg_cross.fit(x[t==0], (mu_t1_mx_star[t==0] - mu_t0_mx_star[t==0]).squeeze()) - - theta_0 = reg_cross.predict(x) - c_corrector = (1 - t)/(1 - p_x) - reg = LinearRegression(fit_intercept=False).fit(c_corrector.reshape(-1, 1)[t==0], (mu_t1_mx_star[t==0] - y[t==0]-theta_0[t==0]).squeeze()) - epsilon_c = reg.coef_ - - theta_0_star = theta_0 + epsilon_c*c_corrector - theta_0_star = np.mean(theta_0_star) - - return theta_0_star - - - def one_step_correction_indirect(self, t, m, x, y): - - n = t.shape[0] - t, m, x, y = self.resize(t, m, x, y) - t0 = np.zeros((n)) - t1 = np.ones((n)) - - # estimate mediator densities - if self._ratio == 'density': - f_m0x, f_m1x = estimate_mediator_density(t, m, x, y, - self._crossfit, - self._classifier_m, - False) - p_x = estimate_treatment_propensity_x(t, - m, - x, - self._crossfit, - self._classifier_t_x) - ratio = f_m0x / (p_x * f_m1x) - - elif self._ratio == 'propensities': - p_x, p_xm = estimate_treatment_probabilities(t, - m, - x, - self._crossfit, - self._classifier_t_x, - self._classifier_t_xm) - ratio = (1-p_xm) / ((1 - p_x) * p_xm) - - h_corrector = t / p_x - t * ratio - - x_t_mr = _get_interactions(False, x, t, m) - mu_tmx = self._regressor_y.predict(x_t_mr) - reg = LinearRegression(fit_intercept=False).fit(h_corrector.reshape(-1, 1), (y-mu_tmx).squeeze()) - epsilon_h = reg.coef_ - # epsilon_h = 0 - print('indirect', epsilon_h) - - # mu_t0_mx = self._regressor_y.predict(_get_interactions(False, x, t0, m)) - # h_corrector_t0 = t0 * f_t0 / (p_x * f_t1) - (1 - t0)/(1 - p_x) - mu_t1_mx = self._regressor_y.predict(_get_interactions(False, x, t1, m)) - h_corrector_t1 = t1 / p_x - t1 * ratio - # mu_t0_mx_star = mu_t0_mx + epsilon_h * h_corrector_t0 - mu_t1_mx_star = mu_t1_mx + epsilon_h * h_corrector_t1 - - - regressor_y = _get_regressor(self._regularize, - self._use_forest) - - - - # reg_cross.fit(x, (mu_t1_mx_star).squeeze()) - - # omega_t = reg_cross.predict(x) - # c_corrector = (2*t - 1)/p_x[:, None] - # reg = LinearRegression(fit_intercept=False).fit(c_corrector.reshape(-1, 1)[t==0], (mu_t1_mx_star - omega_t).squeeze()) - # epsilon_c = reg.coef_ - - - - reg_cross = clone(regressor_y) - reg_cross.fit(x[t==0], mu_t1_mx_star[t==0]) - omega_t0x = reg_cross.predict(x) - c_corrector_t0 = (2*t0 - 1) / p_x[:, None] - - reg = LinearRegression(fit_intercept=False).fit(c_corrector_t0[t==0], (mu_t1_mx_star[t==0]-omega_t0x[t==0]).squeeze()) - epsilon_c_t0 = reg.coef_ - # epsilon_c_t0 = 0 - omega_t0x_star = omega_t0x + epsilon_c_t0*c_corrector_t0 - - reg_cross = clone(regressor_y) - reg_cross.fit(x[t==1], y[t==1]) - omega_t1x = reg_cross.predict(x) - c_corrector_t1 = (2*t1 - 1) / p_x[:,None] - reg = LinearRegression(fit_intercept=False).fit(c_corrector_t1[t==1], (y[t==1]-omega_t1x[t==1]).squeeze()) - epsilon_c_t1 = reg.coef_ - # epsilon_c_t1 = 0 - omega_t1x_star = omega_t1x + epsilon_c_t1*c_corrector_t1 - delta_1 = np.mean(omega_t1x_star - omega_t0x_star) - - - return delta_1 - - - def fit(self, t, m, x, y): - """Fits nuisance parameters to data - - """ - # bucketize if needed - t, m, x, y = self.resize(t, m, x, y) - - # fit nuisance functions - self.fit_score_nuisances(t, m, x, y) - - self.fit_treatment_propensity_x_nuisance(t, x) - self.fit_conditional_mean_outcome_nuisance(t, m, x, y) - - if self._ratio == 'density': - self.fit_mediator_nuisance(t, m, x) - - elif self._ratio == 'propensities': - self.fit_treatment_propensity_xm_nuisance(t, m, x) - - self._fitted = True - - if self.verbose: - print("Nuisance models fitted") - - - @fitted - def estimate(self, t, m, x, y): - """Estimates causal effect on data - - """ - theta_0 = self.one_step_correction_direct(t, m, x, y) - delta_1 = self.one_step_correction_indirect(t, m, x, y) - total_effect = theta_0 + delta_1 - direct_effect_treated = np.copy(theta_0) - direct_effect_control = theta_0 - indirect_effect_treated = delta_1 - indirect_effect_control = np.copy(delta_1) - - causal_effects = { - 'total_effect': total_effect, - 'direct_effect_treated': direct_effect_treated, - 'direct_effect_control': direct_effect_control, - 'indirect_effect_treated': indirect_effect_treated, - 'indirect_effect_control': indirect_effect_control - } - return causal_effects From 632a0940a75a555b8992391f296c28a561a6d157 Mon Sep 17 00:00:00 2001 From: brash6 Date: Fri, 25 Oct 2024 18:16:05 +0200 Subject: [PATCH 15/84] minor reformat example file --- src/med_bench/example.py | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/med_bench/example.py b/src/med_bench/example.py index 5a465fb..161061e 100644 --- a/src/med_bench/example.py +++ b/src/med_bench/example.py @@ -3,35 +3,41 @@ from sklearn.linear_model import RidgeCV from sklearn.model_selection import train_test_split -from med_bench.estimation.coefficient_product import CoefficientProduct +from med_bench.estimation.mediation_coefficient_product import CoefficientProduct from med_bench.get_simulated_data import simulate_data from med_bench.nuisances.utils import _get_regularization_parameters from med_bench.utils.constants import CV_FOLDS if __name__ == "__main__": print("get simulated data") - (x, t, m, y, - theta_1_delta_0, theta_1, theta_0, delta_1, delta_0, + (x, t, m, y, + theta_1_delta_0, theta_1, theta_0, delta_1, delta_0, p_t, th_p_t_mx) = simulate_data(n=1000, rg=default_rng(321)) - (x_train, x_test, t_train, t_test, + (x_train, x_test, t_train, t_test, m_train, m_test, y_train, y_test) = train_test_split(x, t, m, y, test_size=0.33, random_state=42) - + cs, alphas = _get_regularization_parameters(regularization=True) - - clf = RandomForestClassifier(random_state=42, n_estimators=100, min_samples_leaf=10) - + + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) - coef_prod_estimator = CoefficientProduct(mediator_type="binary", regressor=reg, classifier=clf, clip=0.01, trim=0.01, regularize=True) + coef_prod_estimator = CoefficientProduct( + mediator_type="binary", regressor=reg, classifier=clf, clip=0.01, trim=0.01, regularize=True) coef_prod_estimator.fit(t_train, m_train, x_train, y_train) - causal_effects = coef_prod_estimator.estimate(t_test, m_test, x_test, y_test) + causal_effects = coef_prod_estimator.estimate( + t_test, m_test, x_test, y_test) - r_risk_score = coef_prod_estimator.score(t_test, m_test, x_test, y_test, causal_effects['total_effect']) + r_risk_score = coef_prod_estimator.score( + t_test, m_test, x_test, y_test, causal_effects['total_effect']) print('R risk score: {}'.format(r_risk_score)) - print('Total effect error: {}'.format(abs(causal_effects['total_effect']-theta_1_delta_0))) - print('Direct effect error: {}'.format(abs(causal_effects['direct_effect_control']-theta_0))) - print('Indirect effect error: {}'.format(abs(causal_effects['indirect_effect_treated']-delta_1))) - + print('Total effect error: {}'.format( + abs(causal_effects['total_effect']-theta_1_delta_0))) + print('Direct effect error: {}'.format( + abs(causal_effects['direct_effect_control']-theta_0))) + print('Indirect effect error: {}'.format( + abs(causal_effects['indirect_effect_treated']-delta_1))) From 8927181a4d64768f3f0919b33359ad68d9ef723a Mon Sep 17 00:00:00 2001 From: brash6 Date: Fri, 25 Oct 2024 18:16:32 +0200 Subject: [PATCH 16/84] get rid of _get_interactions in base and add _input_reshape function --- src/med_bench/estimation/base.py | 93 ++++++++++++++++++++------------ 1 file changed, 60 insertions(+), 33 deletions(-) diff --git a/src/med_bench/estimation/base.py b/src/med_bench/estimation/base.py index 54a99db..ba12ea1 100644 --- a/src/med_bench/estimation/base.py +++ b/src/med_bench/estimation/base.py @@ -7,7 +7,7 @@ from med_bench.utils.decorators import fitted from med_bench.utils.scores import r_risk -from med_bench.utils.utils import _get_interactions, _get_train_test_lists +from med_bench.utils.utils import _get_train_test_lists class Estimator: @@ -131,6 +131,18 @@ def _resize(self, t, m, x, y): return t, m, x, y + def _input_reshape(self, t, m, x): + """Reshape data for the right shape + """ + if len(t.shape) == 1: + t = t.reshape(-1, 1) + if len(m.shape) == 1: + m = m.reshape(-1, 1) + if len(x.shape) == 1: + x = x.reshape(-1, 1) + + return t, m, x + def _fit_nuisance(self, t, m, x, y, *args, **kwargs): """ Fits the score of the nuisance parameters """ @@ -179,6 +191,7 @@ def _fit_treatment_propensity_xm_nuisance(self, t, m, x): return self + # TODO : Enable any sklearn object as classifier or regressor def _fit_mediator_nuisance(self, t, m, x): """ Fits the nuisance parameter for the density f(M=m|T, X) """ @@ -186,7 +199,8 @@ def _fit_mediator_nuisance(self, t, m, x): clf_param_grid = {} classifier_m = GridSearchCV(self.classifier, clf_param_grid) - t_x = _get_interactions(False, t, x) + t_x = np.hstack([var.reshape(-1, 1) if len(var.shape) + == 1 else var for var in [t, x]]) # Fit classifier self._classifier_m = classifier_m.fit(t_x, m.ravel()) @@ -199,8 +213,11 @@ def _fit_conditional_mean_outcome_nuisance(self, t, m, x, y): if len(m.shape) == 1: mr = m.reshape(-1, 1) else: + # TODO : Why are we doing this ? mr = np.copy(m) - x_t_mr = _get_interactions(False, x, t, mr) + + x_t_mr = np.hstack( + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t, mr]]) reg_param_grid = {} @@ -289,9 +306,12 @@ def _fit_cross_conditional_mean_outcome_nuisance_discrete(self, t, m, x, y): t0, m0 = np.zeros((n, 1)), np.zeros((n, 1)) t1, m1 = np.ones((n, 1)), np.ones((n, 1)) - x_t_m = _get_interactions(False, x, t, m) - x_t1_m = _get_interactions(False, x, t1, m) - x_t0_m = _get_interactions(False, x, t0, m) + x_t_m = np.hstack([var.reshape(-1, 1) if len(var.shape) + == 1 else var for var in [x, t, m]]) + x_t1_m = np.hstack( + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t1, m]]) + x_t0_m = np.hstack( + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t0, m]]) test_index = np.arange(n) ind_t0 = t[test_index] == 0 @@ -318,10 +338,15 @@ def _fit_cross_conditional_mean_outcome_nuisance_discrete(self, t, m, x, y): mu_1bx, mu_0bx = [np.zeros(n) for h in range(2)] # predict E[Y|T=t,M=m,X] + x_t1_mb = np.hstack( + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t1, mb]]) + x_t0_mb = np.hstack( + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t0, mb]]) + mu_0bx[test_index] = self.regressors['y_t_mx'].predict( - _get_interactions(False, x, t0, mb)[test_index, :]) + x_t0_mb[test_index, :]) mu_1bx[test_index] = self.regressors['y_t_mx'].predict( - _get_interactions(False, x, t1, mb)[test_index, :]) + x_t1_mb[test_index, :]) # E[E[Y|T=1,M=m,X]|T=t,X] model fitting self.regressors['reg_y_t1m{}_t0'.format(i)] = clone( @@ -372,9 +397,12 @@ def _estimate_mediator_probability(self, t, m, x, y): f_m0x, f_m1x = [np.zeros(n) for h in range(2)] - t_x = _get_interactions(False, t, x) - t0_x = _get_interactions(False, t0, x) - t1_x = _get_interactions(False, t1, x) + t_x = np.hstack([var.reshape(-1, 1) if len(var.shape) + == 1 else var for var in [t, x]]) + t0_x = np.hstack([var.reshape(-1, 1) if len(var.shape) + == 1 else var for var in [t0, x]]) + t1_x = np.hstack([var.reshape(-1, 1) if len(var.shape) + == 1 else var for var in [t1, x]]) for _, test_index in train_test_list: @@ -424,9 +452,12 @@ def _estimate_mediators_probabilities(self, t, m, x, y): f_t1, f_t0 = [], [] - t_x = _get_interactions(False, t, x) - t0_x = _get_interactions(False, t0, x) - t1_x = _get_interactions(False, t1, x) + t_x = np.hstack([var.reshape(-1, 1) if len(var.shape) + == 1 else var for var in [t, x]]) + t0_x = np.hstack([var.reshape(-1, 1) if len(var.shape) + == 1 else var for var in [t0, x]]) + t1_x = np.hstack([var.reshape(-1, 1) if len(var.shape) + == 1 else var for var in [t1, x]]) for _, test_index in train_test_list: @@ -461,12 +492,7 @@ def _estimate_treatment_propensity_x(self, t, m, x): p_x, p_xm = [np.zeros(n) for h in range(2)] # compute propensity scores - if len(x.shape) == 1: - x = x.reshape(-1, 1) - if len(m.shape) == 1: - m = m.reshape(-1, 1) - if len(t.shape) == 1: - t = t.reshape(-1, 1) + t, m, x = self._input_reshape(t, m, x) train_test_list = _get_train_test_lists(self._crossfit, n, x) @@ -494,12 +520,7 @@ def _estimate_treatment_probabilities(self, t, m, x): p_x, p_xm = [np.zeros(n) for h in range(2)] # compute propensity scores - if len(x.shape) == 1: - x = x.reshape(-1, 1) - if len(m.shape) == 1: - m = m.reshape(-1, 1) - if len(t.shape) == 1: - t = t.reshape(-1, 1) + t, m, x = self._input_reshape(t, m, x) train_test_list = _get_train_test_lists(self._crossfit, n, x) @@ -552,9 +573,12 @@ def _estimate_conditional_mean_outcome(self, t, m, x, y): m1 = np.ones((n, 1)) - x_t_mr = _get_interactions(False, x, t, mr) - x_t1_m = _get_interactions(False, x, t1, m) - x_t0_m = _get_interactions(False, x, t0, m) + x_t_mr = np.hstack( + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t, mr]]) + x_t1_m = np.hstack( + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t1, m]]) + x_t0_m = np.hstack( + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t0, m]]) for _, test_index in train_test_list: @@ -568,13 +592,16 @@ def _estimate_conditional_mean_outcome(self, t, m, x, y): mu_1bx, mu_0bx = [np.zeros(n) for h in range(2)] mb = m1 * b + x_t1_mb = np.hstack( + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t1, mb]]) + x_t0_mb = np.hstack( + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t0, mb]]) + # predict E[Y|T=t,M=m,X] mu_0bx[test_index] = self._regressor_y.predict( - _get_interactions(False, x, t0, mb)[test_index, - :]).squeeze() + x_t0_mb[test_index, :]).squeeze() mu_1bx[test_index] = self._regressor_y.predict( - _get_interactions(False, x, t1, mb)[test_index, - :]).squeeze() + x_t1_mb[test_index, :]).squeeze() mu_t0.append(mu_0bx) mu_t1.append(mu_1bx) From 9ad7c0af3e3798f272152aad6e6f9dfc1a9c4702 Mon Sep 17 00:00:00 2001 From: brash6 Date: Fri, 25 Oct 2024 18:17:15 +0200 Subject: [PATCH 17/84] application of modifications --- .../mediation_coefficient_product.py | 7 +- src/med_bench/estimation/mediation_dml.py | 4 +- .../estimation/mediation_g_computation.py | 1 - src/med_bench/estimation/mediation_mr.py | 8 +-- src/med_bench/estimation/mediation_tmle.py | 25 ++++--- src/med_bench/utils/utils.py | 67 +++---------------- 6 files changed, 27 insertions(+), 85 deletions(-) diff --git a/src/med_bench/estimation/mediation_coefficient_product.py b/src/med_bench/estimation/mediation_coefficient_product.py index b9449b0..9564f49 100644 --- a/src/med_bench/estimation/mediation_coefficient_product.py +++ b/src/med_bench/estimation/mediation_coefficient_product.py @@ -45,12 +45,7 @@ def fit(self, t, m, x, y): alphas = ALPHAS else: alphas = [TINY] - if len(x.shape) == 1: - x = x.reshape(-1, 1) - if len(m.shape) == 1: - m = m.reshape(-1, 1) - if len(t.shape) == 1: - t = t.reshape(-1, 1) + t, m, x = self._input_reshape(t, m, x) self._coef_t_m = np.zeros(m.shape[1]) for i in range(m.shape[1]): diff --git a/src/med_bench/estimation/mediation_dml.py b/src/med_bench/estimation/mediation_dml.py index 44438e4..958c18d 100644 --- a/src/med_bench/estimation/mediation_dml.py +++ b/src/med_bench/estimation/mediation_dml.py @@ -43,9 +43,7 @@ def estimate(self, t, m, x, y): """ t, m, x, y = self._resize(t, m, x, y) - p_x, p_xm = self._estimate_treatment_probabilities(t, - m, - x) + p_x, p_xm = self._estimate_treatment_probabilities(t, m, x) mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 = self._estimate_cross_conditional_mean_outcome_nesting( m, x, y) diff --git a/src/med_bench/estimation/mediation_g_computation.py b/src/med_bench/estimation/mediation_g_computation.py index 1e2bf3c..e89dab4 100644 --- a/src/med_bench/estimation/mediation_g_computation.py +++ b/src/med_bench/estimation/mediation_g_computation.py @@ -1,5 +1,4 @@ import numpy as np -from sklearn.cluster import KMeans from med_bench.estimation.base import Estimator from med_bench.utils.decorators import fitted diff --git a/src/med_bench/estimation/mediation_mr.py b/src/med_bench/estimation/mediation_mr.py index a7d993c..76c194a 100644 --- a/src/med_bench/estimation/mediation_mr.py +++ b/src/med_bench/estimation/mediation_mr.py @@ -1,12 +1,7 @@ import numpy as np -from sklearn.cluster import KMeans from med_bench.estimation.base import Estimator from med_bench.utils.decorators import fitted -from med_bench.utils.utils import (is_array_integer) -from med_bench.nuisances.cross_conditional_outcome import estimate_cross_conditional_mean_outcome_discrete, estimate_cross_conditional_mean_outcome_nesting -from med_bench.nuisances.propensities import estimate_treatment_propensity_x, estimate_treatment_probabilities -from med_bench.nuisances.density import estimate_mediator_density, estimate_mediators_probabilities class MultiplyRobust(Estimator): @@ -20,13 +15,12 @@ class MultiplyRobust(Estimator): verbose (int): in {0, 1} """ - def __init__(self, procedure: str, ratio: str, density_estimation_method: str, clip: float, normalized, **kwargs): + def __init__(self, procedure: str, ratio: str, clip: float, normalized, **kwargs): super().__init__(**kwargs) self._crossfit = 0 self._procedure = procedure self._ratio = ratio - self._density_estimation = density_estimation_method self._clip = clip self._normalized = normalized diff --git a/src/med_bench/estimation/mediation_tmle.py b/src/med_bench/estimation/mediation_tmle.py index 31ce0e7..0b90a96 100644 --- a/src/med_bench/estimation/mediation_tmle.py +++ b/src/med_bench/estimation/mediation_tmle.py @@ -4,7 +4,6 @@ from med_bench.estimation.base import Estimator from med_bench.nuisances.utils import _get_regressor -from med_bench.utils.utils import _get_interactions from med_bench.utils.decorators import fitted ALPHA = 10 @@ -50,7 +49,8 @@ def _one_step_correction_direct(self, t, m, x, y): h_corrector = t * ratio - (1 - t)/(1 - p_x) - x_t_mr = _get_interactions(False, x, t, m) + x_t_mr = np.hstack( + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t, m]]) mu_tmx = self._regressor_y.predict(x_t_mr) # import pdb; pdb.set_trace() reg = LinearRegression(fit_intercept=False).fit( @@ -59,11 +59,14 @@ def _one_step_correction_direct(self, t, m, x, y): # epsilon_h = 0 print(epsilon_h) - mu_t0_mx = self._regressor_y.predict( - _get_interactions(False, x, t0, m)) + x_t0_m = np.hstack( + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t0, m]]) + x_t1_m = np.hstack( + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t1, m]]) + + mu_t0_mx = self._regressor_y.predict(x_t0_m) h_corrector_t0 = t0 * ratio - (1 - t0)/(1 - p_x) - mu_t1_mx = self._regressor_y.predict( - _get_interactions(False, x, t1, m)) + mu_t1_mx = self._regressor_y.predict(x_t1_m) h_corrector_t1 = t1 * ratio - (1 - t1)/(1 - p_x) mu_t0_mx_star = mu_t0_mx + epsilon_h * h_corrector_t0 mu_t1_mx_star = mu_t1_mx + epsilon_h * h_corrector_t1 @@ -104,7 +107,8 @@ def _one_step_correction_indirect(self, t, m, x, y): h_corrector = t / p_x - t * ratio - x_t_mr = _get_interactions(False, x, t, m) + x_t_mr = np.hstack( + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t, m]]) mu_tmx = self._regressor_y.predict(x_t_mr) reg = LinearRegression(fit_intercept=False).fit( h_corrector.reshape(-1, 1), (y-mu_tmx).squeeze()) @@ -114,8 +118,11 @@ def _one_step_correction_indirect(self, t, m, x, y): # mu_t0_mx = self._regressor_y.predict(_get_interactions(False, x, t0, m)) # h_corrector_t0 = t0 * f_t0 / (p_x * f_t1) - (1 - t0)/(1 - p_x) - mu_t1_mx = self._regressor_y.predict( - _get_interactions(False, x, t1, m)) + + x_t1_m = np.hstack( + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t1, m]]) + + mu_t1_mx = self._regressor_y.predict(x_t1_m) h_corrector_t1 = t1 / p_x - t1 * ratio # mu_t0_mx_star = mu_t0_mx + epsilon_h * h_corrector_t0 mu_t1_mx_star = mu_t1_mx + epsilon_h * h_corrector_t1 diff --git a/src/med_bench/utils/utils.py b/src/med_bench/utils/utils.py index 8f4223f..86bb8b8 100644 --- a/src/med_bench/utils/utils.py +++ b/src/med_bench/utils/utils.py @@ -230,7 +230,7 @@ def _check_input(y, t, m, x, setting): else: m_converted = m - if (m_converted.shape[1] >1) and (setting != 'multidimensional'): + if (m_converted.shape[1] > 1) and (setting != 'multidimensional'): raise ValueError("Multidimensional m (mediator) is not supported") if (setting == 'binary') and (len(np.unique(m)) != 2): @@ -241,7 +241,7 @@ def _check_input(y, t, m, x, setting): def is_array_integer(array): - if array.shape[1]>1: + if array.shape[1] > 1: return False return all(list((array == array.astype(int)).squeeze())) @@ -250,15 +250,16 @@ def str_to_bool(string): if bool(string) == string: return string elif string == 'True': - return True + return True elif string == 'False': - return False + return False else: - raise ValueError # evil ValueError that doesn't tell you what the wrong value was + raise ValueError # evil ValueError that doesn't tell you what the wrong value was def bucketize_mediators(m, n_buckets=10, random_state=42): - kmeans = KMeans(n_clusters=n_buckets, random_state=random_state, n_init="auto").fit(m) + kmeans = KMeans(n_clusters=n_buckets, + random_state=random_state, n_init="auto").fit(m) return kmeans.predict(m) @@ -275,6 +276,7 @@ def train_test_split_data(causal_data, test_size=0.33, random_state=42): causal_data_test = x_test, t_test, m_test, y_test return causal_data_train, causal_data_test + def _get_train_test_lists(crossfit, n, x): """ Obtain train and test folds @@ -292,56 +294,3 @@ def _get_train_test_lists(crossfit, n, x): for train_index, test_index in kf.split(x): train_test_list.append([train_index, test_index]) return train_test_list - -def _get_interactions(interaction, *args): - """ - this function provides interaction terms between different groups of - variables (confounders, treatment, mediators) - - Parameters - ---------- - interaction : boolean - whether to compute interaction terms - - *args : flexible, one or several arrays - blocks of variables between which interactions should be - computed - - - Returns - -------- - array_like - interaction terms - - Examples - -------- - >>> x = np.arange(6).reshape(3, 2) - >>> t = np.ones((3, 1)) - >>> m = 2 * np.ones((3, 1)) - >>> get_interactions(False, x, t, m) - array([[0., 1., 1., 2.], - [2., 3., 1., 2.], - [4., 5., 1., 2.]]) - >>> get_interactions(True, x, t, m) - array([[ 0., 1., 1., 2., 0., 1., 0., 2., 2.], - [ 2., 3., 1., 2., 2., 3., 4., 6., 2.], - [ 4., 5., 1., 2., 4., 5., 8., 10., 2.]]) - """ - variables = list(args) - for index, var in enumerate(variables): - if len(var.shape) == 1: - variables[index] = var.reshape(-1,1) - pre_inter_variables = np.hstack(variables) - if not interaction: - return pre_inter_variables - new_cols = list() - for i, var in enumerate(variables[:]): - for j, var2 in enumerate(variables[i+1:]): - for ii in range(var.shape[1]): - for jj in range(var2.shape[1]): - new_cols.append((var[:, ii] * var2[:, jj]).reshape(-1, 1)) - new_vars = np.hstack(new_cols) - result = np.hstack((pre_inter_variables, new_vars)) - return result - - From 48fb5ed0fa2807cf42e181e5095b1645d178563a Mon Sep 17 00:00:00 2001 From: brash6 Date: Tue, 29 Oct 2024 17:57:23 +0100 Subject: [PATCH 18/84] remove cross fitting --- src/med_bench/estimation/base.py | 235 +++++++++---------------------- 1 file changed, 70 insertions(+), 165 deletions(-) diff --git a/src/med_bench/estimation/base.py b/src/med_bench/estimation/base.py index ba12ea1..c954fe3 100644 --- a/src/med_bench/estimation/base.py +++ b/src/med_bench/estimation/base.py @@ -15,38 +15,55 @@ class Estimator: """ __metaclass__ = ABCMeta - def __init__(self, mediator_type: str, regressor: RegressorMixin, classifier: ClassifierMixin, - verbose: bool = True): + def __init__(self, regressor, classifier, verbose: bool = True, crossfit: int = 0): """Initialize Estimator base class Parameters ---------- - mediator_type : str - mediator type (binary or continuous, continuous only can be multidimensional) - regressor : RegressorMixin - Scikit-Learn Regressor used for mu estimation - classifier : ClassifierMixin - Scikit-Learn Classifier used for propensity estimation + regressor + Regressor used for mu estimation, can be any object with a fit and predict method + classifier + Classifier used for propensity estimation, can be any object with a fit and predict_proba method verbose : bool will print some logs if True + crossfit : int + number of crossfit folds, if 0 no crossfit is performed """ - self.rng = np.random.RandomState(123) - - assert mediator_type in [ - 'binary', 'continuous'], "mediator_type must be 'binary' or 'continuous'" - self.mediator_type = mediator_type - + assert hasattr( + regressor, 'fit'), "The model does not have a 'fit' method." + assert hasattr( + regressor, 'predict'), "The model does not have a 'predict' method." + assert hasattr( + classifier, 'fit'), "The model does not have a 'fit' method." + assert hasattr( + classifier, 'predict_proba'), "The model does not have a 'predict_proba' method." self.regressor = regressor - self.classifier = classifier + self._crossfit = crossfit + self._crossfit_check() + self._verbose = verbose + self._fitted = False @property def verbose(self): return self._verbose + def _crossfit_check(self): + """Checks if the estimator inputs are valid + """ + if self._crossfit > 0: + raise NotImplementedError("""Crossfit is not implemented yet + You should perform something like this on your side : + cf_iterator = KFold(k=5) + for data_train, data_test in cf_iterator: + result.append(DML(...., cross_fitting=False) + .fit(train_data.X, train_data.t, train_data.m, train_data.y)\ + .estimate(test_data.X, test_data.t, test_data.m, test_data.y)) + np.mean(result)""") + @abstractmethod def fit(self, t, m, x, y): """Fits nuisance parameters to data @@ -199,8 +216,7 @@ def _fit_mediator_nuisance(self, t, m, x): clf_param_grid = {} classifier_m = GridSearchCV(self.classifier, clf_param_grid) - t_x = np.hstack([var.reshape(-1, 1) if len(var.shape) - == 1 else var for var in [t, x]]) + t_x = np.hstack([t.reshape(-1, 1), x]) # Fit classifier self._classifier_m = classifier_m.fit(t_x, m.ravel()) @@ -210,21 +226,14 @@ def _fit_mediator_nuisance(self, t, m, x): def _fit_conditional_mean_outcome_nuisance(self, t, m, x, y): """ Fits the nuisance for the conditional mean outcome for the density f(M=m|T, X) """ - if len(m.shape) == 1: - mr = m.reshape(-1, 1) - else: - # TODO : Why are we doing this ? - mr = np.copy(m) - - x_t_mr = np.hstack( - [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t, mr]]) + x_t_m = np.hstack([x, t.reshape(-1, 1), m]) reg_param_grid = {} # estimate conditional mean outcomes regressor_y = GridSearchCV(self.regressor, reg_param_grid) - self._regressor_y = regressor_y.fit(x_t_mr, y) + self._regressor_y = regressor_y.fit(x_t_m, y) return self @@ -306,12 +315,9 @@ def _fit_cross_conditional_mean_outcome_nuisance_discrete(self, t, m, x, y): t0, m0 = np.zeros((n, 1)), np.zeros((n, 1)) t1, m1 = np.ones((n, 1)), np.ones((n, 1)) - x_t_m = np.hstack([var.reshape(-1, 1) if len(var.shape) - == 1 else var for var in [x, t, m]]) - x_t1_m = np.hstack( - [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t1, m]]) - x_t0_m = np.hstack( - [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t0, m]]) + x_t_m = np.hstack([x, t.reshape(-1, 1), m]) + x_t1_m = np.hstack([x, t1.reshape(-1, 1), m]) + x_t0_m = np.hstack([x, t0.reshape(-1, 1), m]) test_index = np.arange(n) ind_t0 = t[test_index] == 0 @@ -338,10 +344,9 @@ def _fit_cross_conditional_mean_outcome_nuisance_discrete(self, t, m, x, y): mu_1bx, mu_0bx = [np.zeros(n) for h in range(2)] # predict E[Y|T=t,M=m,X] - x_t1_mb = np.hstack( - [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t1, mb]]) - x_t0_mb = np.hstack( - [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t0, mb]]) + + x_t1_mb = np.hstack([x, t1.reshape(-1, 1), mb]) + x_t0_mb = np.hstack([x, t0.reshape(-1, 1), mb]) mu_0bx[test_index] = self.regressors['y_t_mx'].predict( x_t0_mb[test_index, :]) @@ -382,47 +387,19 @@ def _estimate_mediator_probability(self, t, m, x, y): probabilities f(M|T=1,X) """ n = len(y) - if len(x.shape) == 1: - x = x.reshape(-1, 1) - - if len(t.shape) == 1: - t = t.reshape(-1, 1) t0 = np.zeros((n, 1)) t1 = np.ones((n, 1)) m = m.ravel() - train_test_list = _get_train_test_lists(self._crossfit, n, x) - - f_m0x, f_m1x = [np.zeros(n) for h in range(2)] - - t_x = np.hstack([var.reshape(-1, 1) if len(var.shape) - == 1 else var for var in [t, x]]) - t0_x = np.hstack([var.reshape(-1, 1) if len(var.shape) - == 1 else var for var in [t0, x]]) - t1_x = np.hstack([var.reshape(-1, 1) if len(var.shape) - == 1 else var for var in [t1, x]]) - - for _, test_index in train_test_list: - - test_ind = np.arange(len(test_index)) - - fm_0 = self._classifier_m.predict_proba(t0_x[test_index, :]) - fm_1 = self._classifier_m.predict_proba(t1_x[test_index, :]) - - # predict f(M|T=t,X) - f_m0x[test_index] = fm_0[test_ind, m[test_index]] - f_m1x[test_index] = fm_1[test_ind, m[test_index]] + t0_x = np.hstack([t0.reshape(-1, 1), x]) + t1_x = np.hstack([t1.reshape(-1, 1), x]) - for i, b in enumerate(np.unique(m)): - f_0bx, f_1bx = [np.zeros(n) for h in range(2)] + fm_0 = self._classifier_m.predict_proba(t0_x) + fm_1 = self._classifier_m.predict_proba(t1_x) - # predict f(M=m|T=t,X) - f_0bx[test_index] = fm_0[:, i] - f_1bx[test_index] = fm_1[:, i] - - return f_m0x, f_m1x + return fm_0, fm_1 def _estimate_mediators_probabilities(self, t, m, x, y): """ @@ -437,70 +414,36 @@ def _estimate_mediators_probabilities(self, t, m, x, y): contains array-like, shape (n_samples) probabilities f(M=m|T=1,X) """ n = len(y) - if len(x.shape) == 1: - x = x.reshape(-1, 1) - - if len(t.shape) == 1: - t = t.reshape(-1, 1) t0 = np.zeros((n, 1)) t1 = np.ones((n, 1)) m = m.ravel() - train_test_list = _get_train_test_lists(self._crossfit, n, x) - - f_t1, f_t0 = [], [] + t0_x = np.hstack([t0.reshape(-1, 1), x]) + t1_x = np.hstack([t1.reshape(-1, 1), x]) - t_x = np.hstack([var.reshape(-1, 1) if len(var.shape) - == 1 else var for var in [t, x]]) - t0_x = np.hstack([var.reshape(-1, 1) if len(var.shape) - == 1 else var for var in [t0, x]]) - t1_x = np.hstack([var.reshape(-1, 1) if len(var.shape) - == 1 else var for var in [t1, x]]) - - for _, test_index in train_test_list: - - fm_0 = self._classifier_m.predict_proba(t0_x[test_index, :]) - fm_1 = self._classifier_m.predict_proba(t1_x[test_index, :]) - - for i, b in enumerate(np.unique(m)): - f_0bx, f_1bx = [np.zeros(n) for h in range(2)] - - # predict f(M=m|T=t,X) - f_0bx[test_index] = fm_0[:, i] - f_1bx[test_index] = fm_1[:, i] - - f_t0.append(f_0bx) - f_t1.append(f_1bx) + f_t0 = self._classifier_m.predict_proba(t0_x) + f_t1 = self._classifier_m.predict_proba(t1_x) return f_t0, f_t1 def _estimate_treatment_propensity_x(self, t, m, x): """ - Estimate treatment probabilities P(T=1|X) with train - test lists from crossfitting + Estimate treatment propensity P(T=1|X) Returns ------- p_x : array-like, shape (n_samples) probabilities P(T=1|X) - p_xm : array-like, shape (n_samples) - probabilities P(T=1|X, M) """ n = len(t) - p_x, p_xm = [np.zeros(n) for h in range(2)] # compute propensity scores t, m, x = self._input_reshape(t, m, x) - train_test_list = _get_train_test_lists(self._crossfit, n, x) - - for _, test_index in train_test_list: - - # predict P(T=1|X), P(T=1|X, M) - p_x[test_index] = self._classifier_t_x.predict_proba(x[test_index, :])[ - :, 1] + # predict P(T=1|X), P(T=1|X, M) + p_x = self._classifier_t_x.predict_proba(x) return p_x @@ -516,23 +459,14 @@ def _estimate_treatment_probabilities(self, t, m, x): p_xm : array-like, shape (n_samples) probabilities P(T=1|X, M) """ - n = len(t) - - p_x, p_xm = [np.zeros(n) for h in range(2)] # compute propensity scores t, m, x = self._input_reshape(t, m, x) - train_test_list = _get_train_test_lists(self._crossfit, n, x) - xm = np.hstack((x, m)) - for _, test_index in train_test_list: - - # predict P(T=1|X), P(T=1|X, M) - p_x[test_index] = self._classifier_t_x.predict_proba(x[test_index, :])[ - :, 1] - p_xm[test_index] = self._classifier_t_xm.predict_proba(xm[test_index, :])[ - :, 1] + # predict P(T=1|X), P(T=1|X, M) + p_x = self._classifier_t_x.predict_proba(x) + p_xm = self._classifier_t_xm.predict_proba(xm) return p_x, p_xm @@ -553,58 +487,31 @@ def _estimate_conditional_mean_outcome(self, t, m, x, y): conditional mean outcome estimates E[Y|T=1,M,X] """ n = len(y) - if len(x.shape) == 1: - x = x.reshape(-1, 1) - if len(m.shape) == 1: - mr = m.reshape(-1, 1) - else: - mr = np.copy(m) - if len(t.shape) == 1: - t = t.reshape(-1, 1) t0 = np.zeros((n, 1)) t1 = np.ones((n, 1)) m1 = np.ones((n, 1)) - train_test_list = _get_train_test_lists(self._crossfit, n, x) - - mu_1mx, mu_0mx = [np.zeros(n) for _ in range(2)] mu_t1, mu_t0 = [], [] m1 = np.ones((n, 1)) - x_t_mr = np.hstack( - [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t, mr]]) - x_t1_m = np.hstack( - [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t1, m]]) - x_t0_m = np.hstack( - [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t0, m]]) - - for _, test_index in train_test_list: + x_t1_m = np.hstack([x, t1.reshape(-1, 1), m]) + x_t0_m = np.hstack([x, t0.reshape(-1, 1), m]) - # predict E[Y|T=t,M,X] - mu_0mx[test_index] = self._regressor_y.predict( - x_t0_m[test_index, :]).squeeze() - mu_1mx[test_index] = self._regressor_y.predict( - x_t1_m[test_index, :]).squeeze() + # predict E[Y|T=t,M,X] for all indices + mu_0mx = self._regressor_y.predict(x_t0_m).squeeze() + mu_1mx = self._regressor_y.predict(x_t1_m).squeeze() - for i, b in enumerate(np.unique(m)): - mu_1bx, mu_0bx = [np.zeros(n) for h in range(2)] - mb = m1 * b - - x_t1_mb = np.hstack( - [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t1, mb]]) - x_t0_mb = np.hstack( - [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t0, mb]]) - - # predict E[Y|T=t,M=m,X] - mu_0bx[test_index] = self._regressor_y.predict( - x_t0_mb[test_index, :]).squeeze() - mu_1bx[test_index] = self._regressor_y.predict( - x_t1_mb[test_index, :]).squeeze() - - mu_t0.append(mu_0bx) - mu_t1.append(mu_1bx) + for i, b in enumerate(np.unique(m)): + mb = m1 * b + x_t1_mb = np.hstack([x, t1.reshape(-1, 1), mb]) + x_t0_mb = np.hstack([x, t0.reshape(-1, 1), mb]) + # predict E[Y|T=t,M=m,X] for all indices + mu_0bx = self._regressor_y.predict(x_t0_mb).squeeze() + mu_1bx = self._regressor_y.predict(x_t1_mb).squeeze() + mu_t0.append(mu_0bx) + mu_t1.append(mu_1bx) return mu_t0, mu_t1, mu_0mx, mu_1mx @@ -628,8 +535,6 @@ def _estimate_cross_conditional_mean_outcome_nesting(self, m, x, y): mu_1x, array-like, shape (n_samples) cross conditional mean outcome estimates E[E[Y|T=1,M,X]|T=1,X] """ - n = len(y) - xm = np.hstack((x, m)) # predict E[Y|T=1,M,X] From d35f7d223273b7843d0b63b1db2dabf8649c42a7 Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 30 Oct 2024 18:31:47 +0100 Subject: [PATCH 19/84] minor changes in coefficient product --- src/med_bench/estimation/mediation_coefficient_product.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/med_bench/estimation/mediation_coefficient_product.py b/src/med_bench/estimation/mediation_coefficient_product.py index 9564f49..0184e5b 100644 --- a/src/med_bench/estimation/mediation_coefficient_product.py +++ b/src/med_bench/estimation/mediation_coefficient_product.py @@ -16,7 +16,6 @@ def __init__(self, regularize: bool, **kwargs): """ super().__init__(**kwargs) - self._crossfit = 0 self._regularize = regularize def fit(self, t, m, x, y): @@ -45,7 +44,7 @@ def fit(self, t, m, x, y): alphas = ALPHAS else: alphas = [TINY] - t, m, x = self._input_reshape(t, m, x) + t, m, x, y = self._resize(t, m, x, y) self._coef_t_m = np.zeros(m.shape[1]) for i in range(m.shape[1]): From ab8207a18bd9b1f44929441a6f78611fcf782720 Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 30 Oct 2024 18:32:38 +0100 Subject: [PATCH 20/84] remove discrete procedure in g computation --- .../estimation/mediation_g_computation.py | 79 ++----------------- 1 file changed, 6 insertions(+), 73 deletions(-) diff --git a/src/med_bench/estimation/mediation_g_computation.py b/src/med_bench/estimation/mediation_g_computation.py index e89dab4..d17e969 100644 --- a/src/med_bench/estimation/mediation_g_computation.py +++ b/src/med_bench/estimation/mediation_g_computation.py @@ -9,21 +9,11 @@ class GComputation(Estimator): """GComputation estimation method class """ - def __init__(self, crossfit: int, procedure: str, **kwargs): + def __init__(self, **kwargs): """Initalization of the GComputation estimation method class - - Parameters - ---------- - crossfit : int - Any integer value greater than 0. - procedure : str - nesting or discrete """ super().__init__(**kwargs) - self._crossfit = crossfit - self._procedure = procedure - def fit(self, t, m, x, y): """Fits nuisance parameters to data @@ -32,10 +22,7 @@ def fit(self, t, m, x, y): self._fit_nuisance(t, m, x, y) t, m, x, y = self._resize(t, m, x, y) - if self._procedure == 'nesting': - self._fit_cross_conditional_mean_outcome_nuisance(t, m, x, y) - else: - raise NotImplementedError + self._fit_cross_conditional_mean_outcome_nuisance(t, m, x, y) self._fitted = True if self.verbose: @@ -43,51 +30,13 @@ def fit(self, t, m, x, y): return self - def _estimate_discrete(self, t, m, x, y): - """Estimates causal effect on data using a discrete summation on - mediators + @fitted + def estimate(self, t, m, x, y): + """Estimates causal effect on data """ - # estimate mediator densities - f_t0, f_t1 = self._estimate_mediators_probabilities(t, m, x, y) - - # estimate conditional mean outcomes - mu_t0, mu_t1, _, _ = ( - self._estimate_conditional_mean_outcome(t, m, x, y)) - - n = len(y) - - direct_effect_treated = 0 - direct_effect_control = 0 - indirect_effect_treated = 0 - indirect_effect_control = 0 - - for f_1bx, f_0bx, mu_1bx, mu_0bx in zip(f_t1, f_t0, mu_t1, mu_t0): - direct_effect_ib = mu_1bx - mu_0bx - direct_effect_treated += direct_effect_ib * f_1bx - direct_effect_control += direct_effect_ib * f_0bx - indirect_effect_ib = f_1bx - f_0bx - indirect_effect_treated += indirect_effect_ib * mu_1bx - indirect_effect_control += indirect_effect_ib * mu_0bx - - direct_effect_treated = direct_effect_treated.sum() / n - direct_effect_control = direct_effect_control.sum() / n - indirect_effect_treated = indirect_effect_treated.sum() / n - indirect_effect_control = indirect_effect_control.sum() / n - - total_effect = direct_effect_control + indirect_effect_treated - - causal_effects = { - 'total_effect': total_effect, - 'direct_effect_treated': direct_effect_treated, - 'direct_effect_control': direct_effect_control, - 'indirect_effect_treated': indirect_effect_treated, - 'indirect_effect_control': indirect_effect_control - } - return causal_effects - - def _estimate_nesting(self, t, m, x, y): + t, m, x, y = self._resize(t, m, x, y) mu_0mx, mu_1mx, y0m0, y0m1, y1m0, y1m1 = self._estimate_cross_conditional_mean_outcome_nesting( m, x, y) @@ -115,19 +64,3 @@ def _estimate_nesting(self, t, m, x, y): } return causal_effects - - @fitted - def estimate(self, t, m, x, y): - """Estimates causal effect on data - - """ - - t, m, x, y = self._resize(t, m, x, y) - - if self._procedure == 'discrete': - if not is_array_integer(m): - m = self._bucketizer.predict(m) - return self._estimate_discrete(t, m, x, y) - - elif self._procedure == 'nesting': - return self._estimate_nesting(t, m, x, y) From f2ed579ea9a82399b586c07cb1b69e3d0069f285 Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 30 Oct 2024 18:33:12 +0100 Subject: [PATCH 21/84] minor changes in ipw --- src/med_bench/estimation/mediation_dml.py | 4 +- src/med_bench/estimation/mediation_ipw.py | 3 +- src/med_bench/estimation/mediation_mr.py | 92 +++-------------- src/med_bench/example.py | 115 ++++++++++++++++++---- src/med_bench/utils/loader.py | 17 ++-- 5 files changed, 123 insertions(+), 108 deletions(-) diff --git a/src/med_bench/estimation/mediation_dml.py b/src/med_bench/estimation/mediation_dml.py index 958c18d..9a2396b 100644 --- a/src/med_bench/estimation/mediation_dml.py +++ b/src/med_bench/estimation/mediation_dml.py @@ -13,11 +13,9 @@ class DoubleMachineLearning(Estimator): if |alpha_i| < support_vec_tol * alpha then vector is discarded """ - def __init__(self, procedure: str, clip: float, trim: float, normalized: bool, **kwargs): + def __init__(self, clip: float, trim: float, normalized: bool, **kwargs): super().__init__(**kwargs) - self._crossfit = 0 - self._procedure = procedure self._clip = clip self._trim = trim self._normalized = normalized diff --git a/src/med_bench/estimation/mediation_ipw.py b/src/med_bench/estimation/mediation_ipw.py index 7d657e9..0fb2180 100644 --- a/src/med_bench/estimation/mediation_ipw.py +++ b/src/med_bench/estimation/mediation_ipw.py @@ -15,7 +15,6 @@ def __init__(self, clip: float, trim: float, **kwargs): """ super().__init__(**kwargs) - self._crossfit = 0 self._clip = clip self._trim = trim @@ -41,7 +40,7 @@ def estimate(self, t, m, x, y): """Estimates causal effect on data """ - t, m, x, y = self.resize(t, m, x, y) + t, m, x, y = self._resize(t, m, x, y) p_x, p_xm = self._estimate_treatment_probabilities(t, m, x) ind = ((p_xm > self._trim) & (p_xm < (1 - self._trim))) diff --git a/src/med_bench/estimation/mediation_mr.py b/src/med_bench/estimation/mediation_mr.py index 76c194a..5811aa2 100644 --- a/src/med_bench/estimation/mediation_mr.py +++ b/src/med_bench/estimation/mediation_mr.py @@ -2,39 +2,30 @@ from med_bench.estimation.base import Estimator from med_bench.utils.decorators import fitted +from med_bench.utils.utils import is_array_integer class MultiplyRobust(Estimator): - """Implementation of multiply robust - - Args: - settings (dict): dictionnary of parameters - lbda (float): regularization parameter - support_vec_tol (float): tolerance for discarding non-supporting vectors - if |alpha_i| < support_vec_tol * lbda then vector is discarded - verbose (int): in {0, 1} + """Implementation of multiply robust estimator """ - def __init__(self, procedure: str, ratio: str, clip: float, normalized, **kwargs): + def __init__(self, ratio: str, clip: float, normalized, **kwargs): super().__init__(**kwargs) - self._crossfit = 0 - self._procedure = procedure + assert ratio in ['density', 'propensities'] self._ratio = ratio self._clip = clip self._normalized = normalized def fit(self, t, m, x, y): """Fits nuisance parameters to data - """ - # bucketize if needed t, m, x, y = self._resize(t, m, x, y) # fit nuisance functions self._fit_nuisance(t, m, x, y) - if self._ratio == 'density': + if self._ratio == 'density' and is_array_integer(m): self._fit_treatment_propensity_x_nuisance(t, x) self._fit_mediator_nuisance(t, m, x) @@ -42,14 +33,11 @@ def fit(self, t, m, x, y): self._fit_treatment_propensity_x_nuisance(t, x) self._fit_treatment_propensity_xm_nuisance(t, m, x) - else: - raise NotImplementedError + elif self._ratio == 'density' and not is_array_integer(m): + raise NotImplementedError("""Continuous mediator cannot use the density ratio method, + use a discrete mediator or set the ratio to 'propensities'""") - if self._procedure == 'nesting': - self._fit_cross_conditional_mean_outcome_nuisance(t, m, x, y) - - else: - raise NotImplementedError + self._fit_cross_conditional_mean_outcome_nuisance(t, m, x, y) self._fitted = True @@ -68,7 +56,6 @@ def estimate(self, t, m, x, y): if self._ratio == 'density': f_m0x, f_m1x = self._estimate_mediator_probability(t, m, x, y) - p_x = self._estimate_treatment_propensity_x(t, m, x) ratio_t1_m0 = f_m0x / (p_x * f_m1x) ratio_t0_m1 = f_m1x / ((1 - p_x) * f_m0x) @@ -78,57 +65,20 @@ def estimate(self, t, m, x, y): ratio_t1_m0 = (1-p_xm) / ((1 - p_x) * p_xm) ratio_t0_m1 = p_xm / ((1 - p_xm) * p_x) - if self._procedure == 'nesting': - - # p_x = estimate_treatment_propensity_x(t, - # m, - # x, - # self._crossfit, - # self._classifier_t_x) - - # _, _, f_m0x, f_m1x = estimate_mediator_density(t, - # m, - # x, - # y, - # self._crossfit, - # self._classifier_m, - # False) - - mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 = ( - self._estimate_cross_conditional_mean_outcome_nesting(m, x, y)) - - # clipping - # p_x_clip = p_x != np.clip(p_x, self._clip, 1 - self._clip) - # f_m0x_clip = f_m0x != np.clip(f_m0x, self._clip, 1 - self._clip) - # f_m1x_clip = f_m1x != np.clip(f_m1x, self._clip, 1 - self._clip) - # clipped = p_x_clip + f_m0x_clip + f_m1x_clip - - # var_name = ["t", "y", "p_x", "f_m0x", "f_m1x", "mu_1mx", "mu_0mx"] - # var_name += ["E_mu_t1_t1", "E_mu_t0_t0", "E_mu_t1_t0", "E_mu_t0_t1"] - # n_discarded = 0 - # for var in var_name: - # exec(f"{var} = {var}[~clipped]") - # n_discarded += np.sum(clipped) + mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 = ( + self._estimate_cross_conditional_mean_outcome_nesting(m, x, y)) # score computing if self._normalized: sum_score_m1 = np.mean(t / p_x) sum_score_m0 = np.mean((1 - t) / (1 - p_x)) - # sum_score_t1m0 = np.mean((t / p_x) * (f_m0x / f_m1x)) - # sum_score_t0m1 = np.mean((1 - t) / (1 - p_x) * (f_m1x / f_m0x)) sum_score_t1m0 = np.mean(t * ratio_t1_m0) sum_score_t0m1 = np.mean((1 - t) * ratio_t0_m1) y1m1 = (t / p_x * (y - E_mu_t1_t1)) / sum_score_m1 + E_mu_t1_t1 y0m0 = (((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / sum_score_m0 + E_mu_t0_t0) - # y1m0 = ( - # ((t / p_x) * (f_m0x / f_m1x) * ( - # y - mu_1mx)) / sum_score_t1m0 - # + ((1 - t) / (1 - p_x) * ( - # mu_1mx - E_mu_t1_t0)) / sum_score_m0 - # + E_mu_t1_t0 - # ) + y1m0 = ( (t * ratio_t1_m0 * ( y - mu_1mx)) / sum_score_t1m0 @@ -136,12 +86,7 @@ def estimate(self, t, m, x, y): mu_1mx - E_mu_t1_t0)) / sum_score_m0 + E_mu_t1_t0 ) - # y0m1 = ( - # ((1 - t) / (1 - p_x) * (f_m1x / f_m0x) * (y - mu_0mx)) - # / sum_score_t0m1 + t / p_x * ( - # mu_0mx - E_mu_t0_t1) / sum_score_m1 - # + E_mu_t0_t1 - # ) + y0m1 = ( ((1 - t) * ratio_t0_m1 * (y - mu_0mx)) / sum_score_t0m1 + t / p_x * ( @@ -151,16 +96,7 @@ def estimate(self, t, m, x, y): else: y1m1 = t / p_x * (y - E_mu_t1_t1) + E_mu_t1_t1 y0m0 = (1 - t) / (1 - p_x) * (y - E_mu_t0_t0) + E_mu_t0_t0 - # y1m0 = ( - # (t / p_x) * (f_m0x / f_m1x) * (y - mu_1mx) - # + (1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0) - # + E_mu_t1_t0 - # ) - # y0m1 = ( - # (1 - t) / (1 - p_x) * (f_m1x / f_m0x) * (y - mu_0mx) - # + t / p_x * (mu_0mx - E_mu_t0_t1) - # + E_mu_t0_t1 - # ) + y1m0 = ( t * ratio_t1_m0 * (y - mu_1mx) + (1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0) diff --git a/src/med_bench/example.py b/src/med_bench/example.py index 161061e..89db19c 100644 --- a/src/med_bench/example.py +++ b/src/med_bench/example.py @@ -1,13 +1,22 @@ from numpy.random import default_rng -from sklearn.ensemble import RandomForestClassifier -from sklearn.linear_model import RidgeCV +import pandas as pd +from sklearn.calibration import CalibratedClassifierCV +from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor +from sklearn.linear_model import LogisticRegressionCV, RidgeCV from sklearn.model_selection import train_test_split +from med_bench.mediation import (mediation_IPW, mediation_coefficient_product, mediation_dml, + mediation_g_formula, mediation_multiply_robust) from med_bench.estimation.mediation_coefficient_product import CoefficientProduct +from med_bench.estimation.mediation_dml import DoubleMachineLearning +from med_bench.estimation.mediation_g_computation import GComputation +from med_bench.estimation.mediation_ipw import ImportanceWeighting +from med_bench.estimation.mediation_mr import MultiplyRobust from med_bench.get_simulated_data import simulate_data from med_bench.nuisances.utils import _get_regularization_parameters from med_bench.utils.constants import CV_FOLDS + if __name__ == "__main__": print("get simulated data") (x, t, m, y, @@ -22,22 +31,94 @@ clf = RandomForestClassifier( random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) + clf2 = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) + + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + + reg2 = RidgeCV(alphas=alphas, cv=CV_FOLDS) + RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + + # Step 4: Define estimators (modularized and non-modularized) + estimators = { + "CoefficientProduct": { + "modular": CoefficientProduct( + mediator_type="binary", regressor=reg, classifier=clf, regularize=True + ), + "non_modular": mediation_coefficient_product + }, + "DoubleMachineLearning": { + "modular": DoubleMachineLearning( + clip=1e-6, trim=0.05, normalized=True, regressor=reg2, classifier=clf2 + ), + "non_modular": mediation_dml + }, + "GComputation": { + "modular": GComputation( + crossfit=0, procedure="discrete", regressor=reg2, classifier=CalibratedClassifierCV(clf2, method="sigmoid") + ), + "non_modular": mediation_g_formula + }, + "ImportanceWeighting": { + "modular": ImportanceWeighting( + clip=1e-6, trim=0.01, regressor=reg2, classifier=CalibratedClassifierCV(clf2, method="sigmoid") + ), + "non_modular": mediation_IPW + }, + "MultiplyRobust": { + "modular": MultiplyRobust( + clip=1e-6, ratio="propensities", normalized=True, regressor=reg2, + classifier=CalibratedClassifierCV(clf2, method="sigmoid") + ), + "non_modular": mediation_multiply_robust + } + } + + # Step 5: Initialize results DataFrame + results = [] + + # Step 6: Iterate over each estimator + for estimator_name, estimator_dict in estimators.items(): + # Non-Modularized Estimation + # Check if non-modular is a function + if callable(estimator_dict["non_modular"]): + (total_effect, direct_effect1, direct_effect2, indirect_effect1, indirect_effect2, _) = estimator_dict["non_modular"]( + y, t, m, x) + + results.append({ + "Estimator": estimator_name, + "Method": "Non-Modularized", + "Total Effect": total_effect, + "Direct Effect (Treated)": direct_effect1, + "Direct Effect (Control)": direct_effect2, + "Indirect Effect (Treated)": indirect_effect1, + "Indirect Effect (Control)": indirect_effect2, + "R Risk Score": None # R risk only for modularized + }) - coef_prod_estimator = CoefficientProduct( - mediator_type="binary", regressor=reg, classifier=clf, clip=0.01, trim=0.01, regularize=True) + # Modularized Estimation + modular_estimator = estimator_dict["modular"] + modular_estimator.fit(t_train, m_train, x_train, y_train) + causal_effects = modular_estimator.estimate( + t_test, m_test, x_test, y_test) + r_risk_score = modular_estimator.score( + t_test, m_test, x_test, y_test, causal_effects['total_effect']) - coef_prod_estimator.fit(t_train, m_train, x_train, y_train) - causal_effects = coef_prod_estimator.estimate( - t_test, m_test, x_test, y_test) + # Append modularized results + results.append({ + "Estimator": estimator_name, + "Method": "Modularized", + "Total Effect": causal_effects['total_effect'], + "Direct Effect (Treated)": causal_effects['direct_effect_treated'], + "Direct Effect (Control)": causal_effects['direct_effect_control'], + "Indirect Effect (Treated)": causal_effects['indirect_effect_treated'], + "Indirect Effect (Control)": causal_effects['indirect_effect_control'], + "R Risk Score": r_risk_score + }) - r_risk_score = coef_prod_estimator.score( - t_test, m_test, x_test, y_test, causal_effects['total_effect']) + # Convert results to DataFrame + results_df = pd.DataFrame(results) - print('R risk score: {}'.format(r_risk_score)) - print('Total effect error: {}'.format( - abs(causal_effects['total_effect']-theta_1_delta_0))) - print('Direct effect error: {}'.format( - abs(causal_effects['direct_effect_control']-theta_0))) - print('Indirect effect error: {}'.format( - abs(causal_effects['indirect_effect_treated']-delta_1))) + # Display or save the DataFrame + print(results_df) diff --git a/src/med_bench/utils/loader.py b/src/med_bench/utils/loader.py index d30f5e2..f668823 100644 --- a/src/med_bench/utils/loader.py +++ b/src/med_bench/utils/loader.py @@ -1,8 +1,9 @@ -from med_bench.estimation.ipw import ImportanceWeighting -from med_bench.estimation.g_computation import GComputation -from med_bench.estimation.dml import DoubleMachineLearning -from med_bench.estimation.mr import MultiplyRobust -from med_bench.estimation.tmle import TMLE +from med_bench.estimation.mediation_ipw import ImportanceWeighting +from med_bench.estimation.mediation_g_computation import GComputation +from med_bench.estimation.mediation_coefficient_product import CoefficientProduct +from med_bench.estimation.mediation_dml import DoubleMachineLearning +from med_bench.estimation.mediation_mr import MultiplyRobust +from med_bench.estimation.mediation_tmle import TMLE def get_estimator_by_name(settings): @@ -10,8 +11,8 @@ def get_estimator_by_name(settings): return ImportanceWeighting elif settings['estimator'] == 'g_computation': return GComputation - elif settings['estimator'] == 'linear': - return Linear + elif settings['estimator'] == 'coefficient_product': + return CoefficientProduct elif settings['estimator'] == 'mr': return MultiplyRobust elif settings['estimator'] == 'dml': @@ -19,4 +20,4 @@ def get_estimator_by_name(settings): elif settings['estimator'] == 'tmle': return TMLE else: - raise NotImplementedError \ No newline at end of file + raise NotImplementedError From 09936d44d6c80576bc4dd459f0e2a112dfd677a7 Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 30 Oct 2024 18:48:58 +0100 Subject: [PATCH 22/84] minor changes in ipw --- src/med_bench/estimation/mediation_ipw.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/med_bench/estimation/mediation_ipw.py b/src/med_bench/estimation/mediation_ipw.py index 0fb2180..7d657e9 100644 --- a/src/med_bench/estimation/mediation_ipw.py +++ b/src/med_bench/estimation/mediation_ipw.py @@ -15,6 +15,7 @@ def __init__(self, clip: float, trim: float, **kwargs): """ super().__init__(**kwargs) + self._crossfit = 0 self._clip = clip self._trim = trim @@ -40,7 +41,7 @@ def estimate(self, t, m, x, y): """Estimates causal effect on data """ - t, m, x, y = self._resize(t, m, x, y) + t, m, x, y = self.resize(t, m, x, y) p_x, p_xm = self._estimate_treatment_probabilities(t, m, x) ind = ((p_xm > self._trim) & (p_xm < (1 - self._trim))) From 9c36a8a4a67bf496e2f7623d223e20e154a5f526 Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 30 Oct 2024 18:51:11 +0100 Subject: [PATCH 23/84] Revert "minor changes in ipw" This reverts commit 09936d44d6c80576bc4dd459f0e2a112dfd677a7. --- src/med_bench/estimation/mediation_ipw.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/med_bench/estimation/mediation_ipw.py b/src/med_bench/estimation/mediation_ipw.py index 7d657e9..0fb2180 100644 --- a/src/med_bench/estimation/mediation_ipw.py +++ b/src/med_bench/estimation/mediation_ipw.py @@ -15,7 +15,6 @@ def __init__(self, clip: float, trim: float, **kwargs): """ super().__init__(**kwargs) - self._crossfit = 0 self._clip = clip self._trim = trim @@ -41,7 +40,7 @@ def estimate(self, t, m, x, y): """Estimates causal effect on data """ - t, m, x, y = self.resize(t, m, x, y) + t, m, x, y = self._resize(t, m, x, y) p_x, p_xm = self._estimate_treatment_probabilities(t, m, x) ind = ((p_xm > self._trim) & (p_xm < (1 - self._trim))) From 118a8c389220f75e13252276a575fbf448bc17b9 Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 30 Oct 2024 18:51:58 +0100 Subject: [PATCH 24/84] clean dml --- src/med_bench/estimation/mediation_dml.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/med_bench/estimation/mediation_dml.py b/src/med_bench/estimation/mediation_dml.py index 9a2396b..958c18d 100644 --- a/src/med_bench/estimation/mediation_dml.py +++ b/src/med_bench/estimation/mediation_dml.py @@ -13,9 +13,11 @@ class DoubleMachineLearning(Estimator): if |alpha_i| < support_vec_tol * alpha then vector is discarded """ - def __init__(self, clip: float, trim: float, normalized: bool, **kwargs): + def __init__(self, procedure: str, clip: float, trim: float, normalized: bool, **kwargs): super().__init__(**kwargs) + self._crossfit = 0 + self._procedure = procedure self._clip = clip self._trim = trim self._normalized = normalized From c14ef7a62c9cd32d0bbae7bfc63351f649c8584a Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 30 Oct 2024 18:52:38 +0100 Subject: [PATCH 25/84] clean dml correct This reverts commit 118a8c389220f75e13252276a575fbf448bc17b9. --- src/med_bench/estimation/mediation_dml.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/med_bench/estimation/mediation_dml.py b/src/med_bench/estimation/mediation_dml.py index 958c18d..9a2396b 100644 --- a/src/med_bench/estimation/mediation_dml.py +++ b/src/med_bench/estimation/mediation_dml.py @@ -13,11 +13,9 @@ class DoubleMachineLearning(Estimator): if |alpha_i| < support_vec_tol * alpha then vector is discarded """ - def __init__(self, procedure: str, clip: float, trim: float, normalized: bool, **kwargs): + def __init__(self, clip: float, trim: float, normalized: bool, **kwargs): super().__init__(**kwargs) - self._crossfit = 0 - self._procedure = procedure self._clip = clip self._trim = trim self._normalized = normalized From 46453184f91cf902bfc6001e1e1c1863c651c8a6 Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 30 Oct 2024 18:53:27 +0100 Subject: [PATCH 26/84] not clean multiply robust --- src/med_bench/estimation/mediation_mr.py | 92 ++++++++++++++++++++---- 1 file changed, 78 insertions(+), 14 deletions(-) diff --git a/src/med_bench/estimation/mediation_mr.py b/src/med_bench/estimation/mediation_mr.py index 5811aa2..76c194a 100644 --- a/src/med_bench/estimation/mediation_mr.py +++ b/src/med_bench/estimation/mediation_mr.py @@ -2,30 +2,39 @@ from med_bench.estimation.base import Estimator from med_bench.utils.decorators import fitted -from med_bench.utils.utils import is_array_integer class MultiplyRobust(Estimator): - """Implementation of multiply robust estimator + """Implementation of multiply robust + + Args: + settings (dict): dictionnary of parameters + lbda (float): regularization parameter + support_vec_tol (float): tolerance for discarding non-supporting vectors + if |alpha_i| < support_vec_tol * lbda then vector is discarded + verbose (int): in {0, 1} """ - def __init__(self, ratio: str, clip: float, normalized, **kwargs): + def __init__(self, procedure: str, ratio: str, clip: float, normalized, **kwargs): super().__init__(**kwargs) - assert ratio in ['density', 'propensities'] + self._crossfit = 0 + self._procedure = procedure self._ratio = ratio self._clip = clip self._normalized = normalized def fit(self, t, m, x, y): """Fits nuisance parameters to data + """ + # bucketize if needed t, m, x, y = self._resize(t, m, x, y) # fit nuisance functions self._fit_nuisance(t, m, x, y) - if self._ratio == 'density' and is_array_integer(m): + if self._ratio == 'density': self._fit_treatment_propensity_x_nuisance(t, x) self._fit_mediator_nuisance(t, m, x) @@ -33,11 +42,14 @@ def fit(self, t, m, x, y): self._fit_treatment_propensity_x_nuisance(t, x) self._fit_treatment_propensity_xm_nuisance(t, m, x) - elif self._ratio == 'density' and not is_array_integer(m): - raise NotImplementedError("""Continuous mediator cannot use the density ratio method, - use a discrete mediator or set the ratio to 'propensities'""") + else: + raise NotImplementedError - self._fit_cross_conditional_mean_outcome_nuisance(t, m, x, y) + if self._procedure == 'nesting': + self._fit_cross_conditional_mean_outcome_nuisance(t, m, x, y) + + else: + raise NotImplementedError self._fitted = True @@ -56,6 +68,7 @@ def estimate(self, t, m, x, y): if self._ratio == 'density': f_m0x, f_m1x = self._estimate_mediator_probability(t, m, x, y) + p_x = self._estimate_treatment_propensity_x(t, m, x) ratio_t1_m0 = f_m0x / (p_x * f_m1x) ratio_t0_m1 = f_m1x / ((1 - p_x) * f_m0x) @@ -65,20 +78,57 @@ def estimate(self, t, m, x, y): ratio_t1_m0 = (1-p_xm) / ((1 - p_x) * p_xm) ratio_t0_m1 = p_xm / ((1 - p_xm) * p_x) - mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 = ( - self._estimate_cross_conditional_mean_outcome_nesting(m, x, y)) + if self._procedure == 'nesting': + + # p_x = estimate_treatment_propensity_x(t, + # m, + # x, + # self._crossfit, + # self._classifier_t_x) + + # _, _, f_m0x, f_m1x = estimate_mediator_density(t, + # m, + # x, + # y, + # self._crossfit, + # self._classifier_m, + # False) + + mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 = ( + self._estimate_cross_conditional_mean_outcome_nesting(m, x, y)) + + # clipping + # p_x_clip = p_x != np.clip(p_x, self._clip, 1 - self._clip) + # f_m0x_clip = f_m0x != np.clip(f_m0x, self._clip, 1 - self._clip) + # f_m1x_clip = f_m1x != np.clip(f_m1x, self._clip, 1 - self._clip) + # clipped = p_x_clip + f_m0x_clip + f_m1x_clip + + # var_name = ["t", "y", "p_x", "f_m0x", "f_m1x", "mu_1mx", "mu_0mx"] + # var_name += ["E_mu_t1_t1", "E_mu_t0_t0", "E_mu_t1_t0", "E_mu_t0_t1"] + # n_discarded = 0 + # for var in var_name: + # exec(f"{var} = {var}[~clipped]") + # n_discarded += np.sum(clipped) # score computing if self._normalized: sum_score_m1 = np.mean(t / p_x) sum_score_m0 = np.mean((1 - t) / (1 - p_x)) + # sum_score_t1m0 = np.mean((t / p_x) * (f_m0x / f_m1x)) + # sum_score_t0m1 = np.mean((1 - t) / (1 - p_x) * (f_m1x / f_m0x)) sum_score_t1m0 = np.mean(t * ratio_t1_m0) sum_score_t0m1 = np.mean((1 - t) * ratio_t0_m1) y1m1 = (t / p_x * (y - E_mu_t1_t1)) / sum_score_m1 + E_mu_t1_t1 y0m0 = (((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / sum_score_m0 + E_mu_t0_t0) - + # y1m0 = ( + # ((t / p_x) * (f_m0x / f_m1x) * ( + # y - mu_1mx)) / sum_score_t1m0 + # + ((1 - t) / (1 - p_x) * ( + # mu_1mx - E_mu_t1_t0)) / sum_score_m0 + # + E_mu_t1_t0 + # ) y1m0 = ( (t * ratio_t1_m0 * ( y - mu_1mx)) / sum_score_t1m0 @@ -86,7 +136,12 @@ def estimate(self, t, m, x, y): mu_1mx - E_mu_t1_t0)) / sum_score_m0 + E_mu_t1_t0 ) - + # y0m1 = ( + # ((1 - t) / (1 - p_x) * (f_m1x / f_m0x) * (y - mu_0mx)) + # / sum_score_t0m1 + t / p_x * ( + # mu_0mx - E_mu_t0_t1) / sum_score_m1 + # + E_mu_t0_t1 + # ) y0m1 = ( ((1 - t) * ratio_t0_m1 * (y - mu_0mx)) / sum_score_t0m1 + t / p_x * ( @@ -96,7 +151,16 @@ def estimate(self, t, m, x, y): else: y1m1 = t / p_x * (y - E_mu_t1_t1) + E_mu_t1_t1 y0m0 = (1 - t) / (1 - p_x) * (y - E_mu_t0_t0) + E_mu_t0_t0 - + # y1m0 = ( + # (t / p_x) * (f_m0x / f_m1x) * (y - mu_1mx) + # + (1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0) + # + E_mu_t1_t0 + # ) + # y0m1 = ( + # (1 - t) / (1 - p_x) * (f_m1x / f_m0x) * (y - mu_0mx) + # + t / p_x * (mu_0mx - E_mu_t0_t1) + # + E_mu_t0_t1 + # ) y1m0 = ( t * ratio_t1_m0 * (y - mu_1mx) + (1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0) From 8140f40d00d618edbe737db98ef1366187a5cb36 Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 30 Oct 2024 18:53:51 +0100 Subject: [PATCH 27/84] clean multiply robust This reverts commit 46453184f91cf902bfc6001e1e1c1863c651c8a6. --- src/med_bench/estimation/mediation_mr.py | 92 ++++-------------------- 1 file changed, 14 insertions(+), 78 deletions(-) diff --git a/src/med_bench/estimation/mediation_mr.py b/src/med_bench/estimation/mediation_mr.py index 76c194a..5811aa2 100644 --- a/src/med_bench/estimation/mediation_mr.py +++ b/src/med_bench/estimation/mediation_mr.py @@ -2,39 +2,30 @@ from med_bench.estimation.base import Estimator from med_bench.utils.decorators import fitted +from med_bench.utils.utils import is_array_integer class MultiplyRobust(Estimator): - """Implementation of multiply robust - - Args: - settings (dict): dictionnary of parameters - lbda (float): regularization parameter - support_vec_tol (float): tolerance for discarding non-supporting vectors - if |alpha_i| < support_vec_tol * lbda then vector is discarded - verbose (int): in {0, 1} + """Implementation of multiply robust estimator """ - def __init__(self, procedure: str, ratio: str, clip: float, normalized, **kwargs): + def __init__(self, ratio: str, clip: float, normalized, **kwargs): super().__init__(**kwargs) - self._crossfit = 0 - self._procedure = procedure + assert ratio in ['density', 'propensities'] self._ratio = ratio self._clip = clip self._normalized = normalized def fit(self, t, m, x, y): """Fits nuisance parameters to data - """ - # bucketize if needed t, m, x, y = self._resize(t, m, x, y) # fit nuisance functions self._fit_nuisance(t, m, x, y) - if self._ratio == 'density': + if self._ratio == 'density' and is_array_integer(m): self._fit_treatment_propensity_x_nuisance(t, x) self._fit_mediator_nuisance(t, m, x) @@ -42,14 +33,11 @@ def fit(self, t, m, x, y): self._fit_treatment_propensity_x_nuisance(t, x) self._fit_treatment_propensity_xm_nuisance(t, m, x) - else: - raise NotImplementedError + elif self._ratio == 'density' and not is_array_integer(m): + raise NotImplementedError("""Continuous mediator cannot use the density ratio method, + use a discrete mediator or set the ratio to 'propensities'""") - if self._procedure == 'nesting': - self._fit_cross_conditional_mean_outcome_nuisance(t, m, x, y) - - else: - raise NotImplementedError + self._fit_cross_conditional_mean_outcome_nuisance(t, m, x, y) self._fitted = True @@ -68,7 +56,6 @@ def estimate(self, t, m, x, y): if self._ratio == 'density': f_m0x, f_m1x = self._estimate_mediator_probability(t, m, x, y) - p_x = self._estimate_treatment_propensity_x(t, m, x) ratio_t1_m0 = f_m0x / (p_x * f_m1x) ratio_t0_m1 = f_m1x / ((1 - p_x) * f_m0x) @@ -78,57 +65,20 @@ def estimate(self, t, m, x, y): ratio_t1_m0 = (1-p_xm) / ((1 - p_x) * p_xm) ratio_t0_m1 = p_xm / ((1 - p_xm) * p_x) - if self._procedure == 'nesting': - - # p_x = estimate_treatment_propensity_x(t, - # m, - # x, - # self._crossfit, - # self._classifier_t_x) - - # _, _, f_m0x, f_m1x = estimate_mediator_density(t, - # m, - # x, - # y, - # self._crossfit, - # self._classifier_m, - # False) - - mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 = ( - self._estimate_cross_conditional_mean_outcome_nesting(m, x, y)) - - # clipping - # p_x_clip = p_x != np.clip(p_x, self._clip, 1 - self._clip) - # f_m0x_clip = f_m0x != np.clip(f_m0x, self._clip, 1 - self._clip) - # f_m1x_clip = f_m1x != np.clip(f_m1x, self._clip, 1 - self._clip) - # clipped = p_x_clip + f_m0x_clip + f_m1x_clip - - # var_name = ["t", "y", "p_x", "f_m0x", "f_m1x", "mu_1mx", "mu_0mx"] - # var_name += ["E_mu_t1_t1", "E_mu_t0_t0", "E_mu_t1_t0", "E_mu_t0_t1"] - # n_discarded = 0 - # for var in var_name: - # exec(f"{var} = {var}[~clipped]") - # n_discarded += np.sum(clipped) + mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 = ( + self._estimate_cross_conditional_mean_outcome_nesting(m, x, y)) # score computing if self._normalized: sum_score_m1 = np.mean(t / p_x) sum_score_m0 = np.mean((1 - t) / (1 - p_x)) - # sum_score_t1m0 = np.mean((t / p_x) * (f_m0x / f_m1x)) - # sum_score_t0m1 = np.mean((1 - t) / (1 - p_x) * (f_m1x / f_m0x)) sum_score_t1m0 = np.mean(t * ratio_t1_m0) sum_score_t0m1 = np.mean((1 - t) * ratio_t0_m1) y1m1 = (t / p_x * (y - E_mu_t1_t1)) / sum_score_m1 + E_mu_t1_t1 y0m0 = (((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / sum_score_m0 + E_mu_t0_t0) - # y1m0 = ( - # ((t / p_x) * (f_m0x / f_m1x) * ( - # y - mu_1mx)) / sum_score_t1m0 - # + ((1 - t) / (1 - p_x) * ( - # mu_1mx - E_mu_t1_t0)) / sum_score_m0 - # + E_mu_t1_t0 - # ) + y1m0 = ( (t * ratio_t1_m0 * ( y - mu_1mx)) / sum_score_t1m0 @@ -136,12 +86,7 @@ def estimate(self, t, m, x, y): mu_1mx - E_mu_t1_t0)) / sum_score_m0 + E_mu_t1_t0 ) - # y0m1 = ( - # ((1 - t) / (1 - p_x) * (f_m1x / f_m0x) * (y - mu_0mx)) - # / sum_score_t0m1 + t / p_x * ( - # mu_0mx - E_mu_t0_t1) / sum_score_m1 - # + E_mu_t0_t1 - # ) + y0m1 = ( ((1 - t) * ratio_t0_m1 * (y - mu_0mx)) / sum_score_t0m1 + t / p_x * ( @@ -151,16 +96,7 @@ def estimate(self, t, m, x, y): else: y1m1 = t / p_x * (y - E_mu_t1_t1) + E_mu_t1_t1 y0m0 = (1 - t) / (1 - p_x) * (y - E_mu_t0_t0) + E_mu_t0_t0 - # y1m0 = ( - # (t / p_x) * (f_m0x / f_m1x) * (y - mu_1mx) - # + (1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0) - # + E_mu_t1_t0 - # ) - # y0m1 = ( - # (1 - t) / (1 - p_x) * (f_m1x / f_m0x) * (y - mu_0mx) - # + t / p_x * (mu_0mx - E_mu_t0_t1) - # + E_mu_t0_t1 - # ) + y1m0 = ( t * ratio_t1_m0 * (y - mu_1mx) + (1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0) From 8f783d459cec4aac097f8345e96240c9beb20c9c Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 30 Oct 2024 18:54:50 +0100 Subject: [PATCH 28/84] remove useless loader file --- src/med_bench/utils/loader.py | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 src/med_bench/utils/loader.py diff --git a/src/med_bench/utils/loader.py b/src/med_bench/utils/loader.py deleted file mode 100644 index f668823..0000000 --- a/src/med_bench/utils/loader.py +++ /dev/null @@ -1,23 +0,0 @@ -from med_bench.estimation.mediation_ipw import ImportanceWeighting -from med_bench.estimation.mediation_g_computation import GComputation -from med_bench.estimation.mediation_coefficient_product import CoefficientProduct -from med_bench.estimation.mediation_dml import DoubleMachineLearning -from med_bench.estimation.mediation_mr import MultiplyRobust -from med_bench.estimation.mediation_tmle import TMLE - - -def get_estimator_by_name(settings): - if settings['estimator'] == 'ipw': - return ImportanceWeighting - elif settings['estimator'] == 'g_computation': - return GComputation - elif settings['estimator'] == 'coefficient_product': - return CoefficientProduct - elif settings['estimator'] == 'mr': - return MultiplyRobust - elif settings['estimator'] == 'dml': - return DoubleMachineLearning - elif settings['estimator'] == 'tmle': - return TMLE - else: - raise NotImplementedError From c7b1e1f6140da9dbc84fe798e5f88c36a4fcdf67 Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 30 Oct 2024 18:55:03 +0100 Subject: [PATCH 29/84] old example --- src/med_bench/example.py | 115 ++++++--------------------------------- 1 file changed, 17 insertions(+), 98 deletions(-) diff --git a/src/med_bench/example.py b/src/med_bench/example.py index 89db19c..161061e 100644 --- a/src/med_bench/example.py +++ b/src/med_bench/example.py @@ -1,22 +1,13 @@ from numpy.random import default_rng -import pandas as pd -from sklearn.calibration import CalibratedClassifierCV -from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor -from sklearn.linear_model import LogisticRegressionCV, RidgeCV +from sklearn.ensemble import RandomForestClassifier +from sklearn.linear_model import RidgeCV from sklearn.model_selection import train_test_split -from med_bench.mediation import (mediation_IPW, mediation_coefficient_product, mediation_dml, - mediation_g_formula, mediation_multiply_robust) from med_bench.estimation.mediation_coefficient_product import CoefficientProduct -from med_bench.estimation.mediation_dml import DoubleMachineLearning -from med_bench.estimation.mediation_g_computation import GComputation -from med_bench.estimation.mediation_ipw import ImportanceWeighting -from med_bench.estimation.mediation_mr import MultiplyRobust from med_bench.get_simulated_data import simulate_data from med_bench.nuisances.utils import _get_regularization_parameters from med_bench.utils.constants import CV_FOLDS - if __name__ == "__main__": print("get simulated data") (x, t, m, y, @@ -31,94 +22,22 @@ clf = RandomForestClassifier( random_state=42, n_estimators=100, min_samples_leaf=10) - clf2 = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) - - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - - reg2 = RidgeCV(alphas=alphas, cv=CV_FOLDS) - RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - - # Step 4: Define estimators (modularized and non-modularized) - estimators = { - "CoefficientProduct": { - "modular": CoefficientProduct( - mediator_type="binary", regressor=reg, classifier=clf, regularize=True - ), - "non_modular": mediation_coefficient_product - }, - "DoubleMachineLearning": { - "modular": DoubleMachineLearning( - clip=1e-6, trim=0.05, normalized=True, regressor=reg2, classifier=clf2 - ), - "non_modular": mediation_dml - }, - "GComputation": { - "modular": GComputation( - crossfit=0, procedure="discrete", regressor=reg2, classifier=CalibratedClassifierCV(clf2, method="sigmoid") - ), - "non_modular": mediation_g_formula - }, - "ImportanceWeighting": { - "modular": ImportanceWeighting( - clip=1e-6, trim=0.01, regressor=reg2, classifier=CalibratedClassifierCV(clf2, method="sigmoid") - ), - "non_modular": mediation_IPW - }, - "MultiplyRobust": { - "modular": MultiplyRobust( - clip=1e-6, ratio="propensities", normalized=True, regressor=reg2, - classifier=CalibratedClassifierCV(clf2, method="sigmoid") - ), - "non_modular": mediation_multiply_robust - } - } - - # Step 5: Initialize results DataFrame - results = [] - - # Step 6: Iterate over each estimator - for estimator_name, estimator_dict in estimators.items(): - # Non-Modularized Estimation - # Check if non-modular is a function - if callable(estimator_dict["non_modular"]): - (total_effect, direct_effect1, direct_effect2, indirect_effect1, indirect_effect2, _) = estimator_dict["non_modular"]( - y, t, m, x) - - results.append({ - "Estimator": estimator_name, - "Method": "Non-Modularized", - "Total Effect": total_effect, - "Direct Effect (Treated)": direct_effect1, - "Direct Effect (Control)": direct_effect2, - "Indirect Effect (Treated)": indirect_effect1, - "Indirect Effect (Control)": indirect_effect2, - "R Risk Score": None # R risk only for modularized - }) + reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) - # Modularized Estimation - modular_estimator = estimator_dict["modular"] - modular_estimator.fit(t_train, m_train, x_train, y_train) - causal_effects = modular_estimator.estimate( - t_test, m_test, x_test, y_test) - r_risk_score = modular_estimator.score( - t_test, m_test, x_test, y_test, causal_effects['total_effect']) + coef_prod_estimator = CoefficientProduct( + mediator_type="binary", regressor=reg, classifier=clf, clip=0.01, trim=0.01, regularize=True) - # Append modularized results - results.append({ - "Estimator": estimator_name, - "Method": "Modularized", - "Total Effect": causal_effects['total_effect'], - "Direct Effect (Treated)": causal_effects['direct_effect_treated'], - "Direct Effect (Control)": causal_effects['direct_effect_control'], - "Indirect Effect (Treated)": causal_effects['indirect_effect_treated'], - "Indirect Effect (Control)": causal_effects['indirect_effect_control'], - "R Risk Score": r_risk_score - }) + coef_prod_estimator.fit(t_train, m_train, x_train, y_train) + causal_effects = coef_prod_estimator.estimate( + t_test, m_test, x_test, y_test) - # Convert results to DataFrame - results_df = pd.DataFrame(results) + r_risk_score = coef_prod_estimator.score( + t_test, m_test, x_test, y_test, causal_effects['total_effect']) - # Display or save the DataFrame - print(results_df) + print('R risk score: {}'.format(r_risk_score)) + print('Total effect error: {}'.format( + abs(causal_effects['total_effect']-theta_1_delta_0))) + print('Direct effect error: {}'.format( + abs(causal_effects['direct_effect_control']-theta_0))) + print('Indirect effect error: {}'.format( + abs(causal_effects['indirect_effect_treated']-delta_1))) From a743d74246561065d5b76592886d3d2229ed31ac Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 30 Oct 2024 18:55:28 +0100 Subject: [PATCH 30/84] new example This reverts commit c7b1e1f6140da9dbc84fe798e5f88c36a4fcdf67. --- src/med_bench/example.py | 115 +++++++++++++++++++++++++++++++++------ 1 file changed, 98 insertions(+), 17 deletions(-) diff --git a/src/med_bench/example.py b/src/med_bench/example.py index 161061e..89db19c 100644 --- a/src/med_bench/example.py +++ b/src/med_bench/example.py @@ -1,13 +1,22 @@ from numpy.random import default_rng -from sklearn.ensemble import RandomForestClassifier -from sklearn.linear_model import RidgeCV +import pandas as pd +from sklearn.calibration import CalibratedClassifierCV +from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor +from sklearn.linear_model import LogisticRegressionCV, RidgeCV from sklearn.model_selection import train_test_split +from med_bench.mediation import (mediation_IPW, mediation_coefficient_product, mediation_dml, + mediation_g_formula, mediation_multiply_robust) from med_bench.estimation.mediation_coefficient_product import CoefficientProduct +from med_bench.estimation.mediation_dml import DoubleMachineLearning +from med_bench.estimation.mediation_g_computation import GComputation +from med_bench.estimation.mediation_ipw import ImportanceWeighting +from med_bench.estimation.mediation_mr import MultiplyRobust from med_bench.get_simulated_data import simulate_data from med_bench.nuisances.utils import _get_regularization_parameters from med_bench.utils.constants import CV_FOLDS + if __name__ == "__main__": print("get simulated data") (x, t, m, y, @@ -22,22 +31,94 @@ clf = RandomForestClassifier( random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) + clf2 = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) + + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + + reg2 = RidgeCV(alphas=alphas, cv=CV_FOLDS) + RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + + # Step 4: Define estimators (modularized and non-modularized) + estimators = { + "CoefficientProduct": { + "modular": CoefficientProduct( + mediator_type="binary", regressor=reg, classifier=clf, regularize=True + ), + "non_modular": mediation_coefficient_product + }, + "DoubleMachineLearning": { + "modular": DoubleMachineLearning( + clip=1e-6, trim=0.05, normalized=True, regressor=reg2, classifier=clf2 + ), + "non_modular": mediation_dml + }, + "GComputation": { + "modular": GComputation( + crossfit=0, procedure="discrete", regressor=reg2, classifier=CalibratedClassifierCV(clf2, method="sigmoid") + ), + "non_modular": mediation_g_formula + }, + "ImportanceWeighting": { + "modular": ImportanceWeighting( + clip=1e-6, trim=0.01, regressor=reg2, classifier=CalibratedClassifierCV(clf2, method="sigmoid") + ), + "non_modular": mediation_IPW + }, + "MultiplyRobust": { + "modular": MultiplyRobust( + clip=1e-6, ratio="propensities", normalized=True, regressor=reg2, + classifier=CalibratedClassifierCV(clf2, method="sigmoid") + ), + "non_modular": mediation_multiply_robust + } + } + + # Step 5: Initialize results DataFrame + results = [] + + # Step 6: Iterate over each estimator + for estimator_name, estimator_dict in estimators.items(): + # Non-Modularized Estimation + # Check if non-modular is a function + if callable(estimator_dict["non_modular"]): + (total_effect, direct_effect1, direct_effect2, indirect_effect1, indirect_effect2, _) = estimator_dict["non_modular"]( + y, t, m, x) + + results.append({ + "Estimator": estimator_name, + "Method": "Non-Modularized", + "Total Effect": total_effect, + "Direct Effect (Treated)": direct_effect1, + "Direct Effect (Control)": direct_effect2, + "Indirect Effect (Treated)": indirect_effect1, + "Indirect Effect (Control)": indirect_effect2, + "R Risk Score": None # R risk only for modularized + }) - coef_prod_estimator = CoefficientProduct( - mediator_type="binary", regressor=reg, classifier=clf, clip=0.01, trim=0.01, regularize=True) + # Modularized Estimation + modular_estimator = estimator_dict["modular"] + modular_estimator.fit(t_train, m_train, x_train, y_train) + causal_effects = modular_estimator.estimate( + t_test, m_test, x_test, y_test) + r_risk_score = modular_estimator.score( + t_test, m_test, x_test, y_test, causal_effects['total_effect']) - coef_prod_estimator.fit(t_train, m_train, x_train, y_train) - causal_effects = coef_prod_estimator.estimate( - t_test, m_test, x_test, y_test) + # Append modularized results + results.append({ + "Estimator": estimator_name, + "Method": "Modularized", + "Total Effect": causal_effects['total_effect'], + "Direct Effect (Treated)": causal_effects['direct_effect_treated'], + "Direct Effect (Control)": causal_effects['direct_effect_control'], + "Indirect Effect (Treated)": causal_effects['indirect_effect_treated'], + "Indirect Effect (Control)": causal_effects['indirect_effect_control'], + "R Risk Score": r_risk_score + }) - r_risk_score = coef_prod_estimator.score( - t_test, m_test, x_test, y_test, causal_effects['total_effect']) + # Convert results to DataFrame + results_df = pd.DataFrame(results) - print('R risk score: {}'.format(r_risk_score)) - print('Total effect error: {}'.format( - abs(causal_effects['total_effect']-theta_1_delta_0))) - print('Direct effect error: {}'.format( - abs(causal_effects['direct_effect_control']-theta_0))) - print('Indirect effect error: {}'.format( - abs(causal_effects['indirect_effect_treated']-delta_1))) + # Display or save the DataFrame + print(results_df) From 8ac63aa312d66276fd2f12689c0185d5a2093b1a Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 30 Oct 2024 20:42:06 +0100 Subject: [PATCH 31/84] fix reshape in coefficient product --- src/med_bench/estimation/mediation_coefficient_product.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/med_bench/estimation/mediation_coefficient_product.py b/src/med_bench/estimation/mediation_coefficient_product.py index 0184e5b..1c78a3b 100644 --- a/src/med_bench/estimation/mediation_coefficient_product.py +++ b/src/med_bench/estimation/mediation_coefficient_product.py @@ -44,7 +44,7 @@ def fit(self, t, m, x, y): alphas = ALPHAS else: alphas = [TINY] - t, m, x, y = self._resize(t, m, x, y) + t, m, x = self._input_reshape(t, m, x) self._coef_t_m = np.zeros(m.shape[1]) for i in range(m.shape[1]): From 3ffc4c0651d0f021459d52b3d6927ecabfb88a40 Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 30 Oct 2024 20:44:46 +0100 Subject: [PATCH 32/84] remove _fit_nuisances and _score functions --- src/med_bench/estimation/base.py | 33 ------------------- .../mediation_coefficient_product.py | 3 -- src/med_bench/estimation/mediation_dml.py | 1 - .../estimation/mediation_g_computation.py | 2 -- src/med_bench/estimation/mediation_ipw.py | 1 - src/med_bench/estimation/mediation_mr.py | 3 -- src/med_bench/estimation/mediation_tmle.py | 3 -- 7 files changed, 46 deletions(-) diff --git a/src/med_bench/estimation/base.py b/src/med_bench/estimation/base.py index c954fe3..7eb6f1a 100644 --- a/src/med_bench/estimation/base.py +++ b/src/med_bench/estimation/base.py @@ -160,39 +160,6 @@ def _input_reshape(self, t, m, x): return t, m, x - def _fit_nuisance(self, t, m, x, y, *args, **kwargs): - """ Fits the score of the nuisance parameters - """ - # How do we want to specify gridsearch parameters ? As a function param, a constant or hardcoded here ? - clf_param_grid = {} - reg_param_grid = {} - - classifier_x = GridSearchCV(self.classifier, clf_param_grid) - - self._hat_e = classifier_x.fit(x, t.squeeze()) - - regressor_y = GridSearchCV(self.regressor, reg_param_grid) - - self._hat_m = regressor_y.fit(x, y.squeeze()) - - return self - - @fitted - def score(self, t, m, x, y, tau_): - """Predicts score on data samples - - Parameters - ---------- - - tau_ array-like, shape (n_samples) - estimated risk - """ - - hat_e = self._hat_e.predict_proba(x)[:, 1] - hat_m = self._hat_m.predict(x) - score = r_risk(y.squeeze(), t.squeeze(), hat_m, hat_e, tau_) - return score - def _fit_treatment_propensity_x_nuisance(self, t, x): """ Fits the nuisance parameter for the propensity P(T=1|X) """ diff --git a/src/med_bench/estimation/mediation_coefficient_product.py b/src/med_bench/estimation/mediation_coefficient_product.py index 1c78a3b..0e3b75f 100644 --- a/src/med_bench/estimation/mediation_coefficient_product.py +++ b/src/med_bench/estimation/mediation_coefficient_product.py @@ -37,9 +37,6 @@ def fit(self, t, m, x, y): outcome value for each unit, continuous """ - self._fit_nuisance(t, m, x, y) - # estimate mediator densities - if self._regularize: alphas = ALPHAS else: diff --git a/src/med_bench/estimation/mediation_dml.py b/src/med_bench/estimation/mediation_dml.py index 9a2396b..d1d93b4 100644 --- a/src/med_bench/estimation/mediation_dml.py +++ b/src/med_bench/estimation/mediation_dml.py @@ -24,7 +24,6 @@ def fit(self, t, m, x, y): """Fits nuisance parameters to data """ - self._fit_nuisance(t, m, x, y) t, m, x, y = self._resize(t, m, x, y) self._fit_treatment_propensity_x_nuisance(t, x) diff --git a/src/med_bench/estimation/mediation_g_computation.py b/src/med_bench/estimation/mediation_g_computation.py index d17e969..430f10e 100644 --- a/src/med_bench/estimation/mediation_g_computation.py +++ b/src/med_bench/estimation/mediation_g_computation.py @@ -18,8 +18,6 @@ def fit(self, t, m, x, y): """Fits nuisance parameters to data """ - - self._fit_nuisance(t, m, x, y) t, m, x, y = self._resize(t, m, x, y) self._fit_cross_conditional_mean_outcome_nuisance(t, m, x, y) diff --git a/src/med_bench/estimation/mediation_ipw.py b/src/med_bench/estimation/mediation_ipw.py index 0fb2180..16294f7 100644 --- a/src/med_bench/estimation/mediation_ipw.py +++ b/src/med_bench/estimation/mediation_ipw.py @@ -22,7 +22,6 @@ def fit(self, t, m, x, y): """Fits nuisance parameters to data """ - self._fit_nuisance(t, m, x, y) t, m, x, y = self._resize(t, m, x, y) self._fit_treatment_propensity_x_nuisance(t, x) diff --git a/src/med_bench/estimation/mediation_mr.py b/src/med_bench/estimation/mediation_mr.py index 5811aa2..ab33561 100644 --- a/src/med_bench/estimation/mediation_mr.py +++ b/src/med_bench/estimation/mediation_mr.py @@ -22,9 +22,6 @@ def fit(self, t, m, x, y): """ t, m, x, y = self._resize(t, m, x, y) - # fit nuisance functions - self._fit_nuisance(t, m, x, y) - if self._ratio == 'density' and is_array_integer(m): self._fit_treatment_propensity_x_nuisance(t, x) self._fit_mediator_nuisance(t, m, x) diff --git a/src/med_bench/estimation/mediation_tmle.py b/src/med_bench/estimation/mediation_tmle.py index 0b90a96..21de660 100644 --- a/src/med_bench/estimation/mediation_tmle.py +++ b/src/med_bench/estimation/mediation_tmle.py @@ -168,9 +168,6 @@ def fit(self, t, m, x, y): # bucketize if needed t, m, x, y = self._resize(t, m, x, y) - # fit nuisance functions - self._fit_nuisance(t, m, x, y) - self._fit_treatment_propensity_x_nuisance(t, x) self._fit_conditional_mean_outcome_nuisance(t, m, x, y) From e9475ca74c2e57326f43ebd171237649e68ab5a0 Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 30 Oct 2024 21:26:23 +0100 Subject: [PATCH 33/84] fix predict_proba results reshape --- src/med_bench/estimation/base.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/med_bench/estimation/base.py b/src/med_bench/estimation/base.py index 7eb6f1a..a27bc0c 100644 --- a/src/med_bench/estimation/base.py +++ b/src/med_bench/estimation/base.py @@ -163,7 +163,8 @@ def _input_reshape(self, t, m, x): def _fit_treatment_propensity_x_nuisance(self, t, x): """ Fits the nuisance parameter for the propensity P(T=1|X) """ - self._classifier_t_x = self.classifier.fit(x, t) + classifier = clone(self.classifier) + self._classifier_t_x = classifier.fit(x, t) return self @@ -348,9 +349,9 @@ def _estimate_mediator_probability(self, t, m, x, y): Returns ------- - f_m0x, array-like, shape (n_samples) + f_m0, array-like, shape (n_samples) probabilities f(M|T=0,X) - f_m1x, array-like, shape (n_samples) + f_m1, array-like, shape (n_samples) probabilities f(M|T=1,X) """ n = len(y) @@ -363,8 +364,8 @@ def _estimate_mediator_probability(self, t, m, x, y): t0_x = np.hstack([t0.reshape(-1, 1), x]) t1_x = np.hstack([t1.reshape(-1, 1), x]) - fm_0 = self._classifier_m.predict_proba(t0_x) - fm_1 = self._classifier_m.predict_proba(t1_x) + fm_0 = self._classifier_m.predict_proba(t0_x)[:, 1] + fm_1 = self._classifier_m.predict_proba(t1_x)[:, 1] return fm_0, fm_1 @@ -390,8 +391,8 @@ def _estimate_mediators_probabilities(self, t, m, x, y): t0_x = np.hstack([t0.reshape(-1, 1), x]) t1_x = np.hstack([t1.reshape(-1, 1), x]) - f_t0 = self._classifier_m.predict_proba(t0_x) - f_t1 = self._classifier_m.predict_proba(t1_x) + f_t0 = self._classifier_m.predict_proba(t0_x)[:, 1] + f_t1 = self._classifier_m.predict_proba(t1_x)[:, 1] return f_t0, f_t1 @@ -410,7 +411,7 @@ def _estimate_treatment_propensity_x(self, t, m, x): t, m, x = self._input_reshape(t, m, x) # predict P(T=1|X), P(T=1|X, M) - p_x = self._classifier_t_x.predict_proba(x) + p_x = self._classifier_t_x.predict_proba(x)[:, 1] return p_x @@ -432,8 +433,8 @@ def _estimate_treatment_probabilities(self, t, m, x): xm = np.hstack((x, m)) # predict P(T=1|X), P(T=1|X, M) - p_x = self._classifier_t_x.predict_proba(x) - p_xm = self._classifier_t_xm.predict_proba(xm) + p_x = self._classifier_t_x.predict_proba(x)[:, 1] + p_xm = self._classifier_t_xm.predict_proba(xm)[:, 1] return p_x, p_xm From 43c8c51d3ae1fed95c183741cbf8d6d5a143bc56 Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 30 Oct 2024 21:26:39 +0100 Subject: [PATCH 34/84] default trim value for mediation DML --- src/med_bench/mediation.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/med_bench/mediation.py b/src/med_bench/mediation.py index be9e93b..7f3bf68 100644 --- a/src/med_bench/mediation.py +++ b/src/med_bench/mediation.py @@ -25,7 +25,7 @@ TINY = 1.e-12 -def mediation_IPW(y, t, m, x, trim, regularization=True, forest=False, +def mediation_IPW(y, t, m, x, trim=0.05, regularization=True, forest=False, crossfit=0, clip=1e-6, calibration='sigmoid'): """ IPW estimator presented in @@ -184,7 +184,7 @@ def mediation_coefficient_product(y, t, m, x, interaction=False, alphas = [TINY] # check input - y, t, m, x = _check_input(y, t, m, x, setting='multidimensional') + y, t, m, x = _check_input(y, t, m, x, setting='multidimensional') if len(t.shape) == 1: t = t.reshape(-1, 1) @@ -442,7 +442,6 @@ def mediation_multiply_robust(y, t, m, x, interaction=False, forest=False, # check input y, t, m, x = _check_input(y, t, m, x, setting='binary') - # estimate propensities classifier_t_x = _get_classifier(regularization, forest, calibration) p_x, _ = _estimate_treatment_probabilities(t, m, x, crossfit, From 163fab524a22bc68ba822bc5462006cc4650abce Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 30 Oct 2024 21:26:59 +0100 Subject: [PATCH 35/84] remove trimming in DML --- src/med_bench/estimation/mediation_dml.py | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/med_bench/estimation/mediation_dml.py b/src/med_bench/estimation/mediation_dml.py index d1d93b4..ceea223 100644 --- a/src/med_bench/estimation/mediation_dml.py +++ b/src/med_bench/estimation/mediation_dml.py @@ -45,27 +45,6 @@ def estimate(self, t, m, x, y): mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 = self._estimate_cross_conditional_mean_outcome_nesting( m, x, y) - not_trimmed = ( - (((1 - p_xm) * p_x) >= self._trim) - * ((1 - p_x) >= self._trim) - * (p_x >= self._trim) - * ((p_xm * (1 - p_x)) >= self._trim) - ) - - var_name = [ - "p_x", - "p_xm", - "mu_1mx", - "mu_0mx", - "E_mu_t1_t0", - "E_mu_t0_t1", - "E_mu_t1_t1", - "E_mu_t0_t0", - ] - for var in var_name: - exec(f"{var} = {var}[not_trimmed]") - nobs = np.sum(not_trimmed) - # score computing if self._normalized: sum_score_m1 = np.mean(t / p_x) From df342d236e7a925df5f632ada59fbd4153828e85 Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 30 Oct 2024 21:27:16 +0100 Subject: [PATCH 36/84] minor bug fix in MR --- src/med_bench/estimation/mediation_mr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/med_bench/estimation/mediation_mr.py b/src/med_bench/estimation/mediation_mr.py index ab33561..655768e 100644 --- a/src/med_bench/estimation/mediation_mr.py +++ b/src/med_bench/estimation/mediation_mr.py @@ -49,7 +49,7 @@ def estimate(self, t, m, x, y): """ # Format checking - t, m, x, y = self.resize(t, m, x, y) + t, m, x, y = self._resize(t, m, x, y) if self._ratio == 'density': f_m0x, f_m1x = self._estimate_mediator_probability(t, m, x, y) From cc6dfb111a562fa5850748d87845cd2f0b013d81 Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 30 Oct 2024 21:27:31 +0100 Subject: [PATCH 37/84] working examples with comparions to med_bench --- src/med_bench/example.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/med_bench/example.py b/src/med_bench/example.py index 89db19c..1737f4e 100644 --- a/src/med_bench/example.py +++ b/src/med_bench/example.py @@ -21,7 +21,7 @@ print("get simulated data") (x, t, m, y, theta_1_delta_0, theta_1, theta_0, delta_1, delta_0, - p_t, th_p_t_mx) = simulate_data(n=1000, rg=default_rng(321)) + p_t, th_p_t_mx) = simulate_data(n=1000, rg=default_rng(321), dim_x=5) (x_train, x_test, t_train, t_test, m_train, m_test, y_train, y_test) = train_test_split(x, t, m, y, test_size=0.33, random_state=42) @@ -37,14 +37,12 @@ n_estimators=100, min_samples_leaf=10, random_state=42) reg2 = RidgeCV(alphas=alphas, cv=CV_FOLDS) - RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) # Step 4: Define estimators (modularized and non-modularized) estimators = { "CoefficientProduct": { "modular": CoefficientProduct( - mediator_type="binary", regressor=reg, classifier=clf, regularize=True + regressor=reg, classifier=clf, regularize=True ), "non_modular": mediation_coefficient_product }, @@ -56,7 +54,8 @@ }, "GComputation": { "modular": GComputation( - crossfit=0, procedure="discrete", regressor=reg2, classifier=CalibratedClassifierCV(clf2, method="sigmoid") + regressor=reg2, classifier=CalibratedClassifierCV( + clf2, method="sigmoid") ), "non_modular": mediation_g_formula }, @@ -94,7 +93,6 @@ "Direct Effect (Control)": direct_effect2, "Indirect Effect (Treated)": indirect_effect1, "Indirect Effect (Control)": indirect_effect2, - "R Risk Score": None # R risk only for modularized }) # Modularized Estimation @@ -102,8 +100,6 @@ modular_estimator.fit(t_train, m_train, x_train, y_train) causal_effects = modular_estimator.estimate( t_test, m_test, x_test, y_test) - r_risk_score = modular_estimator.score( - t_test, m_test, x_test, y_test, causal_effects['total_effect']) # Append modularized results results.append({ @@ -114,7 +110,6 @@ "Direct Effect (Control)": causal_effects['direct_effect_control'], "Indirect Effect (Treated)": causal_effects['indirect_effect_treated'], "Indirect Effect (Control)": causal_effects['indirect_effect_control'], - "R Risk Score": r_risk_score }) # Convert results to DataFrame From b23426c6fc1ad6f35ad5167f5848b405221e75eb Mon Sep 17 00:00:00 2001 From: brash6 Date: Mon, 4 Nov 2024 20:26:15 +0000 Subject: [PATCH 38/84] remove unrelevant crossfitting in docstrings --- src/med_bench/estimation/base.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/med_bench/estimation/base.py b/src/med_bench/estimation/base.py index a27bc0c..fb754aa 100644 --- a/src/med_bench/estimation/base.py +++ b/src/med_bench/estimation/base.py @@ -345,7 +345,6 @@ def _fit_cross_conditional_mean_outcome_nuisance_discrete(self, t, m, x, y): def _estimate_mediator_probability(self, t, m, x, y): """ Estimate mediator density f(M|T,X) - with train test lists from crossfitting Returns ------- @@ -372,7 +371,6 @@ def _estimate_mediator_probability(self, t, m, x, y): def _estimate_mediators_probabilities(self, t, m, x, y): """ Estimate mediator density f(M|T,X) - with train test lists from crossfitting Returns ------- @@ -418,7 +416,6 @@ def _estimate_treatment_propensity_x(self, t, m, x): def _estimate_treatment_probabilities(self, t, m, x): """ Estimate treatment probabilities P(T=1|X) and P(T=1|X, M) with train - test lists from crossfitting Returns ------- @@ -441,7 +438,6 @@ def _estimate_treatment_probabilities(self, t, m, x): def _estimate_conditional_mean_outcome(self, t, m, x, y): """ Estimate conditional mean outcome E[Y|T,M,X] - with train test lists from crossfitting Returns ------- From b74bd36d05030cfaacc87b2a785a67305955d011 Mon Sep 17 00:00:00 2001 From: brash6 Date: Mon, 4 Nov 2024 20:27:40 +0000 Subject: [PATCH 39/84] intercept instead of m1 --- src/med_bench/estimation/base.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/med_bench/estimation/base.py b/src/med_bench/estimation/base.py index fb754aa..0d7500b 100644 --- a/src/med_bench/estimation/base.py +++ b/src/med_bench/estimation/base.py @@ -454,12 +454,10 @@ def _estimate_conditional_mean_outcome(self, t, m, x, y): t0 = np.zeros((n, 1)) t1 = np.ones((n, 1)) - m1 = np.ones((n, 1)) + intercept = np.ones((n, 1)) mu_t1, mu_t0 = [], [] - m1 = np.ones((n, 1)) - x_t1_m = np.hstack([x, t1.reshape(-1, 1), m]) x_t0_m = np.hstack([x, t0.reshape(-1, 1), m]) @@ -468,7 +466,7 @@ def _estimate_conditional_mean_outcome(self, t, m, x, y): mu_1mx = self._regressor_y.predict(x_t1_m).squeeze() for i, b in enumerate(np.unique(m)): - mb = m1 * b + mb = intercept * b x_t1_mb = np.hstack([x, t1.reshape(-1, 1), mb]) x_t0_mb = np.hstack([x, t0.reshape(-1, 1), mb]) # predict E[Y|T=t,M=m,X] for all indices From 8da1d741a9218f3061de76d0c805a20a10f2a211 Mon Sep 17 00:00:00 2001 From: houssamzenati Date: Wed, 6 Nov 2024 16:57:12 +0100 Subject: [PATCH 40/84] line formatting --- notebooks/noisymoons.pdf | Bin 173192 -> 161254 bytes notebooks/toy_example.ipynb | 2896 +++++++++++++++++++++++++++++++---- 2 files changed, 2610 insertions(+), 286 deletions(-) diff --git a/notebooks/noisymoons.pdf b/notebooks/noisymoons.pdf index bbe7b69134749c004a4c40afb85ee8d40dc47dd3..4d38723c1ae6e409fb862bc3554672333a34394d 100644 GIT binary patch delta 156872 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%0DS3i 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

Ql>c=m9Kv+}SUy4t5VJN|IHa z5SN0-_*-oId>6z$05$!XfZ_BufbQtQe}p)CP8f9?a-JMd$WKabEoNU3BRgdPp;}C@hRp~Aabb3fn`{G!4zTc`+FGs_rb583&a9MS$qaI zmYf9)YfMHMFyzo@<;d!DRSOqp9hb%KNJ!Z;V{yh#dqA6vgRg-I`m0r*)GyO!e+xLm zSW4yxAPRzemFiHhC%OAYJs4^sT`G87bVLxgnIKjmtqMQbO2ah)ng=NGe%#fm z!-jxTmCdPAK|63iVLl&L%h&^>e`AVy(b)=*z59p(pA-28Tsy%O@@FmN%8oL|rqH$G zo@SANZXILP;9^s^#>S-CvZ)<|R&<&25te=2D^(@@(hJoK#Fpi#LDWC0lf7%m~nJSx* z8VB^I!-owNK@uAD#~(b1R@dIuN~s`L?VVj?%}ZQ(F(}^lZ}!T*GD|^E;9_61$Vi(Kbg^(lfIC_8hLT=GT)B1ajgwIPwR{YQ zWbK*oQ}|_VGT2l#Wxm+Ve|D~WQ{euy1g$i*a9;9yw0|kk-WOFx% zG@aH#n^Sw zcGe_@SLDeY-j>Y$LL~u025RZUYPMX-j?9T_uTa?n81IG>s{hdHe*r;93^YWv*%x?s zA6PR^H(JZ8v%|CdjZ9caQmCOu>bp^=Y3DJ{mP&@T-?lwK!$xi_+_j=_4vTryV=KNh zklaj--x-$wl`+WC>qqDM*{Oh=nit__gduc&)3Agh3^k9QAU}pDOX(RGggSv~F*j@7 zC4W3jV3OMz$&F4!e_$d5UhB`i(`>gDa&$Pe58s3{#mHi2vb{>qbdf>t*pFs(xSL_cP@u_&p=%p? z8bRV!efijCATrkei3AThz0H_9;DZXxC=p@)m%Uf|^x^GvYlOs6PO~={5GDPk7Y+~} znTl~9e=QzE1v6u74z-JbhV!r1NXFJwpjoOSbC0ugo@j5_19uv{h{m5PbrBo#5Gv5fb>f3k5;d5R3Obsmt9WLcN+p->3ZgZw|R zE{x_CS*f}Pc&qaxr9V-;hT7RhOJNLXA`g`MMu1Mqp*&` z-9mUItB_LB3E>7&oj4&OEy-S?RqvTqSE)`?p_sz&jp!x1XihQ|VU^nl=r^AISL`p6 ze_0DZIYxgKE=)7@t3V?W#P5WC;Bk^trFt4BN>Q1Flt4))ZEk8>tgi->!f+rC%bfi_ zaA{;L^|J^>Jd$IGb*z#%+F*396|WooOt8%S@Yw|{fXd~hXfhY{SeoV(YPZAApf&Vh ztTU>$>rsYWeyQ7$b1WdFT<9NMB1X`$e}f9d1NPPhKOaM3G1#hW#A>{Z|{3y3IYI`ecjtPpX7 z`TgGfCooooc)P4J3i<&xe>OTX<4u8J>bYRLq=$)I)<`-{u}1BfI0{&Gk-c8Ee+eoO z`gW<3*n3Y*;H})c2sE6!z2l~4VcP1hW2$jL<|MOL=`$<`Sn6*ynJYEs85H7r^}SSDN`L^U=A{^i4G7fG?#Ij_=N)T&zqCRX>Ov6i~TRkZaA zX1>Ntn1fX;<2=K2X4DP}7pWMr#+D3h`I{fe`EC0P6>k_}dX*Fj%%xE@dLkyr&2rK8 zO=eysW5g5+R{gyG(oW~iSGFP^i`wC%#8!_=UmerI$)=NX8M*zuE@(BDe*g$O!oha3 zgsnQ~eOn`xkoND;pS$koJOG}w-;@N*xPcLI* z<-kHtgJ;m)+JG!l`V0dxaTq~KWid--?T%h0*sl^^Zc=1ro>LYovItY?E+9U2<3THM zO*o-rk}sz*W@E*(qSOdwI`PdWe$0k5B*Zlz2zxi|7YA(pYpOh=e*wSQ25|CmUAs-F z(WQU^eWn&lZ38jF^u&H>fv{G+U>RnvcVgSp+-|Rdjufi=hGz)5vmGWzNZLYEM%O-&V6e{XATO(0LP6#yDf4W0#X ztagBnyH~p;#M@ZvwF#ng>Ut~{5-Rx<^<;S3yAL46r+&IwkGuo(y(t|`q}^M=ov|IV zD7rvsh&+(-i2<(q2;{K$m&*X#$-GT|KQPlleS+CORx&ha>cscnJg4V97QU?kqDYpw zGKDi$#~XS7e*@UqhAu8zzyLZ;mjNK1((Sk-zrFw!F=nt5Kw{an*eJzQpp9f7(`Z(k zc%NVz*+RKLs^E!cV#gYEpO8j7upbD}LoI?}UNM_3Sn(uPunM>RH^A!8uL)gEYRqyR ziZBFG@jfr^U|6{#6a^P!+A2l8KLGp~7^#Gg&?{(Ef4!o@ln?#Y5f2tHYH1nCn1d)f zO%!{F%NV8EoDe+}^jYC9&dMm`!j-YmJWbG%7v3(%yMlGdC>=x)G%*0b(1+0HGG@4l zlOcSiJ_h-c;-#A9_!CamQS_y2W9{#Gs<%1CbA_wQ#nwYsD^$$s0-%%!4;wik_!VaEZACtn3EdS$$l$ zG!+d+LE|eF2xS3NU|s>Utj1t=*4iK&figksDZGFnDNQHd#~cDB7yUN%-#Gb{qX2iw?1HTO{ zf3b-p^`{d^K~ju{%(9Kg@n=+EEc=O<1b=3m040p#^jrWdQK5VqtZU!GK|4s&M%Hc& zppkioP^yxTsYR;GM&`^`E5@iTL{9Vt%>(=H${3rCSkp7d-z0Vk)6e7SuEwFaAE|Oq z{6(-`4+by+f`1HiUJUCN;QE*qt;xOijFJK?#58537X-j z&&-s$^#lXMFR*g&IwQ~UY6IM8lnoPxBNQjy0)77&9>B1ZVI{aG1F+OPGPxbG-8_y$ z*w-fmDw&au)%5i*X&C1S){eS&>@w6EBxSRF+4i#RMOG{QAoyX*lvOVwPZteje*$2M zqv6P`K;d+RYt4m^`eYEyLW_NsDj}6O7a!pYb9W1a{)kq~PdB+71QqTqcKJ}iR zoqxv$P9fnUlY!~pu-~$+8xn>E`iGI@S!V~HRdJC=R}Wez%;kDh5o5BXsu5F|3K)$8 zuX>A7Z8#~yl4{Xtvw!>|IjN`tf3z1`G*U<+sgA<}*x)wsbVxH^+UUrnWuG4eR?t0} zT-tw!v`-0-SfD0^lS$9EPQtzfE@_`7{ZM=C*E(eYd*=rbMUC~hh)~=#3uErUx zbn6rsBEYt?)W!ObQCM2=Tn>Vg4%(yU%T^f0QCm|$Mu2*t(6^RK>Wgd$&lHwg18`}+ zG0yWh!HA9=0CGesQJGsPf6tge6;lrrmZCMgFGur}2ZF*xT*|UA+)i-BLQ)d5T&PyD zTM=xP2{l2{Q}+y!2Y;^>Cndbv5>t|F(G&E7^m z3paDL+I6**p%4nZG+2aBRFv^-sjkEEQf1%~&Wf#+$O-`EWQ%^*#qey+kQs)03p8FG za;_gP$f(?1*x4Rce*;(sIceKtW_x(ZE4PI7T%12K*isE^LX64+5GZdjrk`iC40OYH zWENL#b|Zo%e}Nh6R3hC27Ts&4fvbqB=l;MR1)_}77RsQCiwIl}FDi4ajKVU9>Gq&X z{<6>~Dpr6DKRqjCgRNp0N7VXLWI>(4l{YMukYmNUJ>yQ$e_?}HRx@EBQ{YN=UQb;7 zf;MW!j3_MdU_PpnWe=}RV_jr538}>zq2D+SBzz1v;9pM{bn-DWh&fjI%t13YRD=!t ztbid@*>*o*P*f(2_`{`7DE&&RpAXt5s9=+lqJ-C-|0Fn=Y$3f}Yz}$WS3ok}J zRik6VS!6dwe{BrtzV4b0cP%Qh!xl@Qrv}NOrE(Y$}i?V{qBg$FOt9RyQ6LI?d2CT%5_jTqRpd*S!wZotXx^r^^N9Sss0@g=L@ z#APEULr<0wjAM93%EsC94{L@acQq%gH{hqhlvE`lWKl4gdEkA9OQ}4IhFxQE(YJNc z-xw5sf47>~@$e*gz6@2Y2>H^C!>9}43^MB!M99WA4H zgrum63>Bt9W&!~w1!5YX0{K|-1`zO{49}@huS#-(xS8&19@>bM5;hv zAhqK(uTx(ZOzJDQa?!J?%G`FcXOPi=MwbzWv+voL%Uo@>~lrZ8^ zVFISqVn!D!40wqJz)f|#mJrQg9eLHO$lH(;@1pbcjx%=1;dE{9x|L(>T8c?|-SO6v zUXC^Oap3V{TuHZ|-A>dHER?(u7Ncure^mwO&9+V9Sp-ze5;UnnBk%EAAp*tA;+GW| z)NP?|&c;#Q`0`*QI=HRA{5}hVZDu^m{0Q5|s&@-hTn>ssZj9k3hKqB~*t7t8r_Bc# zt$P0ndI>qe3!8l6a?mmYS>yD~%pF{y#=5)+B*L7~(`W{{!mm=8=@+9UEEe?*f7H41 z7bsmqPo;H;`v$HG0z>Lu_3SZ4-IIMqUk|+3C?)}D--v%@IL3-V^UaF!0~>$K}bQIK#A6VLT=&)#Wfq^%X zd^U%U^84=py|&97-R0T;I6Pj(fAEskr<4ainF&4z^^1<-4?JHF`+Ke*pKG%}2feLB z+056f)zT;h>Ba~4_lW)#gr7EY%U^um!lVS{;g54&5?Thyo18QcqrY}F*iAVn6m5eI zbCeCRnz5x-#*5=JN#u9Ix27(aK0w5`LO~s21V(zNF5AatfGNP&8-(%^f6p5r0;otc ztT_Gaw_^pPqes;HVg@F1us%4UQjm+bt-WU!cG_UVJL=-$z3 zfz@chdhI+G{d~Osu_L)niH@}|BHe4k&5hf)2CQvzby8bYc@&TT;vnX9HrV*k?g-WyPVx(6PF5U&2 z`HoqK6+$QzhYoenoXBa{&3KEVLtMweW5nL=sEzLC4N#mhk^E5QS!v>qv%TsqwHG}G zD-ON%io~sLgcexE*7QHb8=!{8SHbdzX@m-6T^8nZF^s|H!Wd=qe>W&t0sF;J3{jr= zRpB(GlV8vuoKV8hzuINTtS8QVVqXNcQF-2BUn9@((&F;RNZ62OVeSSj4 zywxA(oGsB})f?i=K(e617>8qAwg-zfq)eg@-}KxTO9f=f2R7~{gK`Z;b&~D3l_W8@ zDG2iL)sf|T;0c}px)?_mh=Ud*DhaE@xGCewHRkM!*I)CMe^hX))crren+y;15fzy9 z35zBJ?XenXkj07#q7xWbH`RIr3rJrqs+1XZ4IB*^by9Po`-Nig#cT~h;z8^>lEKs= z3X}S$cnC01Dy!SzF^!V`vz4 z#DXKMIiA+qBpg!Ff6UZ>h7G9Mt1O&m-RutMD(a<}TW2n4R}qkBLt-7}XkAHcj-w~3REOEiV(ixJqw0ZzP2lYDu~S^MMf?RpE+v^1yME(RZ~3 zA@X7$4#L>-p}ME)?g+R+4yjBKd(4SvX@_1n-CVPVJPuikso^OAC8}$Unh8>xumVtj zESF~P@Rugr3p@F}?Z;J_X?GL0QD620_c^S6@bjK@9-~LSr=mRtU z0ZM5#8x((4=H%psiPCtY?X!MJAq5Fs6{=CI(knFV ze}o=pL!MJLPQiOM?uWDWbjKW3_2D|&6{{TlZK#5UC*5oa$lwKPGj~QKD^}lSR^IVR zRu;CCNcT`6)-$p(xfLH_5IL`TtWFd4!~@1C0VQ!1s@$BTL|jlf`Mj2=qCi3xgWL9H z>j&I3uyqNu>R|7rZWz;pWx?51te8CFe+3HzFJ)1ffNod^N)^mC)4y2vhdg>P7&@?R zR{ZwZsxQ=<-c4jaFknJEICUhdkNuwh$qT%AM8hPox(jniwNZGfiuL~%R}XoP7K^D! zOe^d++F!;dgJbgPO=v?Mte|j=k(rO0>t#>HxJve@&|g z-QDUk4?Hd&;d#dw5c=upmfgToNnLz{k{+uls7fvXU3+B?NTEdu8fzXydx7man;q}i z0Aeu&jw3``4IgLLLvuUCVpCC)d%9>arWDO$3V;fnD*dpE|JVn8HT&Z&({?>FR5j2* zc87@D-3+#@ePJ)Tu{j6CTtnS%e;PQIC3YQ7+q0C385sXt{PPTk(Y~7XY(ig(m#tH4 zg=i@FGrYlt(nUo^Oix4+tUYo4F#&I|`k2U=p^J^=Mn^I4}tL)SU++ia#{ZC$HN{{S>9+Z_Y(2@n2?xe0uHR8%GNBs<1@)5%va zT~%2vF-}O~ZQxjhWKlsxe+9vYreEix$KSz2Kum&KXALf-<8@?W`v$u&dPLNUk>IXX z@%wz>wOdpwJm_XEiGm|LgTIR%6X4NFZ-F-oz&D(-{v*po$x5$FK+-`^LGE zHya&DBw`y|%KAgFffCY9#0Uo_mMdCc*FDT`Sdpw_aFW)zYbompNi@Xsm*M<8}T2lChf$Fy6+l)#}i zVl&zYw=kxpgX8fa~XV50HY%PfUxKVDx}W?m666t z?~ph)3yBzB?nmF%3D|JFr6ZCK-1K6hg}XC*mx=g9f9ckYf%ss2w>tD2l~$^BoTb`C zJ_IOM7_YgBjs8i$8^L>_?aH_~%wpKGFDTZWLS$8JN7CLfe|!IBF_Z%bkNWG#?&V^e zm@qLhqMSpiqaC{v_Ny#SV`kmqZ}(!& z237UF!{9aeU3!ie@E4z#3k2zO=0BwN>25D7@W93|Z&Ld-y>T(cMojEBDu$A*JPjI- ze!dR~EismQe;XQ&PkQ?gDqGCc2@6^5l5|ui&$3u68TKTh=91vizd-2IW{%%p006w1 zmx93h9F^(??{mU2-jPb<>w&FUVGGq^K+I`*<3s~c=I^o1-#c2%uCsNaxiU`_M#ARm zUdjiY=K93(OT`hCe5!*IySX`CKpewFYuoI3QaV|?e<0e@Oq1}y-m(N5aPq4ssxfv!D(`_U3ZSNvx7Vb{F-|ES;hx`l@dIm5iU7dqSo8Ue;aF`ehZwQX z!WQXre^ai$yB!Ny;r5uW%vdHjgyVB4h=6KE1;dVa;ynH$GTU)C1X=YUDHPy2X%w>osTRFS^HCzIMFp{2KQLLg*v|GGA2C)O3aT1CS|45}Ct~z0S2MxcMGDZh(w9bwS z+D(4ox=v@}Rg@eW`1wk{Kud+(^>HpqM={*4HQ7BG-X)be?@0+PB)^Q3|X?+W*ZST~baf5KQ)e2`dR4Q?fljnRPzQ;3#`(tMf-z9HITCQ*3c z7t&L-FWXz+&b6#?^!VVKg_@y8>tCLAu}aSO14>55zz(z8jW?Oa0Dc!1`!cwniRS3nf7 z3QTc{YU6g;M-@j|7Z98{f4_%N%(cB3g_EO8If^zcD0YvnK~Nw!T*gun>;cqB*rVZ+ zJ!l>$@~qZ_;=kws@7o!$cbZ8sPB%arC}|VmzWB?t8^e4SRwTAIdW z7>pI-J~`S1Po(@AEaJ?R*=CFuj>X+(=;)23UkB8Y!=MWIiK2j1#}gvTF;wRA>q(^F zh5etOd9{iU8dl|pf5B5`1`-#09q8Y$#z!Rk~1RdyS6JCJ<<5n4U$5~K&% z+T{^@(RUf}9(#SFuQE&SmRzc!?W`(?L4c?DAE%sQc!_Dre`d^1jMtMyHcU?{EF3^g zybM>TiP{sIlThl>en*BJu?>Tu z!hy*wzT=iTqjI9kL80Z?QZ{<#sWjH(x`gd7_JzaFf4P{J6TDI53ZtG~DKpBN?MO{6 zs>i05{<3YxYkE!gFscpk>=+o<#^Nyu-wjsTYcM9HhzB`^h+84B1rE_W<*>m3=~R3;|# zJWh%VlGFwIW%*&X?I`~uGnDbDEf=p3hBJuC4P?TZ0V_yu@EI4j-|!p>Bl>c*s_HEcc+t6f+4qz%}Wb#s_!7f`DV94|W( zfA)FM9`^9^h^c5ju`rDDD8)9o!OLR;w&Oq@E;O00Ps`a07@z^oB;#_agr+fe8DFN= z+)6jBy}_nFP*Pzty#e^JykuZRq%P%mLjAzn7EN&s%c?!jH}-zI?Z=HMD)aA&q~U4!bgdQC)fl-U7N0sTd3e=qJ=UaB4ks(<@XVSzDMW!l&zf!Vum9`4_W z>zS~OwMva6f!WnOM=$yT3Q&OTK&0X)(_4W6_;UAJKxa|^Jq9UQd6;mozhRpw&T?`R zSVycE0Ih2QJEJnUs57g_ykeX4Gg0Q+>HA>K#9$PjtNOrLe;ZBd3cF(hNSz(ke>!Bq zV#F{!0J_eSp&o*ELi7SXlz7UunvVe+MzH$1I1%)2`_$m&;*!R=0v|Na$k zdC291sz8g6l)bJ2s=GQhr`i1U=3o>XvZ(MWFreUPK&FO18}DvA0|q;1H;2SEe3#u zSH$@u14v<%GLUV?6;0(zT=HRGKN9XEgh4mmYoazDes=;o6ei@9!Mqm368Y_Kn}&`T zeYe&kc$7787SFMMt-TubV5mPC5Du~+@Un1W4gepTtH~u~S;Yo@n|0|xe<-w3q#j1B z94x2dJSKzo<}z?I~01 zMG*lGrvpz5n?+C`OmdK0+}+(BaFsNfnulRE8D29%Z~UMoRpK-D?stiL)nbzcpEp{N zf5{{@uK3X4K@S`f=R&Hue*-be2ug_dlo$;qW&s2Ps!OHhxYq2e6+$gZW^m`)1vg<`0NL_k4+Nj=Zvrd{8wtgUt z4*oc~JQ?OO^iI;I`Ru=;ZGR{FWS&aKuQC5f-`Fxa^_aQALTF(ff8A}H(a;GScu>@f z3Q_^E3;IRXr7JG5z2JUA`2t;z$?Qj^wQEvCNOvqY$~K~7+PjR5N1rX_1=%ayfP>8O zB-@l4T2g3IvV!bVamm=k5A`@5v6AOqC0LuZ59s3)BLJr^_aWF7#k@5X!jvq0#FpkP*BmWgrqGHQw*L| zROl7E$+4&zj;d;k<8A?HXZaA1HY z@>UdEqrZUd2-y5;EcL4aoiT_p+Ai?uVUU8Gqz+eIs9ziHmbgSl@Y>yJ#}^$*aRWw50>+Z z==FgzsNz(?ZN{2&Or^TM?Wd;>n-WkJf4VLvHeqn>T04lPm}}h`X~8Mv-&@WOKayJ( z1~+Yi5q@99&-${oKv+0AjaKW~A>!GQoNH*crf@O5p4Lo;n%Z);Mz3cg|^iO3-EDNNb;@Zk}czF;2*mC9P!BP+g^hB4HWdY z@DFbZG2I#-0FdV(#j|k^jKEZve+*P$LslJf45~|Y29UYdy;E}t#At>d^2K5|7!hM@ z35G#uM@97vDNOp}yryZJPOmPR#_9B46!_WGBCXr4yi=K7utf6i?iVfjI zh6Z3vB^lSH%(Z=P%eXKC$yggUH7$b+vz4%=i=7M2r%Gkph-h$p0V@>%z%l*;uPStb zyJ9uXN8!)45z9uQ4Z=vhe>2$hgr2`h*C`$i(7OYZgs$7ThGk-G-QPx>b z7rr+I6&A)jts~jj)SLjXC@GY=nA0r02@CgtnGpA;y9(>x#>$8ve_!}XvB+8cCO8jok_Jpd)RfU5aj8B3m zUHXN`>BN$4qI3MN==5wth?rzK;1)RD^$jZhzYkx9yHY|;KOoxL!2Gpv#Q{{OPOqB* z2tqbi(`?uBu#4CSe@$Hw;{s9NafD8F#v$7(F$wq3{}A#G>BJVxaIrxpkun{q?G%w4 z@bWLw?f<_=X{X>-PYVRfp(D+U{0`|1ZIPodrLeB2+Sp9R?x7x1Sq+HUFQB$=G*qlG zZWxil`YP9p;gGNb&Eks3x%%k|_zXb*_FHNgB!y7t#tAkrfB7gybYr(Jaj*T@OCU^B-mnkZZ1uBQr!xa$ z59^t;lv67PV7Zqwc$o!Q0OZo>3t44MKY)^wiKp2072Apj=RM;xqFCXX62oJ?9u|f- zKri+Jdg_=Ye{beEi#`F-&5K`(LQ=JA<4+rmJxRZzQxLmKnOLx^H#~U0a^OS2``)N> zzp14CLq`5slrxaBcs-}Kil#9_Y!{2rGefAYI^Q*=W zUNJY}QjM$SSNF!bTmAYnz0TYv>cQpof!nud>0t>EQyLe>WfB~|Qu>uupI>IEc9O5C zo33-jfAqWutcCT!$(&kiWL0qa9m|+G>fx#Hf2()sB4-sSK_P0?I1zWAqTB zdLtpNRj~g-y%^EcSlN)qT&186cs>E1X)(w5#{6%V2Auf^@<~Aqb0<6l#pXo%CKzT| zXLi|TeTF4G5|1OPj>R_;^_^V++NO($1^^E-f4ov9z?Ps3;6-@(JwF?wP7Q2ZnvoUob(S)6?r{vTX-)$7mAA<_De|KvxOqzP=zT zI-qxp?XW*?J)(ocVi)~wR6_WPk@qs$HIt5^Q+A6dws59;CYQ}5e{*0W z2aB&?Adh%irXxM8^VmdX8{XPVR{oEFz9-1sDi1B3sY*muLD~%QVmnA#?Qz=C{;_K>Bp!ud@>b%XItD1%N`_fs|r=& zm}#X0573*%HU%L{wseK=C@NGoe>N3#2!vAaPEoaJ@tJ8hOw}7NbsoB3$M`{=ZWtyP zVFxa;l}Wa$8Y+Kv_BVlK2KG3-vW3C=&Vt_$Bp6`wJMgye7Og^a8y8kJKfmj{zr&}% ziRz+pnCh8ncCsL<84r9i(-I3viy>l$E;aFiUjO$t?E|Ssy{&D_Aa+@;e>vq-Q{)Fe z88~bVW7SCNwlmsNJQ`Mii>H3-@{!YD@NiY=F=0VS^5dJh7oL@gu|Tmoq6)YQlPDhS zj%nX=ti_qB^EI1MZt+~q+%)E*P?nGWAUzI>HgREySs2RxjK0BJAiR))7{uTW_%7Jm z0X?X;dQ265u*23VDi2?48VfTTai@HwynaAxr> zi63dEe8$`e%Td7TsMINOcyGgclLxAAzZqLBvL-XoGiBDxLEX+4nHQBoy`-ysaJ3h_ zl*0Bn3X+Vj;O_I=f1T-wlEYA<0oFHa^Yn@OA$lSLt+Jwookg886b@z@Xea>j)>>_J z8RMW~G5ch3LtPxGyJQp*a;&IQmACYSS*Kl7;000RE=T6u?ErU_J>BJE0mzyL@MWt| zz4+?DDHKME0o3-u14(Cb%b1*4z@nO}%&tMHgMp07mK(wkf4q>E6#>;myAUA<9BnRk zRZ~@6AwvQlWda0&1ycU2*L|>kCyp9p&NHFVZpX2vhA~Wu5%3UOkyCwu!G#NS!N0J? z$X*nxx^$Vu9$}_i=9_4gCfqu-^C(}aACWf+CkobDNqST45Z^3%-!Q;?IcYvmvt+q9 zvPC=*JLmx5e=kM`8SP(84l5d2K1l_8*d32X?Al)OXe}NCk!EjWfZCza9aA%;qk?f{Kp3V}+FKSip%p%vn>QLH zanY`w4zi^X!S?BYj>Xiz$4HwBz%3atu2_zyEGv|1f1J+@EO?O**pzK{d(j_4c{Rk8 zF<6J(k0$cO)HVS>(4xna>y(qmmfJqiP1vbDq|Erk(2p8hb}Q72o#oK z|6_sgAX8TA!e>*=MM(OddKJWd-LLMJRy4ek66y8hg!an^5BmMYwNi=6(?k=;Jto89 zV9!qPe>;Kr_o*X2X(-l)kr8q%B=C*ns@Gg!7SWUNM#%VuBI1jvh#OD}*Ihd~R$QT3 zNW^8gHf!f<3y}iVur&GZVq{nsy_>yb95yzIS0J&D1zj%(;fRt=Mk@4%`vsGZNl;gc zRgD!zaAX5Uef8wi%@_wbYCLOauH>=|{jH01siFg?vYk3$8x4SviY~QJbLX>xb(%U>T>H=n z8Id}Z?BN~8HPjHQ01af+6ynbrHc?a-s`S-0HKkWx~8^rJ%3&a6;IVy~B<{|60m$wnPIWk1EVjA9}k2zr>&sf<) zNw=L^HlXsuuFL~OK&&wJeHoLISsXgXe-Lg#;p`Zlc{Jz|?JHz-&V#^LDWeEa6EZ6k zo+{0GS61*WLG^|MPu(@D5g|;I)Z@1X(UBYZhCwWwpaTeSz%)^ys9n!#gXMhjCa|kO zZ5CoLCx|&!ttH*C_Gx4k6;E+Q9_Zdtdn)XHl>dj|Q@~AA?-?>Mq(Jme6Lef`&MFppB|K2$(SIKra#rZEUP?HP96R5;o2Sl&&$7 zB~ze`Z1t!q12T?tnu1v`%r{VGbmxF(H{97H9EH+9WeTWhWkUm9fR+pK@=icN33E{JoA!F4eM`Ph z!_4;Qq13PM3@!OYHeClC4@YdNV{GVpGzRqg+zJPX%1)p-xHX2$e^?&&Tu1+O9^?zD z=bSOm2*Ykd(kLmP9WXMD<{gWLF`(5cN)`xxo9$ukHQL27^sV6=fZW7{0T1LB(%Xc3 z7b@=2)&lsDEs~k7i@w}MiHj4EfCw-bu+s%5w^C2z!@|6m6yFZtsCRR9!MmCj&<5Drj_D>_#CHD~+_WRhiL_LGgQ-6ciqi z0mw@_ zYgbIiz(LxZFZ3j`MZ(al;u8}Z@&reU4N}}m(4Ms+Im|(mUy>b>>kU<=;AakJeZzvY z=u08?`+Cn{FmFxg^oR@+#gqkeYA+-YVN2>UL8(gUFHWS^Y2U=A@H9RvFlvU^G#fX_ zvk=OUiuZsRe+o;L+Zu2Q;pPHL+!%`Du}NykUS!xr+j}C%k3bZ%uySqTj}w3n}zOsr9s`0C9@1~FVN|joWFX*aK9s*4%m46)~Sm1TGJd` zPhnv*pn&1(y%`lH4z(`$P&Uk1SEP!t^9BgR*nkT@f1Kq2qeR>aU9V$bY}*iA4?;eu zHn%yKltu;RMq~OvVF`Z(r1U_j4cU!-v>j5)T+Rn-9eTy!?6+7ujD z08K!$zp?D8bLklv1s5Dt3dFwfC)9qb=t^O8bwLO1*juZBtUMF4!(w7}90Tk|gcvt;X>VLC z(dZ`Mv7N!XEtbk8KT_YW+r9WKyf_BXSuQG!u|4ajgMWJ@Q{%ZcIZlDc+>9N7X3eA) zNN+eH(2lY>p_MbBt0NQBR-E+$1Vj@VGea#2{C5T&cvps~G>l>O2nk;Gq*qjf1&f0V z!4lwW*rQtycrYmN{5{Mtn$=<(a-@wr1~M4!xESwbU8jWXT1w^)WBS;ZF1?U>`Tdx? z+d`_HL4Qus!@;*AES47CI+QOmx#jocKdLg(ZrO1Gu@WQq^~BXwuI)bK+z}18i4puH zA9WK#Szs~vB5WjhDyxr*>Gk1i!u?V*S?>t$a`w4F>;va#+o%-ZVD?|GqlRoVDHQG~ z?J0?oIqedKz|cgcj$nOuWwS)yin5XNHA<{g60vi zSp~FV4fz|~ohY66azuDWjTC*g)!!}MK;AhZu(_Ktk zK~L>M{2JLBz<0_AX=O1zPWaK5Shfgkgto4>B!e3!dkUAEt#P3i#4jwuz=k?E&?3?e zOn>Ee!+`}ZGWsTX^=bF=NDJB#GZx#kyb7SEW+yu|5DJnX^`g^&ni0H%WlpzZ9?agg zKQ>if(+O94&y~CKQ)5eC0@sp@;sj_Q{(6k7I z0y%jF)+!A!tBa`qK z&3O{~2k2~U#dn2zESp04WwiL2 zYZxZ*J+vSURSS2`15tib67Bb50_U>mSa^>C{Kk1E`7mn#n00XBa*9+55-+-d6&yiC z>U-q4jlW0-Ca^W6N-7G4+gdg8W^7i@WyKqb4;AVfct?fF>}IQzaiQgR*lH@rNDwbH zm%yf?rbck@o&{s2sgM$z8z8iz4}U=4pt!hEPBk*%#0zr+YSa!s@i6(c!-ziUy@$J3 zpFex#+5ngV+vF@&uwGqx`FMX1UIUQ5<)lYbG0@H3v!DS+vgW6_}MQ^YaG#5Fx`RJc{CfQ9Uv`5wA-23O#U zzbsuALko%2woQe9sg+q_K48T-ASC<+t3x3FmdyVM-yNYrDm&~Y$kKu4f>8)}@4`Q@ z!Q$GCpz|e z>}2c4)Fa(d2&X(0&WbXRY>!p^7T4*VzP@j^Yy?7Q_1GhOx6e2;rF0)SY}h9E`+C^? zE|nDaWe1o61=+@=6@muh>>0hd7&U~>m*S$YcLxFFc~XkS4ktXpfwqW3wMF{${F#r$ zvR^(qC?DYrx_``}Sdg141MIjETd05PN$Jlce$WnbEG&J%=`LIu__z!?pVpHxWPs^e zLEM(>4tMctJ>+yTx9&%xY=C@h_Q>I?)AbP-N=)?u?6Ix%dXkQf%u2nbP6}G6x}y}L zfD^)n;$v%reS~s+d9N$DY5fwHbv>|f9Wg|UF7huX7JqvwLm%vJavIzV3!VK~OCG?z zYFX9R_KQgtDM2?b-0T&Fe_+AzPj)w6CM{CUi?I@NdytQv_yU?#p{$^Aq1l=^JsU3^ zvK)K<7M&23^y8+osuM+W?6^txc4sgdH)l2rQ)|P?r&>^T;nt4m(;XX68-ptZ&&XBY z5Gtfs!hZpL@dj&P6#%m0baCW56j`Uzpb_idU}b-c}5VM@dqf- zl@f5h3l{_+nj7ViML=TC-Ecl)OnT9KRQkfi3?R@%pTf0ukBRXBd+0nOB3$jW;Z6*e z0HGEPm2yVA8SDVYE`9GAPZYQWwC~_flEe;NV}CFO&KHBi4vC-OrnA}J800{JpFQjo zW};6lMfKNAC^u>M+*NVn=@+@0MW*rSp} z*EsRYt^6W9IWr^M4l_n2^$u0VpFTp>r8+`Vd-ntfjEgQ2C~1 zj0M3gbEJpZfmszmhO=LBVZkNCw8jT^9jJhUg|=vo!5?H#7$|F@lOq%D>~u*ssN^Fg zv5+MVeJcaA-3u2gItws2%du0|{WXq26SLPm)#K3VWIn}b6sN2 zC-ybWp1N~VJo``;ttD(scx;D}1XF8ZS1ONmQt}1k6DE$bbNX=ofVK%q34h6rc(Yd~ z3AUOn2hEOL^lGspH6;*@)s`TwniGH|7ZP)EOOV$k>kDEJf;ARq5*NV{b*rieKRrf8 ztWJNVTyX;ILX{b3;!kX}ECNwhT)p4fE6EljG;+y~wb&rr_RBq}5ZKfaKbWs!K4&se z*ET9aY($0!3mIfA&FD=`QGZ8^d9FB8So*XaObpJ!Uc`qW9bJ%#J2_2Yw3@u87sEcaMlhl z7cq)yMc0v1yCq_GGs!P0fuK8L#?waOpIam^Dc$)rodj|oeSfE7*Q(ZI3lTmIFxFyV zfoCLXxIPIN-Z*?R%vJa=t=SPWX2O90SLD~fq-vzpPBd0~Y|&P&Ry;g{%Z_*y0Lw-- z(VLTaBQsOeGKmB;o8y&o!!3Z@rbloax=lChw{sc1JR;>I2ZB#?_HIk2ELR)JUYX=7 z6;+i|5wRgr>VGuMKS^BvSau5ENw=o~HN)I@==okCu7J2==<8uP#u>FH6hKN?&}OX+ zJ~>cgwWSm@j`@4KP_H*O+1j=VW~i-+fxkk#i?whcn2M=_QDDN|O7~xDDDz#6Ww$a? zbjlsvAy>=|VdVmt`oJ;}$2g@Y^vvpnGa8Tbi=C`NuYWl5sKlul`Nw3d2*(7?N)`D9<*oCVUx8-lRHWdgFhNW7a z`J53j|03UI8U!3uVYQNXE;CFUo!t)I!5^KZ1=U41C# zl7Z|CJ>`ahS~*G$cum4=0YembLOhsTZiF!LP%X;bI;J2tNDoziH|dJ6aNQOAXH0~0 z>7YeWv1xZJ>I6K~-?u?-vVAFyXV>S0=xLg8wSOJ*Cl|^WY~I9H9NGj65s1BE6>mIS zL#QbV7XuQGSuM6h-fmmebjRV(o&a~y+DFqu8;anVbN@J`{CXmuI2DPJ<#T+h2MFP{ zT$;BJ%9&}=a+)%DgyB>g9ScN!nG*t7F}$Pey0bmyZ5JH|8L}2eRs*XBQ1`KW`}OV1 z*?%YqOf;yQ21ruN+r1;!!knOJF$<-GkOAZA3lP1c=LA3#Ml2+5?4FSB(^rlu(W^Wx z1f!yWfnLYvcOkadZ}^lDke}pGIJ{Y;VRkeS`zQSG*B=tDBYWXAyR(s3is>lo)c8Uw zh^}{BOATYB4}t|@sXc_?ekX>J>vFX;`hSM{e>z$1li1$db6Pl{2{Jf4{&{Wd76IEF zZJ4>>Vzjg@tf?0lb{3_5@ZtfIt6?8x5fEBqrF4J^apDeE0e$v?yaa;?AT>%*FEj;V zw5Z5ru8`eoLzx1{_k6=H2xE_8ysGDqAiKKC^AuRoz5rX#R2Fqpro=~ATA>s^M}G_* zB_Z4^s%nSet&{4S$BUy|5wxf_xWJtPkDKw#2o)DWv~Yti14Q-N6Z{ z0Ee;-z0&<5DqN7M;eJH@tm!r%6!CyB7-Z|CePYMH{TO!^w4rBlqZsg2RRpK|8rI{f z(t+Hl9URGJNX8wr?F*oE#qbR*7&aEgniLH!-q^)r8i$QteNssdNIhW_K7Zp2c%ZJK z6~j7j*$)kD4kB0~kBea{2dx6Fd}GGfcCW`5G#&sDuxV&<^m%*z1LMvXB5|QssT>2g z$@qd!hqn7c2L>Nz^VzqGHqr%q*B$w`3qU&@@J&;2CL90R{+;4#=g^><#vlzPrGksb zj}Gf#09r0+Gy1CV{uOIbYkyd{RV#4l0EJ~_W@VtQb!&-n&7w(PV@qfly69bT+cbN2 zc3@C-zdtTF2?ZI0n~YpYS?gFMFGf%UCeEvG8(b1HK785eTI;XR-TQi9zu#tQ^g6nt zLrE@>YUEAPi}<(&Uonkv4Mf6Y&o>}PW#fB!N7JF*xZM# zcD`B+v{JI2?yv@m<=)0Z$`KJET>|d#7sYy*uVHX+HWPDuc>@#Ei`R%nfv8fM*6TE7 zYlo1$m854H63`ydH5ONBb7QL^SC`|i8N4PfF69)cz-+bC4SzB3LTx6Y8h{XqQ8mSQ zAAPRzeyDPjBMlVP=B|KJ;P7O~mh|SQypvK6<89nwj!?~+H<1w3IFiV93 z0wv*dgP~n9EY&l{2{y`kRK6Gwt&#y;IebEb zQCOXT*Vy>E;D1m#oJ)ePPyHh0LBoUu${MHaFIZa3s)k`XV^vY?=97+2;asSip)Ve5 zQjEi#QZ}~~+3?LlY;k{ZhPcOWB!&aIwJ+rKfX4q^#wUr=FK@@w-bM;$;~>cmfc|Eh z5M;yLaiTS4_@K{D$W!ZkDV3-JZCWQUeAQB)%!js_JrsIg@dTCo6wM&J03e53e$!2W z5d(W_dw+2NpRazylH5KtDskv~bvSXGc>#szCl2xpx<1@x9ody_5)zpPLfjXWC5IwV z-iw>eV{E!67oc2xtrT;$dz4WDbL?#A9n&Z5g^kvERk90H1OCV)7rrpr(iYZjt=OLS z!MF2I&}3uQ+9IM4U>B!Zg@F0E)S=xFGRClLOn-e_##)zU5&P(yHi9m_Q;@i{>yiH( z=s3oMG?Z6r#Q_lm9IRq{GCV&z9vGYM#ylPTpcQhlg@#)auMES`N^*jtd*d0_*bexiTwKJ(szYr9&ZHZRq%P({p|5X&L%&EM>Phi3{^YaA#^L&M z+kdmBWY24&n!f3kbJhg4o@R$V+dPWkB1R)FjM$1R8*yxUhbfR;j9U1O;f|yQ*VxkrJb?TvyRmL6ni%Jk}Dj*Tn zP|fhIHO;*qFE{4$y{dbI&U`uda08t?dVh%CvMOpV`rN+k>)P*$$Xno9xfR*bPsK{Sg3~^ZX7Ax!6SOpXUyLzG-f^-+y zV`NG$R8kGs6wbxM`Jb!5w zdLOgDcYD9d(jabZxL&6)W>`Q|SdscuTK5`IMP}J`IFTZ?eSq#WtyV1I#xD%oF<|N4 z(Wlo_bVr30`GNre<|uSw=*UndLNE%uL!(i8W(bb>Em0KvTgQMMyb1Kt5jHdX(h9;z z;jCDvl{SeYDTI6d`|5Ei@SG1 z5%hULS0MA6F2|iOKnV+Vx~w9gE$`=nzI5t6WNYK>4w)VS1zqeg^#_?G9)Ga+J9ePU z;G4|iDL8HVjv+Oss;{29VP336u33Tl@F|o5At4k$RJ0OR*lmVAHj%+#i(?ukYYE0P z%G-z^kz8dQJn)W>HW!SA=|iSlL-{!PfBo-0jp|HTu#%=NSq(2D(foAazkX-HRhszr z7^JU-nfQ?6L3wdTkww+{=YOF%GBt8IJ=B;7Y>6l391X{C`(=>RwstY5Uzp4=>zm^! z(zk;7V7ripV+ghsg7Aj3HLg9+aQw)z;?Tnhaa&vhsHJVhNLTFKQ)~p0jq;~sLHi@+ zSRzHAw9~-=n%r1aEAJwDaYymziHVhN-HEXXy24$zTKnv7{pH=&QGXll=quX8VgnrF zK(87rYE-MbgC9eT&#q#qnzp#j?%sw0sc6{G10u1^h|AOaE&MD;l@<-NW!`dU_`8rv zi*MV?_Usr0BN>t^0Ot8}h3;kHt~3WdB5nvgP!g5o3?*3bC#bst`sY*wuVpYO!jYlQ#4l=rm+V|m zZv;(}n5bfJP%`udq7sFzj^u=5Uo2zPK%R_b843m)w3yH-nK!JZ+@%AoL{3w{6zG}I zVBD{_a77G^Ry|`!+Kt`wq6MusoImTf(e;leKFKzY!tj4p16<6jES}xkz(m_IQ}sP! z^y`+O%7l_BCV%dYSa|0CI8a*n*mTDSQR!hxbc!#WW*Ac_M8Hu2y5x!~ z*8Oferp=91=sC^YxTcrKB=GMRG3W@P;jC%}OqIu4t`+8i>=8`LtpjGzBX&2H=2KWt z(Lu(pR#yh&9(;sUt&O-1yOt&6b~$QxxoU^$LZTcG$AA7t-!%LHEJUC7(VwC!jo}ki zCG0<)CBCceB_|!_6t)EUvh?E%So2O(x!|*zE|hyPVpY6zm&Pg-_IBa%UyT39!zyAq zAG|<98yCG;i@=6YRu}Iw>eqG}n7UU4i7%$V=uYAAWMv@R#$rG-V)+2wLkujJ5qrmH zVjiD~P=8?!!&EF}(y{~h0|j#w-EYXJUswoCYui_k%`h!N)9U5vmyH>aMcACqx2G3} zu0dq*uH=<6YTpYSzG5V*K?KYkH;|l1>*yC4vPjkGKUN}((>2xul;m^3qO23cs#xr= zdg52x;5|6wnTf!mUrfCBP zmwJ@X0)~6?aNT(P%seahU=K%%7@^3;2>*Sfm&Mtt)ziu-iV#WQMJz)OySU7 zygf&PrnJJnUMB?IWK$h${<6>U^1QGI1yWeBY1JmQmiwp`Tj~oC5FW0Gy=@Eq0DPW> zIeR>0-H#0a8%5E5Uah^4FHG24D=0`NVt-1Xc3IWq&bpD~riy(5R|3ip2;2V^3$OfP zkbjTe>*$&psb=h`_5v}kW7$7hI(qygc*gL7GpaI7Rn=a7}u5Rg%*YXLG}{>kS-VpobV!8 z3L3gtGK7Xx>FIK6$WO+C9lY9-Y#oInl^uE5jyBBJ7L(p`7QH>JXsGMvN^mHXcC*S# zsrb@cr_h|3FqzVYSb!f)8;0nX$A7ncDNl~?bv)XY)&X%z*5-DogF1e{b4TQ6#9vxL z2uex22`N~ly*!^9W?_)TaFD1y%yUcajss!_Fr~vTFUP|J4P?u$ zEQq6reXU}7Q*S6*edh3)TZ5l^tjc-Z?^KDEZe3PoZ=ki2vcGU;Bb$S0q<`#AmnjNl zSZ&8%I;;zz)SXJPvDxJM8t*ltZ}Uv?_Cr{2;IwAUJ7Kh}*Q1^*;?GJQ6-eE?Rptq) z4K1S!!{Wr?gKGo#3Mw*vPQ(mibeZ*;DZpWHZzn+s*ABgV2rpymyODj;S>FZCzzr~t z0ZrKPZ@{^*fY*)lHaoygaDSC++;T2QD+_aIsPxnfsG&A=kuQiB50xXT?P-rP{j$8s zte>RvzTO&Y^gxujZkTCD&b6dXOCUz|fw^Pw1>~Ru)1)e!;S+^BxsZ8eK?n+{s;I=@ zVIph4B^Q9`1Cm9cDm&f_uHWT(HmDT(fNeR+F>a%c&Di- zSjZC^JaQ7%3KQQ!SXThwmqtVM*G9L_J$a`NbW$F1wJ-OD@H|H8iNi$ zwl4Dw^-;h10B`ucJe)QSnoNbPp4*X)RalRi5{zuuwnjtq7hwR16J8iFSYU}em6p}hHGLV#o z5evHXWA*ximVbxKu$YV?(ZG}pfDvIK++m7zRU2E+(0K;U{Xj=jj1mLh13|7@r3i&eLYNFq z+!(?>Rr}&dFpg1&5+)?7S__r**#oG+QM1=KJ8dUZx5Dl9XzpJYLi`zQR{-WwsKa{z zvlAb?`uJg+ROGQ(fSu+L08+ z@|77l^pI1dJr1UM(S?KifPVoUn=r43lQ&=tR_b9y8UZk2 zsai~|(+7v)x0p3^S0F&Gsy<9c@j31Fn5s4#K_KL!fPWUxz^es*v2168+bx5DaPf|9 zi#9e$85)H3%F&=-)@h3`#q7@a0TLGj3^5r*MK0vYB3r}AOCipZ5}h7Cyvz~OJSom8 z{K+596FF7DJTE(@y@Ohbj+OHKc;uw4yelbJgitoYgbFcdV18E;j}7gz zT)P9b^?z|uhKb#5-8%Bzk@HAzM^7Pxy9(c4pSHj@)MGD=gRv~pyjN^>1>aEL42d2# z0X~41tI$!p;5q2X@nn^Z;KJW;dN5& zqI4WjC?0f{iCOz}?0UgexW^SQ+7~!1bkz&=$bSkROobf$!jurDz_ty>Bio^jM8mwV z*kBv9l>!~QwmPT_)j@>+^*eEhVMwv@7s2`I;KhrnJ#eO@NQwt@v#%@k7^pRwZF3<4 zm0|KU%p&z_@Vpahio(=|mvn-Oy*-zNMy`98^7*}j%1!QFlx*<}#}q4j1hVJ}PBPI~ zSATZcr=diXnE8X5x17j`1=O1*{2`WM`~uAenOfS7vBWuuT>Yn@(lHt4LM6BGYsh+| znTak=+0~j(Dw`0>3`0^YP8jGfwe7MIeLX-1;oJt@H`higL+As{sswN$1rf)L4bqdk z@;I3)^C6(>z77d~=uhbzIwhP-RAhudF92%c7gLVmL{Dug}%)Q03CQGLdW`opE zmMVDlbcLZofu&n*A3Bg2)2CbeifD*p4uCO*M7!An7spNXhM9e_k`Rm!xU;w~H-E%C z#zzRr*Ozf3A6u#}I#L0YtMRo=D<)}tXE3BB6B80Qk-6;cW?D*kE0LusQ%smkGQj1J zX#-zLB5@6LIx>*;0K+W9n_?oi#rA0fqrPda+M>*0Uu5eTgX=RWOm|&DhMJ>IuB1Jd zib9lufVJG1p!HYy-YK5N*d~>nCw~n9moQ*4bO|9pjPA18L3lOV$Q?a67&~DkebAz} z3!T~ZprHVQ#(+yoDQGPjFE4$Kq9lXKputo@8jDOp1F`{&hf5o|LuL>mP(h)Vavlqi zVeAQ{4xK*?Oj0;W)W4^7rOl%4`{uFW)F=8RiTw<`2!0RXpZb+I3o7=iGk+Sly$T2s z1p>?k%wL9hO0J-Kh=G(&j;56(`P*fVv+%NkW{K@*u3gjZH`v38CtRjSa&x z&SHm$n%a_US(C@6%sPg5#DCDcNlSlY!CNt1SDS?)?D&|od^t82Oa!#V=yX}?fs1|X zGLG>|_~-%)G>C{uIVs^m{_T7}%&-D8Uc}XexvV{aJGLs?mjm66;~JFddF>-W!zV*B zDy;8t_SR+5$#NKMpj)h>R@~VXNcr%ais26yKo#A3PTYA%p zGLd#oaaW##xxw4IVR1+6EoXe@sj)U_rZPs!pA;xx&{M^4SfLipJ42HmmMr9Uj2i+_ z)>LWYp<>;SZtJZN)PMJ1?&`|vnIKE&v3W(xqs-V>lTj~9+_?Ziammh|ohkUD%np4= z`f*5a6dQL9vle4%OkIep;J`3Tw<=WzvJ4|Pz8)E8GBr?=SvSI%idFrp9Gu9#khL+z>VE70PL%xcfH)$fHog(3*6u>O^}N%#^^g<6uvM33i}ZaJ_Qlx zpZaetR{W_M{(l7GNz89yBtU@zwRKCMM+^q^8vTDoMXQ>-sfm>I%c)NwrV3naBn+S8 z9=PD`9&6Pz`_?DnuAIa)Ju-Y+YS>+~Dn+&cwhF;BfvBk_yTIQN<s-Cq_al$dRFcVXg@Ogub=!K%1k zb&u*}=zolKU8=D-2pktwx*4!Nss40J^7wRYe^dp#<5fTtnZ^)$w*}j!_$a~Z(q;r1 zmmAzrRUaGrS)8EaZmuhk`lq=oK5&;{nJxe{72Ppfve4-$3=z81If$pZz_Ao>ktXP7 z*JZ8Em~GtgDr?M*DoSHoX)bBq*t&@8$K>eikbfxpG4LsBv0U#NG;7&)4#Q$^z+zBh zViJvIj~T$P5gw%NYYt%wSgN2FNAoQf(wMYeVgDcksht0jRhgiq6b}`f4Nz*uQ=AqU zQJ((hC*OjzyR!1lQ2?OqwgH0CfYwzI0|l7n4&5iv?=bfp_(OwV*L#Hdrmkz<{!L#D z8Gofmv(Haz7m67Z=+{)*y?wc3Mve(Qgu{!mOi2@70xY18K#GVJMDcM}j*}>mh`qkb^-^hkv-~O00Qo_L&{{Gp9-uP>=1;jcZXe8?L-XQ=~ z^^eYjUZ9WP&q%!i!q|1+v3y63X=#~tLt9(09{8DVgO`^yG~@MD3+lM-OeHf&Gk?@B zul%id$3dDKodBpEfZR^(Nk&h(+MjebAS_5ZQ&^%h85Z!m7hT1oo(H`Wjb~^UAs5%f z-;ufUK%{C@7Gtk5fDfau_Ha@Zt;f&-r_TnlB~E)_3{@pD%6cqD$Nj$2oRma2+%yc3 z73C=Lse`o`JuA#~r2AgoRaUS7)qgWla63gr$3Lj86b_@$NKQ8Z9W!4(n2M0sgycQ; zBs?j6MV6)L@m@!h@~YTd$kQV%V$IQ!eAdSWwF+H4B?ru0_uCo{$yB28kVALb1?_j;E*wP{P}C(s0;&b6raU zPbB8x6EFCB=!`<>hW&L%6&-V{`FI&V>O##}8OQvT@w{Yuy$eKabfir_At~3Nje*IY z5mQH?XaGE6>Rc$k?hAoxUVokeqT(y|-K0fC+QGAjDQ5;HnNS9&Jqnfu6OCBak?yT( zm{KQwLV__Kv9=(IPX`E6*fiiNoc<NGk?>9d>H zp^jObEDh4lI5bq-d+DIoe#deT$WDdFzD>nFR^%9mjgPRw7ql)7!Jv0J%TZEE1sl>H zbBXNStgD5>xzf5s1Ak4G3UH}7qtOASK0!LB@)%SKQC`-tTmjEWjsl&Dxi{5~ZdToF zAtQ(K6c|ItcEO}60BEFsQ8R>gFg5}e9Nu`)PS6cMVs{265UTG`KP`4sz>xxEXta58 zolGhpRN5N*hH^!w_9!ue3{7ej6HNA@Dn|dj#e6*E+AC0yjDLR|YB8DVQmvo7seUAR znL1)+QcOMyG{UhigniC1q_GwNU;){o&#w=YZg?;{gn9t_7&#Uk`wF?vCxph=kA-#N zwIbNLyRV8$F;v%dN8%AZ?@9j(+QUdlx}{e8C*`MCB+8v8pAtp}9Y}v9Wt}_iFiL}R z*?6jDcQ&k5jDNa$>}*boVtD^9PoKexo|&rV8#0O)OjG2oI(Z0!RC)jfnSz)5k9(O> z;V#x>Sf7Ec1?g*D6hNz|FV%7}gCL)yu1aiocegy_Bld=`-@yC|s?FF(9Jamw z8Zw-*U`&O#-H|^=yE~!t2nLx7D*QYs)&P9L%IPUP#^uYw4|6bVO2GRg-nT90jf4?C zZ=nmxK!1T7Rc*WGs*v2a+3YpM8es4X2oSyRW0D4|gWnxDygBeo0>PwPw@q^tb#Y9< zcpr1=FCSML*YJK6i8Jt{E}XzJvXLgynf#64Zkmu0E)0OQ zeG61Ez}1VSO_wlwf;*%YLF7RxNEaz6k7XkeWy$YH*gxaDmZI4fb|v5^p3*=RzM6KT zLw}@vWAuKsD-d;`ro=?cPPxGta{MrL0{V?GP-w7=Agoqh$+ePMz4a^x^xhHa$52SM z#WHTm25F0_5A@TQn|kRHVyplk&&Vxo7SUn?YaPdoZZV4H1{L!}dosfBzhmcD5l!0< z_w7PIGi^*5=SL#s3ziY36L16DM4q{6w|_Gre=ojsn`PmbY}X810#`0PNKn9hc@K}a z+G-6>@i@3IJp!F_X6j)t6cu%M_>{VgWL<1kOljP49bv*Jtc*PG{f?7-K}6{jO!DjN zi1Lqubn9Nmfvzo*3aghJYU#j$#;KK=<~Rk8eJDN&4!>Z3Suqy@FtU7m`*ByosDBO- zIJR-qcc1|_=?r!<{tL@t)s4#2(PbIMw0`EWi|$OUc0y}VW$E0`d(r$;0*^&^T+=Fe zqP{gD>(fbu(y^@q9ag|Y&%fx#URD86%tj?Rhp8Zl|ASh=Ar4vhih*=_FS&4&-J+5n zeyFODURY;%V#8WJ?PHz!_5Fg7UVkx_)ae%z$at?TqZGpK^L`BFnH3(&ejAjXsBxwg zCe`HBz(jFb!Fn8r?KxED)f@|@b^Ab|#hJJDd2JI5&FKmY&|C&udUkYg3Sb%Sj-w)4 zh#g7l1@YVRWeZ1)-d-OFz_)|8r`_;Gaa9|e!;OkNzN&sZR_TV8Dt)9!mw#ejuOhty z1$2Fz3)4~BSt$_sfEzA6^tZwc6ouTwGoExa@+Z5c7c@AvkcO1cdXxr$&vfF{1we(Q ztb@kc5JslGy#`={=m0VU#F41skY<&T+EA#9abe6_q5nWg8c*4SiTXA|2w}e+H(_cB z6)6M%f{u(w9xJAf58%_lyMM^;Q~;R^n)ylG5ySfum+-jA1j7;i(%>jLt4??{IXPRPt8z3t%eH*lQrMYAonqkbhG{t7mup`?_ga z_T0+4qux}3{EJ!e0<-jXIH_}e*4}!-V1FTLgk+A@dpdUK%<9n^53fBePjqZJ$lX$J z`VLr`_3%<%`XX7$G2G~GTh6UWSe%fCr&{%o9m{RH&;aBy^Fq!3YH+EH4bV687^Hm( zKsJKm7oO;kW-=FP0Dmxr1+}W8wi0%8QR+|)fk1R&*XT=Yw~ZXn-3VG%R>c8#cEEo) z;*OZ&KPG=2Qw%i!kNX^0fH3$PIDo8pw~t!G%Af#)h&x-;y7*AVLFFnl$BH(g`*pwF z4v0JhpVAitNl4*2C*-L8@>!RPpGQVy$+~o0#?T2?jWrf2?tf6>Qt0PHf6om;6B1Ce zmAH$y5e^xuOR65~K!KoQG*ZGpfKeaY3;j0Zu8BvwF+($SZKymDoGmEflYk}!^%cfq zSR+dJGhz43oCRqXU@SYwQy0c8;Ga7hPDWyJkgO;bkEA!;0Qezr8ouLZ(h~fj3nafq z0mw{jRg9w{ntx)|I(N~B*KXOvuHxo?v@+S;ReLYl#=Yd3H zkI{i($KMw9w~g%yXmSUsiY5IH@&6Wwf&YQ?S!H0nM>;Z|GR zLjam`8?&F6+g799gBlK!C2vo`{9+A|*tVG5ec09Y*mvm?pItZSj@hY*$XCFDa5@V% zL4Tw^DrDoENmY2_^N=yQUCINmb~{GS;x7$FT8Sp))2c91&CLzdTF?nP*+mbvnCj3O zJFeKiiFIH4cNj*SZia13tu+RG(e_D7Nq2^rFkx&<&%+wsKN z2BbbMaz$>#D9YXN$JAfDkfy~-TImQJOMUV=fEfZIh?7*0c2p4>A!rRiU6C;BVq;Vc zUnlY4Y%MsYJh94IqW8aed-VX;CS zq2z2RkAR0&6iFn`VGeAD;zk1sh6~C?Kr{7=@!^0E1J-s9Z^))~HS&A58>T0q-Z?8Y zO^%NU4lL!9gV@)zla1sh*#i@0Lw`;NL@*NK3(sKsD=-!CFfcVu*8)l*>4p*%s6r^N z0NA00=bF#M>rZ~1UvET$BEU!PhmFL*_hVy8a!acUG^5&Sy&@&1YYY(bSx^wld zJWxNNLI^7>4BPOgTej_S5<{~HQNkPM)MSfj++&-yEL)_K75G5^DDd!t+6s!~RArRW zZPCh*zb$&6Jth|+*1v(OLw}|sMJm`@0bdPG-^hX?7L2vd?F5KDj|*AtjdPEZKYh_| znmT1$Q)v})MXbV%t)#NS+TSW8plvOb5CO-*L9mxT1*l&|wuSmxTCrFGW_cTTU=-$P zjb((ga#?r0?wogQyBz4K;l>C*F|XHa>Z>b`u@b#b)@x_Z3xM62 zG-LOMa*iz)Q;5UV=G(3&}(Q7OpHOWlwVTZCe*K;X+Xyd7!V10UaKib@Za zIaHrvFQc+3i+^OB{1rmJmZ#F?jB6OAJ~{$XB^}{@^iD~KL)iwUb&uny(#vVHXpI&y z!nlI~q^1tl;49hPhKn0*E*-?U$S-zevO@Y%tjUX3+KheOk*G-->rV1Nm*5*ani7)) zfJC?{RfdV6lTi@M9?Kb6Lk1nPycHC!3J-D>f0?-LUw{1|@lVp3Yv?KIvFXEvTy|$@ zi06Y$SZ5n}_MT&Ix{gnw0ftY^d^0$yX_MJYDLzaciYpMDWj2QrWo+Wo#kGM$x`Qp& zMxKviE;emP5$($TK!s(1y|JJZ*!fM~cGd3Fwk(c3bQ3df=?IxbJKoAe$1@LA78uY( zS2G{)7k^My?50Webl4#nu3Oa=X|m|cJy5kuND{aO2g*SYs=u7a&h&g836#`K#nYq3 zj=G1G8%q#rdqCw|&O8%33Hx)g^5bS#-KJY#=V2b4qT>636~}#04zq3G5IVxI6T27$ z^kX?&7(9q<&6SU_0b$$Tez6r*u@g8ZO6BbsO@H<}Fuo424w{*}6x#i}#9VSc)W$^V`z;_b$y7Mve4z8PUVQ8Du z#OFGi))GN;hgX{!j@VJXKp+YX)B)Nka zR4ASU1&A-0u1`ak38T9PkQlyxM(QWtj?ABQ8R5oseC8{OCKSR8#vsBjXyy%UeSZzK zFWU&O(CkvBF6@VlQogI7iCQ(|f~!<{p$4cEqSJ)P@^*H&L)Jc6ga(ifLTy39*><7h zJ<{PWTXMQ>tE_*J$8Vr=RoD9ZFn(uPv=F{6h5t=hWbP3p~Ug;N?yj% z9j7_pFfO_%$U%E9-P~3QJTA%l8_N6RAw))#1LJF$3I<&IZ}BUkAmM%t4~KQZY-j1{ zel;MO;eD_k%zt!PQT(74VRO<_LeoprCswDg)hhX&Dlz2)y~Jc=*Rgt@%zu53eOY&} zpvSeuqT*yf)35KJEe?l~zU$7s;1jkJi*Udi!Lw30% ztD~CDpbJJ<9Q}zw8ch8W_b1%tMU;G4a$YAH_rs6SyRQQnC@#q{ySpGH9|&FTHSZTq zf%DL1gS0VS9Rj$bhkyTiF)~v-H(DapHRR?vM9={Wv0!bTXHZm2w}xTJQ8GhvK%(Rs zCNLPtAUOv?Bq~7xi4tdnL;(RkBozcCCsC3}5CjoLBxeL93IY;_VF(jG&b@WNs&l;i z&+d9^b**=G*Z$GFy4K5_tXSu0+hu1ic_o}@snm#jUUU1*!od{RQ<6hA&G=2w zi+riEvZq=h;yNMB-5eAlvZuhTMj;(D9Q10hSa3=Q5?z3uSn z8nD=}U@hY@-87MsNdgcb9@*8Fmpd@xedZZPFV)ZQ_=5dvI;7xE>e6XEYeRZ%1unG$ z7FqF>KNZi}%0W9n-CWOG`<43WYIU9dw5J}GHvf2@GhF+7_|%B^8g2r--r$v%y?e8c zLk!ce-}a5~gN@&g@_R1A%dN5NTf8*=jcVtTS7Q>qg&fGNX{o@Fb~I85M8cU#`waF5 zQLa9Dr$|xBt07}*;C$AJm|4E2Wl4}5u-z_Vt@Y=@%UONPY2u>MpON)bqJ#@oE=xak zHbW4WcugPhX?}t7ROPH2*ReZsdkSN0UcpD1Uf5g~)Rs_5uGFP8kGp}I`xzSbf8xOd4zWQ?(q|FGb5;CyCPHBX(^kmAm+NM}WK z4C5R|ir|FFA-&*gy$4ooKw;AsFu!ClV`+CEw z_6S0X$7?ZNoiiry?1bzMYg`tj+Buj@jmaMOW-~M1;xRx+N3AF}fd6&(gkU0Tb?S_B z4m*ruOvmsZC-al_tzb3IHzRaSfei$uEQ%q9boel;odc<^98q+iVL!={&NJ^rLr=RB zp}J8M>`w7A5^VR~h1*Y1DNG#|7p?XDoTWOrI-av49-Y#J+`0KkNlnwTBD|&Ot`t}_ zj=@$JoD2+SN0C^O;vW?@TDOZ_FkA3?Nv8azpOdw^UKAf6+rEuZ9_4#w^!~L-w0W;= zo3rq`IwL*AFym>T>?K__=FscxP8J-TAR>oGh&0?H0cjS^@*@E* zUu^-%=4M9;`dkpT6JVNqhKbhyfbPn2{;UBurAiBPG<3wm6qswAiRT>1lgI^5>jqXMdArQ>!)KLi4kshwVX6vD%gFuEa+WShPdk)moygqEM;X;_ud$j z&XWnNoFDWo;_@NB^-VK_iz`!}tYy(7rJ%dO1V8Kd+GVp0m*vHsZBZj#hDn^q@+nu@ zy9ZlC2d_P@E7R#EV&H`|R&sG|HADBdT{ChmXfCax3fQ*q+x=cIW#u z1Py!ZewLd>28Cr*Q(x`LLoPtHA9GC%y}?>@Sz9&S&kX_{4vm-bS7$Advr@hmHon`2UJ9-(WEYi7fQWEEj6FRVr{#LK7iJimZ=QI?9Cnchh)k@>xT(Wh{E z*{D{es1zTs;x5DVY>`{^aTYyc{qh@$mn{RquM(3iX`{xU-yt#Q=(if&2(IixcyO(=-;xd#pjL1tG?{Md8b!onASM7G{h9W1YCaJ zJ6=fJpLBG?aWlorUqyH?q&cl7ZO#iw<96*bY@Myxlx~(>i>nV!js}-LujNj}@4zb^ zW+y4UOxdp8=Sk`H;iZX+iOR`h3D%md75qJd_Wr^Gb=!?sl2T zZdfAG+~R{4MZ<*%DH##xS(_!=mP=duT^T}~oa1Ft*5hvmd4qKuzI_S8yO5`!Vz^h_ z73Nj_4BV+$kZ7wix~PZ7A)JByvqv=71C565AmLI?pJLWrf4vAj3O%oOR|4=4j|I1# zpLM6X6WM#ņ#h{v8+PJFfVyI$aai^D{ERn1}}wH|Mpxj2|!tRT5aV^ZiSS^9zf zL+S_6nI_w=s5*f`72MjkA)3y|4Z$4!Xbm&O^(a-0V2krO9rdZ zJgmv5T3f>|l*?92)23QKWt-R4w%fCCnZsCmvzdTVxNm%g^5RgLtK)aJ)gCy6AoXH5 zDfz~9GD&kDA}Q%;0+Aj~xZJO+BH@$rQ{i6*1+?CweQ!SA6C$oC^G$vkW+@$H3>uH$Ov%Vl*HtK6pEFL8raZfw zRn}!9qVT)#M^M=%4mC2o#FqD=1|nwr-p&Z5^nwkKEz3_x6lBPu)ispC%r}J}K9Os**4wUZhl&kKgfEdXOCLg^PK8KHpl-yB}Fc zkH7ii!EbnQ=^jb$i|ykx1m}&e=;$6*Rl0Ts{aGW z%%*;*Q<0IVGd43Fr{QB1daFo5&Ee*|@<*2$v*J*_rS>!%%4=nDCi{gy2#62Ybm{aa zYdDxqKxPL_P{h>?KEq~29i-G1f37l)d_22AY~4RB>uAq>OD_J_Fi(1mIX>qL;CIN2 z0CCwDAn!VocJaO)#BBj=``+OofvmC9+)g~6eM>&6k>+`Y^&LVW4igl%yhL6PwPhoO*v z#3@6S|71$&KN(W-pX~2ENQAIrwm={V0U%KbDD0mBXClywO8;gsC=&H=rU*yi=qDzh*X9_|A" + "

" ] }, "metadata": {}, @@ -120,122 +142,143 @@ } ], "source": [ - "### Dataset visualisation\n", - "\n", - "reg = LogisticRegression().fit(X, l)\n", - "l_fitted = reg.predict(X)\n", - "l_fitted\n", - "markers = np.array(['.', '+'], dtype=str)\n", - "labels = ['nonsocial', 'social']\n", - "\n", - "# plt.scatter(X[:, 0], X[:, 1], s=10, color=colors[y_fitted], marker=markers[y])\n", - "for i, c in enumerate(np.unique(l)):\n", - " plt.scatter(X[:,0][l==c],X[:,1][l==c],color=colors[l_fitted][l==c], marker=markers[i], label=labels[i])\n", - " \n", - "plt.plot()\n", - "plt.xlim(-1.5, 2.5)\n", - "plt.ylim(-1.5, 1.5)\n", - "plt.xticks(())\n", - "plt.yticks(())\n", - "plt.title('noisymoons')\n", - "plt.legend()\n", - "plt.savefig('noisymoons.pdf')" + "def visualise_data(dataset_name='blobs_overlap'):\n", + "\n", + " X, l = get_features_and_labels(dataset_name, overlap_coefficient=0.1)\n", + " ### Dataset visualisation\n", + "\n", + " reg = LogisticRegression().fit(X, l)\n", + " l_fitted = reg.predict(X)\n", + " l_fitted\n", + " markers = np.array(['.', '+'], dtype=str)\n", + " labels = ['nonsocial', 'social']\n", + "\n", + " # plt.scatter(X[:, 0], X[:, 1], s=10, color=colors[y_fitted], marker=markers[y])\n", + " for i, c in enumerate(np.unique(l)):\n", + " plt.scatter(X[:,0][l==c],X[:,1][l==c],color=colors[l][l==c], marker=markers[i], label=labels[i])\n", + "\n", + " plt.plot()\n", + " plt.xlim(-2.5, 2.5)\n", + " plt.ylim(-2.5, 2.5)\n", + " plt.xticks(())\n", + " plt.yticks(())\n", + " plt.title(dataset_name)\n", + " plt.legend()\n", + " plt.savefig('{}.pdf'.format(dataset_name))\n", + "\n", + "visualise_data()" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 258, "id": "55d8284a", "metadata": {}, "outputs": [], "source": [ - "# Treatments and other quantities\n", + "def generate_causal_data(dataset_name, n_samples, mediator_binary, overlap_coefficient=1):\n", + " \n", + " X, l = get_features_and_labels(dataset_name, n_samples, overlap_coefficient=overlap_coefficient)\n", + " # Treatments and other quantities\n", "\n", - "T = rng.choice([0,1], size=(n_samples,1))\n", - "np.mean(X, axis=0)\n", - "#mean_X = np.array([0.5, 0.25])\n", - "mean_X = np.array([0., 0.])" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "1c590f2f", - "metadata": {}, - "outputs": [], - "source": [ - "# Coefficients\n", + " T = rng.choice([0,1], size=(n_samples,1))\n", + " np.mean(X, axis=0)\n", + " #mean_X = np.array([0.5, 0.25])\n", + " mean_X = np.array([0., 0.])\n", + " \n", + " # Coefficients\n", + " reg = LinearRegression().fit(X, l)\n", + " reg.score(X, l), reg.coef_, reg.intercept_\n", + " beta_0 = reg.intercept_\n", + " beta_X = reg.coef_\n", + "\n", + " beta_T = np.array([1])\n", + " beta_TX = np.array([0,0])\n", + " omega_T = 0.9\n", + "\n", + " gamma_0 = 0\n", + " gamma_X = np.array([0,0]) \n", + " gamma_T = np.array([0.2])\n", + " gamma_M = np.array([1])\n", + " gamma_MT = np.array([0])\n", + " omega_M = 0.9\n", + " \n", + " ### Mediator generation\n", "\n", - "reg = LinearRegression().fit(X, l)\n", - "reg.score(X, l), reg.coef_, reg.intercept_\n", - "beta_0 = reg.intercept_\n", - "beta_X = reg.coef_\n", + " if mediator_binary:\n", + " p = expit(beta_0 + X.dot(beta_X) + omega_T*T.dot(beta_T) + (T*X).dot(beta_TX) )\n", + " M_ = rng.binomial(1, p)\n", + " M = np.expand_dims(M_, axis=-1) \n", "\n", - "beta_T = np.array([1])\n", - "beta_TX = np.array([0,0])\n", - "omega_T = 0.9\n", + " else:\n", + " M_ = beta_0 + X.dot(beta_X) + omega_T*T.dot(beta_T) + (T*X).dot(beta_TX) + rng.normal(0, 0.1, size=T.shape[0])\n", + " M = np.expand_dims(M_, axis=-1)\n", + "\n", + " Y = gamma_0 + X.dot(gamma_X) + T.dot(gamma_T) + omega_M*M.dot(gamma_M) + (T*M).dot(gamma_MT) + rng.normal(0, 0.1, size=T.shape[0])\n", + " \n", + " causal_data = X, T, M, Y\n", + " \n", + " ### Causal quantities\n", + " \n", + " if mediator_binary:\n", + " mean_M_t1 = np.mean(expit(beta_0 + X.dot(beta_X) + X.dot(beta_TX) + omega_T *beta_T), axis=0)\n", + " mean_M_t0 = np.mean(expit(beta_0 + X.dot(beta_X)), axis=0)\n", + " theta_1 = gamma_T + gamma_MT.T.dot(mean_M_t1) # to do mean(m1) pour avoir un vecteur de taille dim_m\n", + " theta_0 = gamma_T + gamma_MT.T.dot(mean_M_t0)\n", + " product_mean_term = expit(beta_0 + X.dot(beta_X) + X.dot(beta_TX) + omega_T *beta_T) - expit(beta_0 + X.dot(beta_X))\n", + "\n", + " delta_1 = np.mean(product_mean_term*(omega_M * gamma_M+gamma_MT), axis=0)\n", + " delta_0 = np.mean(product_mean_term*(omega_M * gamma_M), axis=0)\n", + " tau = delta_0 + theta_1\n", "\n", - "M_ = beta_0 + X.dot(beta_X) + omega_T*T.dot(beta_T) + (T*X).dot(beta_TX) + rng.normal(0, 0.1, size=T.shape[0])\n", - "M = np.expand_dims(M_, axis=-1)\n", + " else:\n", + " mean_M_t1 = beta_0 + mean_X.dot(beta_X) + mean_X.dot(beta_TX) + omega_T *beta_T\n", + " mean_M_t0 = beta_0 + mean_X.dot(beta_X)\n", "\n", - "gamma_0 = 0\n", - "gamma_X = np.array([0,0]) \n", - "gamma_T = np.array([0.2])\n", - "gamma_M = np.array([1])\n", - "gamma_MT = np.array([0])\n", - "omega_M = 0.9\n", + " theta_1 = gamma_T + gamma_MT.T.dot(mean_M_t1) # to do mean(m1) pour avoir un vecteur de taille dim_m\n", + " theta_0 = gamma_T + gamma_MT.T.dot(mean_M_t0)\n", + " #delta_1 = (gamma_T * t1 + m1.dot(gamma_m) + m1.dot(gamma_t_m) * t1 - gamma_t * t1 + m0.dot(gamma_m) + m0.dot(gamma_t_m) * t1).mean()\n", + " #delta_0 = (gamma_T * t0 + m1.dot(gamma_m) + m1.dot(gamma_t_m) * t0 - gamma_t * t0 + m0.dot(gamma_m) + m0.dot(gamma_t_m) * t0).mean()\n", + " delta_1 = (mean_X.dot(beta_TX) + omega_T * beta_T) * (omega_M * gamma_M + gamma_MT)\n", + " delta_0 = (mean_X.dot(beta_TX) + omega_T * beta_T) * (omega_M * gamma_M)\n", "\n", - "Y = gamma_0 + X.dot(gamma_X) + T.dot(gamma_T) + omega_M*M.dot(gamma_M) + (T*M).dot(gamma_MT) + rng.normal(0, 0.1, size=T.shape[0])" + " tau = gamma_T + omega_M * gamma_M * omega_T * beta_T\n", + " \n", + " causal_effects = [tau[0], theta_1[0], theta_0[0], delta_1, delta_0, 0]\n", + " \n", + " return causal_data, causal_effects" ] }, { "cell_type": "code", - "execution_count": 106, + "execution_count": 259, "id": "a24af6c3", "metadata": {}, "outputs": [], "source": [ - "((T*X).dot(beta_TX)).shape\n", - "linear_X = beta_0 + X.dot(beta_X)\n", - "linear_T = omega_T*T.dot(beta_T)\n", - "linear_TX = (T*X).dot(beta_TX)\n", - "noise = rng.normal(0, 0.1, size=T.shape[0])" + "#((T*X).dot(beta_TX)).shape\n", + "#linear_X = beta_0 + X.dot(beta_X)\n", + "#linear_T = omega_T*T.dot(beta_T)\n", + "#linear_TX = (T*X).dot(beta_TX)\n", + "#noise = rng.normal(0, 0.1, size=T.shape[0])\n", + "dataset_name='blobs_overlap'\n", + "n_samples=10000\n", + "mediator_binary=False" ] }, { "cell_type": "code", - "execution_count": 12, - "id": "811a6446", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "d5c31a25", + "execution_count": 7, + "id": "08c288e2", "metadata": {}, "outputs": [], "source": [ - "### Causal quantities\n", - "\n", - "mean_M_t1 = beta_0 + mean_X.dot(beta_X) + mean_X.dot(beta_TX) + omega_T *beta_T\n", - "mean_M_t0 = beta_0 + mean_X.dot(beta_X)\n", - "\n", - "theta_1 = gamma_T + gamma_MT.T.dot(mean_M_t1) # to do mean(m1) pour avoir un vecteur de taille dim_m\n", - "theta_0 = gamma_T + gamma_MT.T.dot(mean_M_t0)\n", - "#delta_1 = (gamma_T * t1 + m1.dot(gamma_m) + m1.dot(gamma_t_m) * t1 - gamma_t * t1 + m0.dot(gamma_m) + m0.dot(gamma_t_m) * t1).mean()\n", - "#delta_0 = (gamma_T * t0 + m1.dot(gamma_m) + m1.dot(gamma_t_m) * t0 - gamma_t * t0 + m0.dot(gamma_m) + m0.dot(gamma_t_m) * t0).mean()\n", - "delta_1 = (mean_X.dot(beta_TX) + omega_T * beta_T) * (omega_M * gamma_M + gamma_MT)\n", - "delta_0 = (mean_X.dot(beta_TX) + omega_T * beta_T) * (omega_M * gamma_M)\n", - "\n", - "tau = gamma_T + omega_M * gamma_M * omega_T * beta_T\n", - "tau" + "causal_data, causal_effects = generate_causal_data(dataset_name, n_samples, mediator_binary)" ] }, { "cell_type": "markdown", - "id": "9bd617ea", + "id": "82292fa9", "metadata": {}, "source": [ "## Causal effect estimation" @@ -243,19 +286,18 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 8, "id": "fa63c8d4", "metadata": {}, "outputs": [], "source": [ - "\n", "CV_FOLDS = 5\n", "ALPHAS = np.logspace(-5, 5, 8)" ] }, { "cell_type": "markdown", - "id": "1a5768c8", + "id": "610ccc7b", "metadata": {}, "source": [ "### Importance weighting" @@ -263,7 +305,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 163, "id": "cfdb2b86", "metadata": {}, "outputs": [], @@ -321,7 +363,7 @@ " \n", " return p_x, p_xm\n", "\n", - "def SNIPW(y, t, m, x, trim, p_x, p_xm):\n", + "def SNIPW(y, t, m, x, trim, p_x, p_xm, clip):\n", " \"\"\"\n", " IPW estimator presented in\n", " HUBER, Martin. Identifying causal mechanisms (primarily) based on inverse\n", @@ -378,7 +420,9 @@ " clip float\n", " limit to clip for numerical stability (min=clip, max=1-clip)\n", " \"\"\"\n", - "\n", + " \n", + " t = t.squeeze()\n", + " \n", " # trimming. Following causal weight code, not sure I understand\n", " # why we trim only on p_xm and not on p_x\n", " ind = ((p_xm > trim) & (p_xm < (1 - trim)))\n", @@ -404,7 +448,7 @@ " y0m1 - y0m0,\n", " np.sum(ind))\n", "\n", - "def IPW(y, t, m, x, trim, p_x, p_xm):\n", + "def IPW(y, t, m, x, trim, p_x, p_xm, clip):\n", " \"\"\"\n", " IPW estimator presented in\n", " HUBER, Martin. Identifying causal mechanisms (primarily) based on inverse\n", @@ -461,7 +505,11 @@ " clip float\n", " limit to clip for numerical stability (min=clip, max=1-clip)\n", " \"\"\"\n", - "\n", + " \n", + " t = t.squeeze()\n", + " \n", + " # trimming. Following causal weight code, not sure I understand\n", + " # why we trim only on p_xm and not on p_x\n", " # trimming. Following causal weight code, not sure I understand\n", " # why we trim only on p_xm and not on p_x\n", " ind = ((p_xm > trim) & (p_xm < (1 - trim)))\n", @@ -472,9 +520,9 @@ " p_x = np.clip(p_x, clip, 1 - clip)\n", " p_xm = np.clip(p_xm, clip, 1 - clip)\n", "\n", - " y1m1 = np.mean(y * t / p_x) \n", + " y1m1 = np.mean(y * t / p_x)\n", " y1m0 = np.mean(y * t * (1 - p_xm) / (p_xm * (1 - p_x))) \n", - " y0m0 = np.mean(y * (1 - t) / (1 - p_x)) \n", + " y0m0 = np.mean(y * (1 - t) / (1 - p_x))\n", " y0m1 = np.mean(y * (1 - t) * p_xm / ((1 - p_xm) * p_x)) \n", "\n", " return(y1m1 - y0m0,\n", @@ -482,146 +530,96 @@ " y1m0 - y0m0,\n", " y1m1 - y1m0,\n", " y0m1 - y0m0,\n", - " np.sum(ind))\n", - "\n", - "\n", - "\n" + " np.sum(ind))\n" ] }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 164, "id": "cf795077", "metadata": {}, "outputs": [], "source": [ - "y = Y\n", - "t = T\n", - "m = M\n", - "x = X\n", - "trim=0\n", - "logit=True\n", - "regularization=False\n", - "forest=False\n", - "crossfit=0\n", - "clip=0.0\n", - "calibration=False\n", - "classifier_x, classifier_xm = get_classifier(regularization, forest, calibration)" + "# y = Y\n", + "# t = T\n", + "# m = M\n", + "# x = X\n", + "# trim=0\n", + "# logit=True\n", + "# regularization=False\n", + "# forest=False\n", + "# crossfit=0\n", + "# clip=0.0\n", + "# calibration=False\n", + "# classifier_x, classifier_xm = get_classifier(regularization, forest, calibration)" ] }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 11, "id": "60063b02", "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/opt/anaconda3/lib/python3.8/site-packages/sklearn/utils/validation.py:1143: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", - " y = column_or_1d(y, warn=True)\n", - "/opt/anaconda3/lib/python3.8/site-packages/sklearn/utils/validation.py:1143: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", - " y = column_or_1d(y, warn=True)\n" - ] - } - ], + "outputs": [], "source": [ - "p_x, p_xm = estimate_probabilities(t, m, x, crossfit, classifier_x, classifier_xm)\n", - "effects_IPW = IPW(y, t, m, x, trim, p_x, p_xm)\n", - "effects_SNIPW = SNIPW(y, t, m, x, trim, p_x, p_xm)" + "# p_x, p_xm = estimate_probabilities(t, m, x, crossfit, classifier_x, classifier_xm)\n", + "# effects_IPW = IPW(y, t, m, x, trim, p_x, p_xm)\n", + "# effects_SNIPW = SNIPW(y, t, m, x, trim, p_x, p_xm)" ] }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 12, "id": "d6e0cf37", "metadata": {}, "outputs": [], "source": [ - "tau_hat, theta_1_hat, theta_0_hat, delta_1_hat, delta_0_hat, n_non_trimmed = effects_IPW" + "# tau_hat, theta_1_hat, theta_0_hat, delta_1_hat, delta_0_hat, n_non_trimmed = effects_IPW" ] }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 13, "id": "69e45369", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "IPW\n", - "Direct effects\n", - "True theta1:[0.2], estimated theta1: -478403411903829.6\n", - "True theta0:[0.2], estimated theta0: -5.960267411051258e+25\n", - "\\\n", - "Indirect effects\n", - "True delta1:[0.81], estimated delta1: 5.960267411051258e+25\n", - "True delta0:[0.81], estimated delta0: 478403411903829.1\n", - "\\\n", - "Total effect\n", - "True tau:[1.01], estimated tau: -0.489\n" - ] - } - ], + "outputs": [], "source": [ - "print(\"IPW\")\n", - "print(\"Direct effects\")\n", - "print(\"True theta1:{}, estimated theta1: {}\".format(theta_1, round(theta_1_hat,3)))\n", - "print(\"True theta0:{}, estimated theta0: {}\".format(theta_0, round(theta_0_hat,3)))\n", - "print(\"\\\\\")\n", - "print(\"Indirect effects\")\n", - "print(\"True delta1:{}, estimated delta1: {}\".format(delta_1, round(delta_1_hat,3)))\n", - "print(\"True delta0:{}, estimated delta0: {}\".format(delta_0, round(delta_0_hat,3)))\n", - "print(\"\\\\\")\n", - "print(\"Total effect\")\n", - "print(\"True tau:{}, estimated tau: {}\".format(tau, round(tau_hat,3)))" + "# print(\"IPW\")\n", + "# print(\"Direct effects\")\n", + "# print(\"True theta1:{}, estimated theta1: {}\".format(theta_1, round(theta_1_hat,3)))\n", + "# print(\"True theta0:{}, estimated theta0: {}\".format(theta_0, round(theta_0_hat,3)))\n", + "# print(\"\\\\\")\n", + "# print(\"Indirect effects\")\n", + "# print(\"True delta1:{}, estimated delta1: {}\".format(delta_1, round(delta_1_hat,3)))\n", + "# print(\"True delta0:{}, estimated delta0: {}\".format(delta_0, round(delta_0_hat,3)))\n", + "# print(\"\\\\\")\n", + "# print(\"Total effect\")\n", + "# print(\"True tau:{}, estimated tau: {}\".format(tau, round(tau_hat,3)))" ] }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 14, "id": "c5ad6863", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "SNIPW\n", - "Direct effects\n", - "True theta1:[0.2], estimated theta1: -0.694\n", - "True theta0:[0.2], estimated theta0: -0.903\n", - "\\\n", - "Indirect effects\n", - "True delta1:[0.81], estimated delta1: 0.893\n", - "True delta0:[0.81], estimated delta0: 0.684\n", - "\\\n", - "Total effect\n", - "True tau:[1.01], estimated tau: -0.01\n" - ] - } - ], + "outputs": [], "source": [ - "tau_hat, theta_1_hat, theta_0_hat, delta_1_hat, delta_0_hat, n_non_trimmed = effects_SNIPW\n", - "print(\"SNIPW\")\n", - "print(\"Direct effects\")\n", - "print(\"True theta1:{}, estimated theta1: {}\".format(theta_1, round(theta_1_hat,3)))\n", - "print(\"True theta0:{}, estimated theta0: {}\".format(theta_0, round(theta_0_hat,3)))\n", - "print(\"\\\\\")\n", - "print(\"Indirect effects\")\n", - "print(\"True delta1:{}, estimated delta1: {}\".format(delta_1, round(delta_1_hat,3)))\n", - "print(\"True delta0:{}, estimated delta0: {}\".format(delta_0, round(delta_0_hat,3)))\n", - "print(\"\\\\\")\n", - "print(\"Total effect\")\n", - "print(\"True tau:{}, estimated tau: {}\".format(tau, round(tau_hat,3)))" + "# tau_hat, theta_1_hat, theta_0_hat, delta_1_hat, delta_0_hat, n_non_trimmed = effects_SNIPW\n", + "# print(\"SNIPW\")\n", + "# print(\"Direct effects\")\n", + "# print(\"True theta1:{}, estimated theta1: {}\".format(theta_1, round(theta_1_hat,3)))\n", + "# print(\"True theta0:{}, estimated theta0: {}\".format(theta_0, round(theta_0_hat,3)))\n", + "# print(\"\\\\\")\n", + "# print(\"Indirect effects\")\n", + "# print(\"True delta1:{}, estimated delta1: {}\".format(delta_1, round(delta_1_hat,3)))\n", + "# print(\"True delta0:{}, estimated delta0: {}\".format(delta_0, round(delta_0_hat,3)))\n", + "# print(\"\\\\\")\n", + "# print(\"Total effect\")\n", + "# print(\"True tau:{}, estimated tau: {}\".format(tau, round(tau_hat,3)))" ] }, { "cell_type": "markdown", - "id": "e5147842", + "id": "7370ccd3", "metadata": {}, "source": [ "### Ordinary least squares" @@ -629,8 +627,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "1eaa1b0b", + "execution_count": 165, + "id": "32dbc702", "metadata": {}, "outputs": [], "source": [ @@ -699,34 +697,253 @@ }, { "cell_type": "code", - "execution_count": 126, - "id": "d8c15b96", + "execution_count": 16, + "id": "0db06a94", "metadata": {}, "outputs": [], "source": [ - "def get_regressions(regularization=False, interaction=False, forest=False, calibration=True, calib_method='sigmoid'):\n", + "# effects_linear = ols_mediation(y, t, m, x)\n", + "\n", + "# tau_hat, theta_1_hat, theta_0_hat, delta_1_hat, delta_0_hat, n_non_trimmed = effects_linear\n", + "# print(\"Linear coefficients\")\n", + "# print(\"Direct effects\")\n", + "# print(\"True theta1:{}, estimated theta1: {}\".format(theta_1, round(theta_1_hat,3)))\n", + "# print(\"True theta0:{}, estimated theta0: {}\".format(theta_0, round(theta_0_hat,3)))\n", + "# print(\"\\\\\")\n", + "# print(\"Indirect effects\")\n", + "# print(\"True delta1:{}, estimated delta1: {}\".format(delta_1, round(delta_1_hat,3)))\n", + "# print(\"True delta0:{}, estimated delta0: {}\".format(delta_0, round(delta_0_hat,3)))\n", + "# print(\"\\\\\")\n", + "# print(\"Total effect\")\n", + "# print(\"True tau:{}, estimated tau: {}\".format(tau, round(tau_hat,3)))" + ] + }, + { + "cell_type": "markdown", + "id": "c13945ae", + "metadata": {}, + "source": [ + "### G computation" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "0ffc9cc2", + "metadata": {}, + "outputs": [], + "source": [ + "def get_interactions(interaction, *args):\n", + " \"\"\"\n", + " this function provides interaction terms between different groups of\n", + " variables (confounders, treatment, mediators)\n", + " Inputs\n", + " --------\n", + " interaction boolean\n", + " whether to compute interaction terms\n", + "\n", + " *args flexible, one or several arrays\n", + " blocks of variables between which interactions should be\n", + " computed\n", + " Returns\n", + " --------\n", + " Examples\n", + " --------\n", + " >>> x = np.arange(6).reshape(3, 2)\n", + " >>> t = np.ones((3, 1))\n", + " >>> m = 2 * np.ones((3, 1))\n", + " >>> get_interactions(False, x, t, m)\n", + " array([[0., 1., 1., 2.],\n", + " [2., 3., 1., 2.],\n", + " [4., 5., 1., 2.]])\n", + " >>> get_interactions(True, x, t, m)\n", + " array([[ 0., 1., 1., 2., 0., 1., 0., 2., 2.],\n", + " [ 2., 3., 1., 2., 2., 3., 4., 6., 2.],\n", + " [ 4., 5., 1., 2., 4., 5., 8., 10., 2.]])\n", + " \"\"\"\n", + " variables = list(args)\n", + " for index, var in enumerate(variables):\n", + " if len(var.shape) == 1:\n", + " variables[index] = var.reshape(-1,1)\n", + " pre_inter_variables = np.hstack(variables)\n", + " if not interaction:\n", + " return pre_inter_variables\n", + " new_cols = list()\n", + " for i, var in enumerate(variables[:]):\n", + " for j, var2 in enumerate(variables[i+1:]):\n", + " for ii in range(var.shape[1]):\n", + " for jj in range(var2.shape[1]):\n", + " new_cols.append((var[:, ii] * var2[:, jj]).reshape(-1, 1))\n", + " new_vars = np.hstack(new_cols)\n", + " result = np.hstack((pre_inter_variables, new_vars))\n", + " return result\n", + "\n", + "def g_computation(y, t, m, x, interaction=False, forest=False,\n", + " crossfit=0, calibration=True, regularization=True,\n", + " calib_method='sigmoid'):\n", + " \"\"\"\n", + " m is binary !!!\n", + "\n", + " implementation of the g formula for mediation\n", + "\n", + " y array-like, shape (n_samples)\n", + " outcome value for each unit, continuous\n", + "\n", + " t array-like, shape (n_samples)\n", + " treatment value for each unit, binary\n", + "\n", + " m array-like, shape (n_samples)\n", + " mediator value for each unit, here m is necessary binary and uni-\n", + " dimensional\n", + "\n", + " x array-like, shape (n_samples, n_features_covariates)\n", + " covariates (potential confounders) values\n", + "\n", + " interaction boolean, default=False\n", + " whether to include interaction terms in the model\n", + " interactions are terms XT, TM, MX\n", + "\n", + " forest boolean, default False\n", + " whether to use a random forest model to estimate the propensity\n", + " scores instead of logistic regression, and outcome model instead\n", + " of linear regression\n", + "\n", + " crossfit integer, default 0\n", + " number of folds for cross-fitting\n", + "\n", + " regularization boolean, default True\n", + " whether to use regularized models (logistic or\n", + " linear regression). If True, cross-validation is used\n", + " to chose among 8 potential log-spaced values between\n", + " 1e-5 and 1e5\n", + " \"\"\"\n", " if regularization:\n", + " alphas = ALPHAS\n", " cs = ALPHAS\n", " else:\n", + " alphas = [0.0]\n", " cs = [np.inf]\n", + " n = len(y)\n", + " if len(x.shape) == 1:\n", + " x = x.reshape(-1, 1)\n", + " if len(m.shape) == 1:\n", + " mr = m.reshape(-1, 1)\n", + " else:\n", + " mr = np.copy(m)\n", + " if len(t.shape) == 1:\n", + " t = t.reshape(-1, 1)\n", + " t0 = np.zeros((n, 1))\n", + " t1 = np.ones((n, 1))\n", + " m0 = np.zeros((n, 1))\n", + " m1 = np.ones((n, 1))\n", + "\n", + " if crossfit < 2:\n", + " train_test_list = [[np.arange(n), np.arange(n)]]\n", + " else:\n", + " kf = KFold(n_splits=crossfit)\n", + " train_test_list = list()\n", + " for train_index, test_index in kf.split(x):\n", + " train_test_list.append([train_index, test_index])\n", + " mu_11x, mu_10x, mu_01x, mu_00x, f_00x, f_01x, f_10x, f_11x = \\\n", + " [np.zeros(n) for h in range(8)]\n", + "\n", + " for train_index, test_index in train_test_list:\n", + " if not forest:\n", + " y_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS)\\\n", + " .fit(get_interactions(interaction, x, t, mr)[train_index, :], y[train_index])\n", + " pre_m_prob = LogisticRegressionCV(Cs=cs, cv=CV_FOLDS)\\\n", + " .fit(get_interactions(interaction, t, x)[train_index, :], m.ravel()[train_index])\n", + " else:\n", + " y_reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10)\\\n", + " .fit(get_interactions(interaction, x, t, mr)[train_index, :], y[train_index])\n", + " pre_m_prob = RandomForestClassifier(n_estimators=100, min_samples_leaf=10)\\\n", + " .fit(get_interactions(interaction, t, x)[train_index, :], m.ravel()[train_index])\n", + " if calibration:\n", + " m_prob = CalibratedClassifierCV(pre_m_prob, method=calib_method)\\\n", + " .fit(get_interactions(\n", + " interaction, t, x)[train_index, :], m.ravel()[train_index])\n", + " else:\n", + " m_prob = pre_m_prob\n", + " mu_11x[test_index] = y_reg.predict(get_interactions(interaction, x, t1, m1)[test_index, :])\n", + " mu_10x[test_index] = y_reg.predict(get_interactions(interaction, x, t1, m0)[test_index, :])\n", + " mu_01x[test_index] = y_reg.predict(get_interactions(interaction, x, t0, m1)[test_index, :])\n", + " mu_00x[test_index] = y_reg.predict(get_interactions(interaction, x, t0, m0)[test_index, :])\n", + " f_00x[test_index] = m_prob.predict_proba(get_interactions(interaction, t0, x)[test_index, :])[:, 0]\n", + " f_01x[test_index] = m_prob.predict_proba(get_interactions(interaction, t0, x)[test_index, :])[:, 1]\n", + " f_10x[test_index] = m_prob.predict_proba(get_interactions(interaction, t1, x)[test_index, :])[:, 0]\n", + " f_11x[test_index] = m_prob.predict_proba(get_interactions(interaction, t1, x)[test_index, :])[:, 1]\n", + "\n", + " direct_effect_i1 = mu_11x - mu_01x\n", + " direct_effect_i0 = mu_10x - mu_00x\n", + " direct_effect_treated = (direct_effect_i1 * f_11x + direct_effect_i0 * f_10x).sum() / n\n", + " direct_effect_control = (direct_effect_i1 * f_01x + direct_effect_i0 * f_00x).sum() / n\n", + " indirect_effect_i1 = f_11x - f_01x\n", + " indirect_effect_i0 = f_10x - f_00x\n", + " indirect_effect_treated = (indirect_effect_i1 * mu_11x + indirect_effect_i0 * mu_10x).sum() / n\n", + " indirect_effect_control = (indirect_effect_i1 * mu_01x + indirect_effect_i0 * mu_00x).sum() / n\n", + " total_effect = direct_effect_control + indirect_effect_treated\n", + "\n", + " return [total_effect,\n", + " direct_effect_treated,\n", + " direct_effect_control,\n", + " indirect_effect_treated,\n", + " indirect_effect_control,\n", + " None]" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "1d3605ff", + "metadata": {}, + "outputs": [], + "source": [ + "# effects_g_computation = g_computation(y, t, m, x)\n", + "\n", + "# tau_hat, theta_1_hat, theta_0_hat, delta_1_hat, delta_0_hat, n_non_trimmed = effects_linear\n", + "# print(\"Linear coefficients\")\n", + "# print(\"Direct effects\")\n", + "# print(\"True theta1:{}, estimated theta1: {}\".format(theta_1, round(theta_1_hat,3)))\n", + "# print(\"True theta0:{}, estimated theta0: {}\".format(theta_0, round(theta_0_hat,3)))\n", + "# print(\"\\\\\")\n", + "# print(\"Indirect effects\")\n", + "# print(\"True delta1:{}, estimated delta1: {}\".format(delta_1, round(delta_1_hat,3)))\n", + "# print(\"True delta0:{}, estimated delta0: {}\".format(delta_0, round(delta_0_hat,3)))\n", + "# print(\"\\\\\")\n", + "# print(\"Total effect\")\n", + "# print(\"True tau:{}, estimated tau: {}\".format(tau, round(tau_hat,3)))" + ] + }, + { + "cell_type": "markdown", + "id": "d3d47477", + "metadata": {}, + "source": [ + "### Multiply robust estimator" + ] + }, + { + "cell_type": "code", + "execution_count": 166, + "id": "d8c15b96", + "metadata": {}, + "outputs": [], + "source": [ + "def get_regressions(regularization=False, interaction=False, forest=False, calibration=True, calib_method='sigmoid'):\n", + " if regularization:\n", + " alphas, cs = ALPHAS, ALPHAS\n", + " else:\n", + " alphas, cs = [0.0], [np.inf]\n", " \n", " # mu_tm, f_mtx, and p_x model fitting\n", " if not forest:\n", " y_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS)\n", - " pre_m_prob = LogisticRegressionCV(Cs=cs, cv=CV_FOLDS).fit(\n", - " get_interactions(interaction, t, x)[train_index, :], m[train_index]\n", - " )\n", - " pre_p_x_clf = LogisticRegressionCV(Cs=cs, cv=CV_FOLDS).fit(\n", - " x[train_index, :], t[train_index]\n", - " )\n", + " pre_m_prob = LogisticRegressionCV(Cs=cs, cv=CV_FOLDS)\n", + " pre_p_x_clf = LogisticRegressionCV(Cs=cs, cv=CV_FOLDS)\n", " else:\n", " y_reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10)\n", - " pre_m_prob = RandomForestClassifier(\n", - " n_estimators=100, min_samples_leaf=10\n", - " )\n", - " pre_p_x_clf = RandomForestClassifier(\n", - " n_estimators=100, min_samples_leaf=10\n", - " )\n", + " pre_m_prob = RandomForestClassifier(n_estimators=100, min_samples_leaf=10)\n", + " pre_p_x_clf = RandomForestClassifier(n_estimators=100, min_samples_leaf=10)\n", " if calibration:\n", " m_prob = CalibratedClassifierCV(pre_m_prob, method=calib_method)\n", " p_x_clf = CalibratedClassifierCV(pre_p_x_clf, method=calib_method)\n", @@ -1102,96 +1319,2203 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "8baf76a4", + "execution_count": 20, + "id": "2dabfd33", "metadata": {}, "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": 128, - "id": "a7bb5072", - "metadata": {}, - "outputs": [ - { - "ename": "ValueError", - "evalue": "m is not binary", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0meffects_MR\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mmultiply_robust_efficient\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mt\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mm\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m\u001b[0m in \u001b[0;36mmultiply_robust_efficient\u001b[0;34m(y, t, m, x, interaction, forest, crossfit, trim, regularization, calibration, calib_method)\u001b[0m\n\u001b[1;32m 103\u001b[0m \u001b[0mdim_m\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mm\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 104\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mdim_m\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0msum\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mm\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mravel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0msum\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mm\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mravel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 105\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"m is not binary\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 106\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 107\u001b[0m \u001b[0my\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mravel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mValueError\u001b[0m: m is not binary" - ] - } - ], "source": [ - "effects_MR = multiply_robust_efficient(y, t, m, x)" + "# effects_MR = multiply_robust_efficient(y, t, m, x)\n", + "\n", + "# tau_hat, theta_1_hat, theta_0_hat, delta_1_hat, delta_0_hat, n_non_trimmed = effects_linear\n", + "# print(\"Multiply robust coefficients\")\n", + "# print(\"Direct effects\")\n", + "# print(\"True theta1:{}, estimated theta1: {}\".format(theta_1, round(theta_1_hat,3)))\n", + "# print(\"True theta0:{}, estimated theta0: {}\".format(theta_0, round(theta_0_hat,3)))\n", + "# print(\"\\\\\")\n", + "# print(\"Indirect effects\")\n", + "# print(\"True delta1:{}, estimated delta1: {}\".format(delta_1, round(delta_1_hat,3)))\n", + "# print(\"True delta0:{}, estimated delta0: {}\".format(delta_0, round(delta_0_hat,3)))\n", + "# print(\"\\\\\")\n", + "# print(\"Total effect\")\n", + "# print(\"True tau:{}, estimated tau: {}\".format(tau, round(tau_hat,3)))" ] }, { "cell_type": "code", - "execution_count": 130, - "id": "2dabfd33", + "execution_count": 289, + "id": "859c9b16", "metadata": {}, "outputs": [], - "source": [] + "source": [ + "params={\n", + " 'trim':0,\n", + " 'logit':True,\n", + " 'regularization':False,\n", + " 'forest':False,\n", + " 'crossfit':0,\n", + " 'clip':0.01,\n", + " 'calibration':False,\n", + "}\n", + "\n", + "dataset_name='blobs_overlap'\n", + "n_samples=10000\n", + "mediator_binary=False\n", + "\n", + "list_causal_effects = ['total effect $\\tau$', 'direct effect treated $\\theta(1)$','direct effect non treated $\\theta(0)$', 'indirect effect treated $\\delta(1)$', 'indirect effect untreated $\\delta(0)$', 'n']\n", + "\n", + "def run_experiment(dataset_name, n_samples, mediator_binary, params, overlap_coefficient):\n", + " \n", + " causal_data, causal_effects = generate_causal_data(dataset_name, n_samples, mediator_binary, overlap_coefficient)\n", + " x, t, m, y = causal_data\n", + " classifier_x, classifier_xm = get_classifier(params['regularization'], params['forest'], params['calibration'])\n", + " p_x, p_xm = estimate_probabilities(t, m, x, params['crossfit'], classifier_x, classifier_xm)\n", + " effects_IPW = IPW(y, t, m, x, params['trim'], p_x, p_xm, params['clip'])\n", + " effects_SNIPW = SNIPW(y, t, m, x, params['trim'], p_x, p_xm, params['clip'])\n", + " effects_linear = ols_mediation(y, t, m, x)\n", + " effects_g_computation = g_computation(y, t, m, x)\n", + " effects_MR = multiply_robust_efficient(y, t, m, x)\n", + " data = {'causal_effects': list_causal_effects}\n", + " data['Truth'] = causal_effects\n", + " data['IPW'] = effects_IPW\n", + " data['SNIPW'] = effects_SNIPW\n", + " data['linear'] = effects_linear\n", + " data['G-computation'] = effects_g_computation\n", + " data['MR'] = effects_MR\n", + " df = pd.DataFrame(data)\n", + " df = df[:-1]\n", + " df.set_index('causal_effects', inplace=True)\n", + " return df\n", + "\n", + "# results_df = run_experiment(dataset_name, n_samples, True, params)" + ] }, { "cell_type": "code", - "execution_count": 133, - "id": "f67c3f8f", + "execution_count": 311, + "id": "a1929ae8", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=2):\n", + "ABNORMAL_TERMINATION_IN_LNSRCH.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=2):\n", + "ABNORMAL_TERMINATION_IN_LNSRCH.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=2):\n", + "ABNORMAL_TERMINATION_IN_LNSRCH.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=2):\n", + "ABNORMAL_TERMINATION_IN_LNSRCH.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=2):\n", + "ABNORMAL_TERMINATION_IN_LNSRCH.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=2):\n", + "ABNORMAL_TERMINATION_IN_LNSRCH.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=2):\n", + "ABNORMAL_TERMINATION_IN_LNSRCH.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n" + ] + } + ], + "source": [ + "list_overlap_coefficients = list(np.arange(0, 1.1, 0.1))\n", + "\n", + "direct_effect_treated_dic ={\n", + " 'Truth': [],\n", + " 'IPW': [],\n", + " 'SNIPW': [],\n", + " 'linear': [],\n", + " 'G-computation': [],\n", + " 'MR': []\n", + "}\n", + "direct_effect_treated_df = pd.DataFrame(direct_effect_treated_dic)\n", + "\n", + "direct_effect_non_treated_df = direct_effect_treated_df.copy()\n", + "indirect_effect_treated_df = direct_effect_treated_df.copy()\n", + "indirect_effect_non_treated_df = direct_effect_treated_df.copy()\n", + "total_effect_df = direct_effect_treated_df.copy()\n", + "n_samples = 100000\n", + "\n", + "for coefficient in list_overlap_coefficients:\n", + " results_df = run_experiment(dataset_name, n_samples, True, params, coefficient)\n", + " total_effect_df.loc[len(total_effect_df.index)] = results_df.iloc[0].values\n", + " direct_effect_treated_df.loc[len(direct_effect_treated_df.index)] = results_df.iloc[1].values\n", + " direct_effect_non_treated_df.loc[len(direct_effect_non_treated_df.index)] = results_df.iloc[2].values\n", + " indirect_effect_treated_df.loc[len(indirect_effect_treated_df.index)] = results_df.iloc[3].values\n", + " indirect_effect_non_treated_df.loc[len(indirect_effect_non_treated_df.index)] = results_df.iloc[4].values" + ] + }, + { + "cell_type": "code", + "execution_count": 309, + "id": "c03cac85-b10c-41a5-8c0f-8dd19d538aeb", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
TruthIPWSNIPWlinearG-computationMR
00.3574020.3524600.3524600.3493570.3025150.352481
10.3579080.3582670.3582960.3578860.2564030.357535
20.3588980.3332630.3328750.3301530.2900080.333733
30.3597490.3543990.3543850.3508640.3189230.355388
40.3603300.3439090.3437900.3407820.2362880.344092
50.3607100.3600250.3598610.3568760.2694090.359386
60.3609610.4220340.4220310.4177720.3555090.422454
70.3611330.3358430.3359500.3328040.2802510.336579
80.3612540.4359420.4358860.4355830.3765360.436722
90.3613420.3608320.3608300.3572710.3055340.361261
100.3614080.3666850.3667480.3637640.2876680.365552
\n", + "
" + ], + "text/plain": [ + " Truth IPW SNIPW linear G-computation MR\n", + "0 0.357402 0.352460 0.352460 0.349357 0.302515 0.352481\n", + "1 0.357908 0.358267 0.358296 0.357886 0.256403 0.357535\n", + "2 0.358898 0.333263 0.332875 0.330153 0.290008 0.333733\n", + "3 0.359749 0.354399 0.354385 0.350864 0.318923 0.355388\n", + "4 0.360330 0.343909 0.343790 0.340782 0.236288 0.344092\n", + "5 0.360710 0.360025 0.359861 0.356876 0.269409 0.359386\n", + "6 0.360961 0.422034 0.422031 0.417772 0.355509 0.422454\n", + "7 0.361133 0.335843 0.335950 0.332804 0.280251 0.336579\n", + "8 0.361254 0.435942 0.435886 0.435583 0.376536 0.436722\n", + "9 0.361342 0.360832 0.360830 0.357271 0.305534 0.361261\n", + "10 0.361408 0.366685 0.366748 0.363764 0.287668 0.365552" + ] + }, + "execution_count": 309, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "total_effect_df" + ] + }, + { + "cell_type": "code", + "execution_count": 314, + "id": "1b8f5869-e7c9-48a7-b2b6-70b5a890f313", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5, 1.0, 'Undirect effect non treated')" + ] + }, + "execution_count": 314, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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okUMHDgQb29vfH19GTVqFLt27arR/x9//MEtt9xC69atMZlMREREcOutt5KXl+du88wzz/DYY48BEBMTc0JuAFzv+auvQ1BQEOPGjePo0aMnnM97771HbGwsZrOZPn36sGbNmtOev2j8ZOa8ELWkqipjxoxh1apV3HbbbXTv3p0lS5bw2GOPkZaWxuuvvw7A/Pnzuf322+nTpw933nknALGxsQBs2rSJ9evXM27cOFq0aEFqaiqzZ89myJAh7N69+6xngNWmv169etG6dWu++uorJkyYUGP/BQsWEBgYSGJiIuBaiKZv377uFz2hoaEsWrSI2267jeLi4hMWQp0+fToGg4FHH30Ui8WCwWBg9+7dfP/991x33XXExMSQlZXFf//7XwYPHszu3buJjIwEXB90XHLJJWRkZPDvf/+biIgIPv/8c1atWnXCea5cuZKRI0cSHx/P1KlT0Wg07jfZa9asoU+fPqe8Rk6nkzFjxrB27VruvPNOOnTowM6dO3n99dfZv38/33//PaGhocyfP5/nn3+e0tJSZsyYAUCHDh2YP38+Dz/8MC1atOCRRx4BIDQ0tFb9Vps2bRrPPPMM/fv359lnn8VgMLBx40ZWrlzJ8OHDmTVrFg888AA+Pj48+eSTAGcsnSSEEOKfGT9+PP/3f//H0qVLueOOO07bduXKlXz11Vfcf//9hISEEB0dXesx0+FwMHr0aFasWMG4ceP497//TUlJCcuWLePPP/9k6NChzJ49m3vuuYerrrqKq6++GqDGV/v/rry8nMGDB5OWlsZdd91Fy5YtWb9+PZMnTyYjI4NZs2adcgzr0aOHu87tsGHDuPnmm8+q32q33XYb8+bNY+TIkdx+++3Y7XbWrFnDhg0b6NWr12lfD/1dhw4dePbZZ5kyZQp33nknAwcOBKB///7uNnl5eYwcOZJx48Zx0003ER4eflZj8ezZs+nUqRNjxoxBp9Px448/cu+99+J0OrnvvvsATjse1/baqKrKFVdcwdq1a7n77rvp0KED33333QmvwYQQQvxFxuTzZ0w+3osvvohGo+HRRx+lqKiIl19+mRtvvJGNGze621SXLOrduzczZswgKyuLN954g3Xr1rFt27Ya3whwOBwkJiaSkJDAzJkzWb58Oa+++iqxsbHcc889p4yjNu+X7733XkJDQ5kyZQplZWWAKzczYcIE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+44777yTRx99FL1ez3PPPcddd93FJZdcwtixY0lJSeGjjz6SmvNNnSqEOKn77rtP/ft/kZKSEvXhhx9WIyMjVb1er7Zt21Z95ZVXVKfTWaPd3r171UGDBqlms1kF1AkTJqiqqqoFBQXqxIkT1ZCQENXHx0dNTExU9+7dq7Zq1crdRlVVddWqVSqgrlq16rQx1ra/asnJySqgAuratWtP2mdWVpZ63333qVFRUaper1cjIiLUSy+9VH3vvfdOiO/rr78+Yf/Kykr1kUceUZs1a6aazWb1oosuUpOSktTBgwergwcPrtH20KFD6qhRo1Sz2ayGhoaqjzzyiPrNN9+ogLphw4Yabbdt26ZeffXVanBwsGo0GtVWrVqp119/vbpixYrTXiNVVVWr1aq+9NJLaqdOnVSj0agGBgaq8fHx6rRp09SioiJ3u8GDB6udOnU6Yf9WrVqpo0aNOud+VVVV586dq/bo0cPdbvDgweqyZcvcz2dmZqqjRo1SfX19VeCEayWEEOLsfPTRR+4xD1ANBoMaERGhDhs2TH3jjTfU4uLiE/aZOnXqCWM/oN53330nPUZtxkxVVdXy8nL1ySefVGNiYtztrr32WvXgwYPuNuvXr1fj4+NVg8GgAurUqVNPe34lJSXq5MmT1TZt2qgGg0ENCQlR+/fvr86cOVO1Wq3udqcaw051XrXt1263q6+88ooaFxenGgwGNTQ0VB05cqS6ZcsWd5tTvR46lR9++EHt2LGjqtPpVED96KOPVFU99fisqrUfixcuXKh27dpVNZlManR0tPrSSy+pc+fOVQE1JSXF3e5043Ftr01eXp46fvx41c/PT/X391fHjx+vbtu2rcY5CSFEUyJjssuFMiaf6v1+SkrKSceyBQsWuN/rBgUFqTfeeKN67NixGm0mTJigent7n3Csk/2eT+ZU43P1v61Nmzad8lwSExNVf39/1WQyqbGxseott9yibt682d3m2LFj6lVXXaUGBASo/v7+6nXXXaemp6ef9Hc/ffp0tXnz5qpGoznhNcQ333yjDhgwQPX29la9vb3VuLg49b777lP37dtXo493331XjYmJUY1Go9qrVy/1t99+O2m+RDQdiqqe40oOQghRD2bNmsXDDz/MsWPHaN68uafDEUIIIYQQQgghhBCiXkhyXgjhMRUVFTVWVa+srKRHjx44HA7279/v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vP/++9x0000A7Nu3j6lTp7Jp0yYOHDjA0qVLufPOO+nRowetW7euxDMkUjWorxcpm+bRbchzKYIiqBVavPZXUtK5vwAWEalsyu0iF9agdfH6aMlpbjRs3wk3T08sWVbqpruz3NOVE5vedXKEF0eD806QmV5S1kYz50WqMsMwsGZnO+VmGMZFxfz3yyFNJhPvvPMON910E15eXjRq1IilS5faPeb333/n2muvxcfHh+DgYO644w5SU1Nt9y9btowrr7ySWrVqUbt2ba677jr27dtnu//AgQOYTCY+/PBDYmNj8fDwYNGiRRcVvzhXSSmZp59+mrZt2xIfH8+yZctsi8QeOnTIbiHXpKQk2rVrR7t27UhOTmbGjBm0a9eOu+++29bm9OnTjBkzhqZNm3LnnXdy5ZVXsnz5clxd/6zzu2TJEjp16sSwYcNo3rw506ZN47nnnuO+++4Dimf1f//99/Tt25emTZvyyCOPMHjwYL788stKOjNSk6mvL6a+XmqyNlH9SQkoniDlElwIwClLHbJT0p0ZlohUEOX2YsrtUtNEX9seDCtZrrXJ3H+cmI5XANA5JYhCk4mPts+Hi/w/6ExaENYJSmbOq6yNSNVm5OSwq30Hpzx3k982YSqnmRPPPPMM06dP56WXXmLWrFkMGzaMgwcPEhgYyKlTp+jduzd33303r776Kjk5OTz++OMMGTKEH374AYCsrCzGjx9P69atyczM5Omnn+amm24iPj7erhTJE088wcsvv0y7du3w8FD/Vl2NHTuWsWPHlnpfXFyc3e+RkZEX/AAyZMgQhgwZct42ISEhzJs375z3169fn9WrV593HyIXS329+nqp+ZqEd+NkQB71T3iRlLQNr4I6ZLsGkvjtJloM7+Ps8ESknCm3K7dLzeRVrza1ik5wyiWY/d9toelVsez4aRXBx70xNYaPLLmMTlyNW1RPZ4daJhqcd4KSmfO+Aer0RKTijRgxgltvvRWA559/nv/7v/9jw4YN9O/fn9dff5127drx/PPP29q/++671K9fn927d9O4cWMGDx5st793332XoKAgduzYQcuWLW3bx40bx80331w5ByUiInbU14ucm6vFFe/aJgCOHThCk8Bc9mfDwS3HaOHk2EREzkW5XeRsoSEmTqXC4V2naPvAtXj4+pGbcYbmab5sr5PBt+tncKMG5+V8DMMg42RJWRvVnBepykyenjT5bZPTnru8/LUmt7e3N35+fqSkpACwZcsWVq1ahY+Pz1mP27dvH40bN2bPnj08/fTT/PLLL6SmptoW6Tx06JDdm7qOHTuWW8wiIpVFfb36erk8RNWvT9H6M5BTRFATL/ZvhmOny+//oIhUHcrtyu1Sc0V2bciOL7NIyauFCRNNrujOlhXf0i2zCdvr/MqizD3ccDoJk3+os0N1mAbnK1l+TiEFeUUA+GjmvEiVZjKZyu2SRGf6a21vKD6ukjdmmZmZXH/99bz44otnPa5evXoAXH/99URERPD2228TGhqK1WqlZcuW5Ofn27X39vauoCMQEak46uvV18vloXWDbqzy/x91T3ngEu6GaVMROa4BpG7ZR5020c4OT0TKkXK7crvUXPWvbovli5UUuHhz9MdtNO0Wy5YV32I6kIVXuIkEdzd+W/sSHa591dmhOkyD85UsM7243ryHtyuu7hYnRyMil7v27dvz6aefEhkZiYvL2Snh5MmT7Nq1i7fffpurrroKgJ9//rmywxQRkUugvl4E2sQM5MOAj6h7yoPk/VsIMBqSRgj7v9+mwXkRqXaU2+Vy5eLhTpAljWOEkvjTHq6aNBif2nXIPJnK9Xkt+NDldxYdXk6HwnxwcXN2uA4xX7iJlKeMNJW0EZGqY8yYMaSlpXHrrbeyceNG9u3bx/Llyxk5ciRFRUUEBARQu3Zt5s6dy969e/nhhx8YP368s8MWEZEyUF8vAiG1GpITUDxb9GDCVsLCigezjuzNdGZYIiIXRbldLmfhMcVXeyQdycdkNtOka/EXUNEZDQFY6WYmacsCp8VXVhqcr2SZfwzO+waqpI2IOF9oaChr1qyhqKiIvn370qpVK8aNG0etWrUwm82YzWaWLFnCpk2baNmyJQ8//DAvvfSSs8MWEZEyUF8vUlwOol7d4g/zWSezCO0UBkBKQSBFeQXODE1EpMyU2+VyFnV1KwDSTEHkpZ2hWfdYAFJ+38UVlmCsJhNLtr7jzBDLRGVtKllGWnFZG9WbF5HyEhcXZ/v5wIEDdvcZhnFW+1OnTtn93qhRIz777LNz7r9Pnz7s2LHjnPuNjIws9XlERKT8qK8XuXQtQ1tw0Hs3/lmuEGTBpTCbQhcvDq2Mp+GATs4OT0QuM8rtIhendpsoPAu2kuNai/3LNtH01p4E1AslPTmJ/m79WJ/zPp8ap7nvyK94hVf9BY81c76SZaarrI2IiIiIiEhlax3Rk+MBxZOlkvckUNftFAAH1u13YlQiIiJSFmazmWDfbAAObU7CZDLRpFvx7HnT/izCTW6csVj4at00Z4bpMA3OV7IMlbURERERERGpdC0a9iO1VvHnsQNbfyG8sR8ASclWZ4YlIiIiZdSgdTAAyWnFi7427d4DgINbN3NLvQEALD69HSM73TkBloEG5ytZ5h9lbTQ4LyIiIiIiUnm83H3wCCweiD9x+CiRvZoBcMoSRPbxNGeGJiIiImUQfW17MKxkudYmfechaofVJygyCmtREc2K2uNlwD5XF9atne7sUC+oSgzOz549m8jISDw8POjSpQsbNmw4Z9u3336bq666ioCAAAICAujTp0+p7RMSErjhhhvw9/fH29ubTp06cejQoYo8jAuyWg0yT5XUnFdZGxERERERkcrUuG4IOW5FGEUGBZ6FeBecBJOZ/d9scnZoFaIsn7W3b9/O4MGDiYyMxGQyMXPmzLPaZGRkMG7cOCIiIvD09KRbt25s3LjRrk1mZiZjx44lPDwcT09PmjdvzptvvmnXpmfPnphMJrvbfffdVy7HLCIiNZ9XvdrUKjoBwP7vtgDQtFvx7PkDv2xgUO02ACw68DVYq/YVck4fnP/www8ZP348kydP5rfffqNNmzb069ePlJSUUtvHxcVx6623smrVKtatW0f9+vXp27cvR48etbXZt28fV155JU2bNiUuLo6tW7cyadIkPDycO1s9+3Q+htXAZDbh5a/BeRERERERkcrUOqQjJ/6oO390VwIhAfkAHNp63JlhVYiyftbOzs4mKiqKadOmERISUmqbu+++mxUrVrBgwQK2bdtG37596dOnj93n8fHjx7Ns2TIWLlxIQkIC48aNY+zYsSxdutRuX6NHjyY5Odl2mz696s9uFBGRqiM0xATA4V2ngD8H5w8n/M5NzcZiMgx+dDU4uP0jZ4XoEKcPzr/yyiuMHj2akSNH2r5R9/Ly4t133y21/aJFi3jggQdo27YtTZs25Z133sFqtbJy5Upbm6eeeooBAwYwffp02rVrR3R0NDfccAN169atrMMqlW0x2FrumM0mp8YiIiIiIiJyuWkdfa1tUdgj2+OJaFcPgGNnPJ0ZVoUo62ftTp068dJLL3HLLbfg7n72ZLKcnBw+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IiIiIiJSyTQ4LyIiIiIiIiIiIiJSyTQ4X8Hc3d2ZPHky7u7uzg6lytO5KhudL8fpXJWNzpfjdK4uT/q7O07nqmx0vhync1U2Ol+O07m6POnv7jidK8fpXJWNzpfjdK7KpqqfLy0IKyIiIiIiIiIiIiJSyTRzXkRERERERERERESkkmlwXkRERERERERERESkkmlwXkRERERERERERESkkmlwXkRERERERERERESkkmlwXkRERERERERERESkkmlwvhzMnj2byMhIPDw86NKlCxs2bDhv+48//pimTZvi4eFBq1at+OabbyopUucry7l6++23ueqqqwgICCAgIIA+ffpc8NzWNGV9bZVYsmQJJpOJQYMGVWyAVUhZz9WpU6cYM2YM9erVw93dncaNG+v/4nnMnDmTJk2a4OnpSf369Xn44YfJzc2tpGid58cff+T6668nNDQUk8nEF198ccHHxMXF0b59e9zd3YmJiWH+/PkVHqeUP+V2xym3l41yu+OU2x2nvO445fbLk/J62Si3O055vWyU2x2n3O6YGpHXDbkkS5YsMdzc3Ix3333X2L59uzF69GijVq1axvHjx0ttv2bNGsNisRjTp083duzYYfz73/82XF1djW3btlVy5JWvrOfqtttuM2bPnm1s3rzZSEhIMEaMGGH4+/sbR44cqeTInaOs56tEYmKiERYWZlx11VXGjTfeWDnBOllZz1VeXp7RsWNHY8CAAcbPP/9sJCYmGnFxcUZ8fHwlR+4cZT1fixYtMtzd3Y1FixYZiYmJxvLly4169eoZDz/8cCVHXvm++eYb46mnnjI+++wzAzA+//zz87bfv3+/4eXlZYwfP97YsWOHMWvWLMNisRjLli2rnIClXCi3O065vWyU2x2n3O445fWyUW6//Civl41yu+OU18tGud1xyu2Oqwl5XYPzl6hz587GmDFjbL8XFRUZoaGhxgsvvFBq+yFDhhgDBw6029alSxfj3nvvrdA4q4Kynqu/KywsNHx9fY333nuvokKsUi7mfBUWFhrdunUz3nnnHWP48OGXTaIv67maM2eOERUVZeTn51dWiFVKWc/XmDFjjN69e9ttGz9+vNG9e/cKjbOqcSTRP/bYY0aLFi3stg0dOtTo169fBUYm5U253XHK7WWj3O445XbHKa9fPOX2y4PyetkotztOeb1slNsdp9x+caprXldZm0uQn5/Ppk2b6NOnj22b2WymT58+rFu3rtTHrFu3zq49QL9+/c7Zvqa4mHP1d9nZ2RQUFBAYGFhRYVYZF3u+nn32WerWrctdd91VGWFWCRdzrpYuXUrXrl0ZM2YMwcHBtGzZkueff56ioqLKCttpLuZ8devWjU2bNtkuo9u/fz/ffPMNAwYMqJSYq5PLtY+vSZTbHafcXjbK7Y5Tbnec8nrFu1z7+JpCeb1slNsdp7xeNsrtjlNur1hVsY93cdoz1wCpqakUFRURHBxstz04OJidO3eW+phjx46V2v7YsWMVFmdVcDHn6u8ef/xxQkNDz/pPVBNdzPn6+eef+e9//0t8fHwlRFh1XMy52r9/Pz/88APDhg3jm2++Ye/evTzwwAMUFBQwefLkygjbaS7mfN12222kpqZy5ZVXYhgGhYWF3HfffTz55JOVEXK1cq4+/syZM+Tk5ODp6emkyMRRyu2OU24vG+V2xym3O055veIpt1dvyutlo9zuOOX1slFud5xye8WqinldM+elWpg2bRpLlizh888/x8PDw9nhVDkZGRnccccdvP3229SpU8fZ4VR5VquVunXrMnfuXDp06MDQoUN56qmnePPNN50dWpUUFxfH888/zxtvvMFvv/3GZ599xtdff83UqVOdHZqIVGPK7een3F42yu2OU14XkYqi3H5uyutlp9zuOOX26k0z5y9BnTp1sFgsHD9+3G778ePHCQkJKfUxISEhZWpfU1zMuSoxY8YMpk2bxvfff0/r1q0rMswqo6zna9++fRw4cIDrr7/ets1qtQLg4uLCrl27iI6OrtigneRiXlv16tXD1dUVi8Vi29asWTOOHTtGfn4+bm5uFRqzM13M+Zo0aRJ33HEHd999NwCtWrUiKyuLe+65h6eeegqzWd/zljhXH+/n56eZddWEcrvjlNvLRrndccrtjlNer3jK7dWb8nrZKLc7Tnm9bJTbHafcXrGqYl7XX+cSuLm50aFDB1auXGnbZrVaWblyJV27di31MV27drVrD7BixYpztq8pLuZcAUyfPp2pU6eybNkyOnbsWBmhVgllPV9NmzZl27ZtxMfH22433HADvXr1Ij4+nvr161dm+JXqYl5b3bt3Z+/evbY3QwC7d++mXr16NTbBl7iY85WdnX1WMi95g2QYRsUFWw1drn18TaLc7jjl9rJR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nToxdepUhg4dyrp163j99dd54403AGjcuDHDhg3jzjvv5OWXX6Zdu3acOHGClStX0rp1awYOHOjg2T7b5MmTufrqq4mOjuaWW26hsLCQb775hscff/ystuV1niMjI/nll184cOAAPj4+BAYGMmXKFDp06ECLFi3Iy8vjq6++OuebJhERqdqU25XbldtFRGoW5XblduV2qao0c16kHEybNo3Bgwdzxx130L59e/bu3cvy5csJCAiwazds2DC2bNnCTTfdZHdZl8lk4ptvvqFHjx6MHDmSxo0bc8stt3Dw4EGCg4MdjiMoKIj58+fz8ccf07x5c6ZNm3bOy7OmTZvGQw89RIcOHTh27Bhffvklbm5u59z3p59+SqdOnbj11ltp3rw5jz32mO1b6Pbt2/PRRx+xZMkSWrZsydNPP82zzz5rt9r8vHnzuPPOO3nkkUdo0qQJgwYNYuPGjTRo0MDh4ytNz549+fjjj1m6dClt27ald+/ebNiwodS25XWeH330USwWC82bN7ddgujm5sbEiRNp3bo1PXr0wGKxsGTJkks6NhERcR7lduV25XYRkZpFuV25XbldqiKTYRiGs4MQkcoTFxdHr169SE9Pt6vXJiIiItWTcruIiEjNotwucvnQzHkRERERERERERERkUqmwXkRERERERERERERkUqmsjYiIiIiIiIiIiIiIpVMM+dFRERERERERERERCqZBudFRERERERERERERCqZBudFRERERERERERERCqZBudFRERERERERERERCqZBudFRERERERERERERCqZBudFRERERERERERERCqZBudFRERERERERERERCqZBudFRERERERERERERCqZBudFylnPnj3p2bOn7fcDBw5gMpmYP3++02KqCAsWLKBp06a4urpSq1Yt2/aXXnqJqKgoLBYLbdu2dVp8l4u/v95ERORPysnKyZez+fPnYzKZOHDggLNDEREREZFz0OC81GhTpkzBZDKRmppa6v0tW7as0QObixcvZubMmeW+3507dzJixAiio6N5++23mTt3LgDfffcdjz32GN27d2fevHk8//zz5f7c33zzDVOmTHG4/RtvvOH0QZi1a9cyZcoUTp065dQ4REScSTlZObmqqQr5OTs7mylTphAXF+e0GERERETEeVycHYBITRcREUFOTg6urq6V/tyLFy/m999/Z9y4ceW637i4OKxWK6+99hoxMTG27T/88ANms5n//ve/uLm5letzlvjmm2+YPXu2w4MBb7zxBnXq1GHEiBEVEo8j1q5dyzPPPMOIESPsZjSKiEjlUk4uX2XNyVVNVcjP2dnZPPPMMwA1+sspERERESmdZs6LVDCTyYSHhwcWi+W87bKysiopokuXkpICcNYH2ZSUFDw9PStsEKCiVae/gYiIlJ1yslwsq9VKbm6us8MQERERkRpGg/MifxEXF4fJZOKjjz7iueeeIzw8HA8PD66++mr27t17Vvu5c+cSHR2Np6cnnTt35qeffjqrTWn1bUeMGIGPjw/79u1jwIAB+Pr6MmzYMKD4w9/MmTNp0aIFHh4eBAcHc++995Kenn7Wvr/99ltiY2Px9fXFz8+PTp06sXjxYqB49tXXX3/NwYMHMZlMmEwmIiMjL3gOFi5cSIcOHfD09CQwMJBbbrmFw4cP2+6PjIxk8uTJAAQFBWEymWylCubNm0dWVpbt+f56zBfab4lffvmFAQMGEBAQgLe3N61bt+a1116znbfZs2cD2J7DZDKd81giIyPZvn07q1evtrUtmZVWUod19erVPPDAA9StW5fw8HC7c3vVVVfh7e2Nr68vAwcOZPv27Xb737p1KyNGjCAqKgoPDw9CQkIYNWoUJ0+etLWZMmUKEyZMAKBhw4a2OP5a/9XRc+PI601EpKZQTq5ZObkk3uuuu46ff/6Zzp074+HhQVRUFO+///5Zbffv388///lPAgMD8fLy4oorruDrr7+2a1PW18hfXSg/m0wmxo4dy6JFi2jRogXu7u4sW7YMgKNHjzJq1CiCg4Nxd3enRYsWvPvuu3b7z8/P5+mnn6ZDhw74+/vj7e3NVVddxapVq2xtDhw4QFBQEADPPPOMLYa/Xomwc+dO/vGPfxAYGIiHhwcdO3Zk6dKlZx3P9u3b6d27N56enoSHh/Of//wHq9V63nMgIiIiIs6nsjYipZg2bRpms5lHH32U06dPM336dIYNG8Yvv/xia/Pf//6Xe++9l27dujFu3Dj279/PDTfcQGBgIPXr17/gcxQWFtKvXz+uvPJKZsyYgZeXFwD33nsv8+fPZ+TIkTz44IMkJiby+uuvs3nzZtasWWO7FH/+/PmMGjWKFi1aMHHiRGrVqsXmzZtZtmwZt912G0899RSnT5/myJEjvPrqqwD4+PicN6bnnnuOSZMmMWTIEO6++25OnDjBrFmz6NGjB5s3b6ZWrVrMnDmT999/n88//5w5c+bg4+ND69atiYmJYe7cuWzYsIF33nkHgG7dujm8X4AVK1Zw3XXXUa9ePR566CFCQkJISEjgq6++4qGHHuLee+8lKSmJFStWsGDBggue45kzZ/Kvf/0LHx8fnnrqKQCCg4Pt2jzwwAMEBQXx9NNP22ZKLliwgOHDh9OvXz9efPFFsrOzmTNnDldeeSWbN2+2DaisWLGC/fv3M3LkSEJCQti+fTtz585l+/btrF+/HpPJxM0338zu3bv54IMPePXVV6lTpw6A7cO4o+fmUl9vIiLVlXJyzcjJJfbu3cs//vEP7rrrLoYPH867777LiBEj6NChAy1atADg+PHjdOvWjezsbB588EFq167Ne++9xw033MAnn3zCTTfdZLdPR14jf3eh/AzFpYE++ugjxo4dS506dYiMjOT48eNcccUVtsH7oKAgvv32W+666y7OnDljK1t05swZ3nnnHW699VZGjx5NRkYG//3vf+nXrx8bNmygbdu2BAUFMWfOHO6//35uuukmbr75ZgBat24NFA+4d+/enbCwMJ544gm8vb356KOPGDRoEJ9++qntPBw7doxevXpRWFhoazd37lw8PT0d/ruIiIiIiJMYIjXY5MmTDcA4ceJEqfe3aNHCiI2Ntf2+atUqAzCaNWtm5OXl2ba/9tprBmBs27bNMAzDyM/PN+rWrWu0bdvWrt3cuXMNwG6fiYmJBmDMmzfPtm348OEGYDzxxBN28fz0008GYCxatMhu+7Jly+y2nzp1yvD19TW6dOli5OTk2LW1Wq22nwcOHGhERESc+wT9xYEDBwyLxWI899xzdtu3bdtmuLi42G0/13kdPny44e3tfVH7LSwsNBo2bGhEREQY6enp5zymMWPGGGXpuv7+Ny4xb948AzCuvPJKo7Cw0LY9IyPDqFWrljF69Gi79seOHTP8/f3ttmdnZ5+13w8++MAAjB9//NG27aWXXjIAIzEx0a6to+emLK83EZGqSjlZOTkiIuKsHJmSkmK4u7sbjzzyiG3buHHjDMD46aefbNsyMjKMhg0bGpGRkUZRUZFhGI6/Rs7lXPnZMAwDMMxms7F9+3a77XfddZdRr149IzU11W77LbfcYvj7+9veGxQWFtrFZBiGkZ6ebgQHBxujRo2ybTtx4oQBGJMnTz4rhquvvtpo1aqVkZuba9tmtVqNbt26GY0aNbJtKzlfv/zyi21bSkqK4e/vf87jExEREZGqQWVtREoxcuRIuxqtV111FVB8iTXAr7/+SkpKCvfdd59duxEjRuDv7+/w89x///12v3/88cf4+/tzzTXXkJqaart16NABHx8f26XQK1asICMjgyeeeAIPDw+7fVzokvJz+eyzz7BarQwZMsTuuUNCQmjUqJHdZdgVsd/NmzeTmJjIuHHjzqqbe7HH5IjRo0fb1R5esWIFp06d4tZbb7WL12Kx0KVLF7vz8NcZabm5uaSmpnLFFVcA8Ntvv13wuR09N+X1ehMRqY6Uk2tWTm7evLntbwjFM9WbNGli+3tC8UKznTt35sorr7Rt8/Hx4Z577uHAgQPs2LHDbp8Xeo1crNjYWJo3b2773TAMPv30U66//noMw7A7h/369eP06dO2/G+xWGwxWa1W0tLSKCwspGPHjg69R0hLS+OHH35gyJAhZGRk2J7n5MmT9OvXjz179nD06FGg+HxdccUVdO7c2fb4oKAgW3kmEREREam6VNZGLnulfchs0KCB3e8BAQEAthqzBw8eBKBRo0Z27VxdXYmKinLoeV1cXOxqnAPs2bOH06dPU7du3VIfU7Lo2759+wBo2bKlQ8/liD179mAYxlnHVKLk0v2K2m9FHJMjGjZsaPf7nj17AOjdu3ep7f38/Gw/p6Wl8cwzz7BkyRLb36bE6dOnL/jcjp6b8ni9iYhUB8rJfz53Tc3Jf/97QvHf9K91/A8ePEiXLl3OatesWTPb/X+N7UKvkYv19/cIJ06c4NSpU8ydO5e5c+eW+pi/vh947733ePnll9m5cycFBQXn3G9p9u7di2EYTJo0iUmTJp3zucLCws55vpo0aXLB5xERERER59LgvNRoJTPYcnJySr0/Ozv7rFlugN1M6r8yDKPcYnN3d8dstr94xWq1UrduXRYtWlTqY/5aB7W8Wa1WTCYT3377banHf6HauJW93/Ly93qsJYunLViwgJCQkLPau7j82W0OGTKEtWvXMmHCBNq2bYuPjw9Wq5X+/fs7tAhbVT83IiLlSTnZcTU5J1fE37OiXiPneo9w++23M3z48FIfU1IvfuHChYwYMYJBgwYxYcIE6tati8Vi4YUXXrB9+XE+Jc/16KOP0q9fv1LbxMTEOHwsIiIiIlI1aXBearSIiAgAdu3addaCcNnZ2Rw+fJi+ffte9H737NljN8O6oKCAxMRE2rRpc1HxRkdH8/3339O9e/fzLuIVHR0NwO+//37eD2ZlufQ8OjoawzBo2LAhjRs3djzoctrvX4+pT58+52xX1svpy9q+JI66deueN4709HRWrlzJM888w9NPP23bXjLz3pEYHD03FfV6ExGpTMrJysmOioiIYNeuXWdt37lzp+3+8lDW+IOCgvD19aWoqOi85wXgk08+ISoqis8++8zueSZPnuxQDCVXfbi6ul7wuSIiIkp9/1HaORQRERGRqkU156VGu/rqq3Fzc2POnDlnzWSeO3cuhYWFXHvttWXeb8eOHQkKCuLNN98kPz/ftn3+/PmcOnXqouMdMmQIRUVFTJ069az7CgsLbfvu27cvvr6+vPDCC+Tm5tq1++ssMW9vb4fKqwDcfPPNWCwWnnnmmbNmmhmGwcmTJ8t4NGXbb/v27WnYsCEzZ8486xz+/ZgAh8+zt7d3mf4m/fr1w8/Pj+eff97uEvQSJ06cAP6cpff3Y5o5c2apMZQWs6PnpqJebyIilUk5WTnZUQMGDGDDhg2sW7fOti0rK4u5c+cSGRlpVwf+UpQ1fovFwuDBg/n000/5/fffz7q/5D1CSVuwP1+//PKL3TEBeHl5lRpD3bp16dmzJ2+99RbJycnnfa4BAwawfv16NmzYYHf/ua76EBEREZGqQzPnpUarW7cuTz/9NP/+97/p0aMHN9xwA15eXqxdu5YPPviAvn37cv3115d5v66urvznP//h3nvvpXfv3gwdOpTExETmzZt3STXAY2Njuffee3nhhReIj4+nb9++uLq6smfPHj7++GNee+01/vGPf+Dn58err77K3XffTadOnbjtttsICAhgy5YtZGdn89577wHQoUMHPvzwQ8aPH0+nTp3w8fE55/FGR0fzn//8h4kTJ3LgwAEGDRqEr68viYmJfP7559xzzz08+uijZT4mR/drNpuZM2cO119/PW3btmXkyJHUq1ePnTt3sn37dpYvX247JoAHH3yQfv36YbFYuOWWW875/B06dGDOnDn85z//ISYmhrp1656znjwU15SfM2cOd9xxB+3bt+eWW24hKCiIQ4cO8fXXX9O9e3def/11/Pz86NGjB9OnT6egoICwsDC+++47EhMTS40B4KmnnuKWW27B1dWV66+/3uFzU1GvNxGRyqScrJzsqCeeeIIPPviAa6+9lgcffJDAwEDee+89EhMT+fTTT88qQXSxzpWfSwbtSzNt2jRWrVpFly5dGD16NM2bNyctLY3ffvuN77//nrS0NACuu+46PvvsM2666SYGDhxIYmIib775Js2bNyczM9O2P09PT5o3b86HH35I48aNCQwMpGXLlrRs2ZLZs2dz5ZVX0qpVK0aPHk1UVBTHjx9n3bp1HDlyhC1btgDw2GOPsWDBAvr3789DDz2Et7c3c+fOJSIigq1bt5bLuRIRERGRCmKIXAYWLlxoXHHFFYa3t7fh7u5uNG3a1HjmmWeM3Nxcu3arVq0yAOPjjz+2256YmGgAxrx58+y2v/HGG0bDhg0Nd3d3o2PHjsaPP/5oxMbGGrGxsed97PDhww1vb+9zxjt37lyjQ4cOhqenp+Hr62u0atXKeOyxx4ykpCS7dkuXLjW6detmeHp6Gn5+fkbnzp2NDz74wHZ/Zmamcdtttxm1atUyACMiIuKC5+rTTz81rrzySsPb29vw9vY2mjZtaowZM8bYtWuXrc3kyZMNwDhx4oTdY893XI7s1zAM4+effzauueYaw9fX1/D29jZat25tzJo1y3Z/YWGh8a9//csICgoyTCaTcaFu7NixY8bAgQMNX19fA7D9bebNm2cAxsaNG0t93KpVq4x+/foZ/v7+hoeHhxEdHW2MGDHC+PXXX21tjhw5Ytx0001GrVq1DH9/f+Of//ynkZSUZADG5MmT7fY3depUIywszDCbzQZgJCYmlvncOPJ6ExGp6pSTL9+cHBERYQwcOPCs7aXlsn379hn/+Mc/jFq1av0/e/cdHld1rQ38PedMb5JGXbJsuffesE0vNpDQQyDUmMBN+OxQHBIgCXAJLYRyCQmEQCjpgdA7GINtcMe9SW6yZKt3afrMOef7YzQjyVVlmmbe3/PokXQ0ZWkQ3rPXXntt1WAwqLNmzVI//PDDbrfp7d/IsRxvfAagLlq06Jj3qa2tVRctWqQWFRWpWq1WzcvLU8855xz1xRdfDN9GURT10UcfVYcMGaLq9Xp16tSp6ocffqjeeOONR/23X716tTp9+nRVp9Md9R5i//796g033KDm5eWpWq1WLSwsVL/73e+qb775ZrfH2LZtm3rGGWeoBoNBLSwsVB966CH15ZdfPuo9BxERERElFkFVI3iaFhERERERERERERERnRR7zhMRERERERERERERxRiT80REREREREREREREMcbkPBERERERERERERFRjDE5T0RERERERER9tnLlSlx00UUoKCiAIAh49913T3qf5cuXY9q0adDr9RgxYgRee+21qMdJRESUaJicJyIiIiIiIqI+czqdmDx5Mp577rke3b6srAzf+c53cNZZZ2HLli244447cPPNN+Ozzz6LcqRERESJRVBVVY13EEREREREREQ08AmCgHfeeQeXXnrpcW9z991346OPPsKOHTvC166++mq0tLTg008/jUGUREREiUET7wASkaIoqKqqgtVqhSAI8Q6HiIhSgKqqaG9vR0FBAUSRG9sijWM7ERHFGsf241uzZg3OPffcbtcWLFiAO+6447j38Xq98Hq94e8VRUFTUxMyMzM5thMRUUxEY2xncv4YqqqqUFRUFO8wiIgoBR06dAiDBg2KdxhJh2M7ERHFC8f2o9XU1CA3N7fbtdzcXLS1tcHtdsNoNB51n8ceewwPPvhgrEIkIiI6rkiO7UzOH4PVagUQfKFtNlucoyEiolTQ1taGoqKi8BhEkcWxnYiIYo1je2Tde++9WLJkSfj71tZWDB48mGM7ERHFTDTGdibnjyG0Jc5ms3GQJyKimOK27Ojg2E5ERPHCsf1oeXl5qK2t7XattrYWNpvtmFXzAKDX66HX64+6zrGdiIhiLZJjOxvfEREREREREVHMzJkzB8uWLet2benSpZgzZ06cIiIiIooPJueJiIiIiIiIqM8cDge2bNmCLVu2AADKysqwZcsWVFRUAAi2pLnhhhvCt//JT36CAwcO4Be/+AVKSkrw/PPP44033sCdd94Zj/CJiIjihsl5IiIiIiIiIuqzb7/9FlOnTsXUqVMBAEuWLMHUqQLGO74AAPh4SURBVFNx//33AwCqq6vDiXoAGDp0KD766CMsXboUkydPxlNPPYW//OUvWLBgQVziJyIiihf2nCciIiIiIiKiPjvzzDOhqupxf/7aa68d8z6bN2+OYlRERESJj5XzREREREREREREREQxxuQ8EREREREREREREVGMMTlPRERERERERERERBRjTM4TEREREREREREREcUYk/NERERERERERERERDHG5DwRERERERERERER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p/H5558bn9doNEhLS0Pv3r2NF+9/lZ6ejieffNJk28CBA7FixQqTbT179jT+bKgt3qNHD5NtlZWVKCkpgY+PDwCgTZs2xot3AOjfvz/0ej1OnTrVqPqwOp0Ob731Fr788ktcunQJWq0WVVVVUKvVFh0nPT0dDz74oMm2gQMHYvny5dDpdJDLa0c/3vzeBUFAcHAw8vPzGxw/OQ+uJUPkfJjbmduZ24mIiMiRsHPeTjSFtZ3zXn68gCdyFoIgmD39XEodOnSAIAg4deqUyfZ27doBADw8PAAA8+fPNxl1dvNzjeXufqNcl2GafX3bDFPqzSGTySCKosm26urqO+737rvvYsWKFVi+fDl69OgBT09PPPfcc9BqtWa/tiVufp9A7Xu15H2S89IYb7wztxM5C+Z28zG338DcTkRERLbS+OEbZBbN9bq0vIAnImtr3rw5hg8fjlWrVqGsrOyW7QIDA9GhQwfjA6gdGZaWloZr167Vu0/Xrl2xd+9ek2179+5FREREo+POzs7G5cuXjb//9ttvkMlkxinjAQEByMnJMT6v0+lw/Phxk2MoFArodLo68T344IP429/+hl69eqFdu3Y4ffr0Hff7q1u9906dOhlH1lHTZpgV58WyNkRkZcztzO1ERETUNLBz3k5KC3kBT0S28/7776OmpgYxMTHYvHkz0tPTcerUKXz++ec4efLkLS84H330UQQHByMhIQF79+7F+fPn8c0332D//v0AgBdffBHr16/H6tWrcebMGSxduhRbtmypM0qvIVQqFSZNmoSjR4/il19+wbPPPotHHnnEOO192LBh+O677/Ddd9/h5MmTmDZtGoqKikyOER4ejp9//hmXLl1CQUEBAKBjx47YtWsX9u3bh/T0dDz11FPIy8urs9+BAweQmZmJgoKCekfDPf/880hOTsaCBQtw+vRp/Pvf/8aqVaus8t7JNbCsDRHZEnM7czsRERG5PnbO24lh6jsv4InIFtq3b48jR44gLi4Os2bNQq9evRATE4OVK1fihRdewIIFC+rdT6FQ4Mcff0RgYCBGjhyJHj16YNGiRcYL/oSEBKxYsQKLFy9Gt27d8MEHH+CTTz7BkCFDGh1zhw4d8H//938YOXIk7r33XvTs2RPvv/++8fnHH38ckyZNwsSJExEbG4t27dqZLFQH1E7nz8zMRPv27REQEAAAmD17NqKiohAfH48hQ4YYOyhu9sILL0AulyMiIgIBAQHIzs6uE19UVBS+/PJLbNq0Cd27d8fcuXMxf/58kwXjqOmqqqiBtqIGAG+8E5FtMLcztxMREZHrE8S/Fv0jlJSUwNfXF8XFxcbFjRrro6SfUVVeg0fn9oN/iKdVjklE1lVZWYmMjAy0bdsWKhVvpNnS66+/jq1btyItLU3qUOzqdn9jtsg9dIO1z+/VSxpsWnAQSrUbnlg62AoREpG1Ma/bF3M7c7u98fwSEZG92SL3cOS8HWgralBVfn10nT9H1xERETk7lrQhIiIiIiKixmLnvB0Y6s0r1W5QqNwkjoaIiIgay7AYrDdL2hAREREREVEDsXPeDoyj6/w4uo6ICKid+t7Upr2Ta+FaMkREppjbiYiIiCzHznk7MFzAe7OkDRERkUsw3Hj3Zuc8ERERERERNRA75+3AMPWdI+eJiIhcw43czhvvRERERERE1DDsnLeDG4vG8QKeiIjIFWgKWdaGiIiIiIiIGoed83Zwo6wNL+CJiIicnagXWdaGiIiIiIiIGo2d83bAsjZERESuo7xUC71OhCAAnr4KqcMhIiIiIiIiJ8XOeRsT9SI0RSxrQ0RE5Co012rzumczJWRyfpUiIiIiIiKihuEVpY2Vl2qhr7k+uq4ZO+eJiIicHWfEERERERERkTWwc97GDKPr1L5KyDm6johsYPLkyRAEAU8//XSd56ZPnw5BEDB58mSTtoIgwN3dHW3btsVLL72EyspKO0dN5LxuLAbLm+5EZBvM7URERERNA3uLbcxwAe/NC3gisqHQ0FBs2rQJFRUVxm2VlZXYuHEj2rRpY9J2xIgRyMnJwfnz57Fs2TJ88MEHmDdvnr1DJnJahhvv3hw5T0Q2xNxORERE5PrcpA7A1RmnvvvzAp7I2YiiiJqqKkle202phCAIZrePiorCuXPnsGXLFkyYMAEAsGXLFrRp0wZt27Y1aatUKhEcHAyg9sI/Li4Ou3btwttvv229N0DkwkoLmduJnBVzOxERERE5EnbO25hhdB3r0hI5n5qqKvxr0v+T5LWf/ffXcFdZ9rnx+OOP45NPPjFewK9btw6JiYlISUm55T7Hjx/Hvn37EBYW1phwiZoUjbHmPGfFETkb5nYiIiIiciQsa2NjLGtDRPbyt7/9Db/++iuysrKQlZWFvXv34m9/+1uddtu3b4eXlxdUKhV69OiB/Px8vPjiixJETOScSguvl7XhyHkisjHmdiIiIiLXxpHzNmYsa8OR80ROx02pxLP//lqy17ZUQEAARo0ahfXr10MURYwaNQotWrSo027o0KFYvXo1ysrKsGzZMri5ueGhhx6yRthELq+mWoeKEi0Ads4TOSPmdiIiIiJyJOyctzGOriNyXoIgWDz9XGqPP/44ZsyYAQB477336m3j6emJDh06AKidHt+rVy98/PHHmDJlit3iJHJWmut53c1dBqUnv0YRORvmdiIiIiJyJCxrY0O6ar1xdJ0Xy9oQkR2MGDECWq0W1dXViI+Pv2N7mUyGV199FbNnz0ZFRYUdIiRybobOeS9/lUULOxIRNRRzOxEREZHrYue8DdVU69C5XzBCu/pB5ekudThE1ATI5XKkp6fjxIkTkMvlZu3z8MMPQy6X33I0HhHdoFDJ0SE6EG26+UsdChE1EcztRERERK6LnfM2pFS7Iy4xAg/M7M3RdURkNz4+PvDx8TG7vZubG2bMmIF33nkHZWVlNoyMyPkFhvkgfmp33P1IJ6lDIaImhLmdiIiIyDUJoiiKUgfhaEpKSuDr64vi4mKLvgQTkXOrrKxERkYG2rZtC5WT1aMl53C7vzHmHtvi+SVqepjXyR6Y26XD80tERPZmi9zDkfNERERERERERERERHbGznkiIiIiIiIiIiIiIjtj5zwRERERERERERERkZ2xc56IiIiIiIiIiIiIyM7YOU9E9BdcJ5tshX9bRET2x89esiX+fREREVFjsHOeiOg6uVwOANBqtRJHQq6qvLwcAODu7i5xJERErs/wWWv47CWyBeZ2IiIiagw3qQMgInIUbm5uUKvVuHLlCtzd3SGT8f4lWYcoiigvL0d+fj6aNWtmvBFERES2I5fL0axZM+Tn5wMA1Go1BEGQOCpyFcztREREZA3snCciuk4QBLRs2RIZGRnIysqSOhxyQc2aNUNwcLDUYRARNRmGz1xDBz2RtTG3ExERUWOwc56I6CYKhQIdO3ZkaRuyOnd3d46qIyKyM8ON98DAQFRXV0sdDrkY5nYiIiJqLHbOExH9hUwmg0qlkjoMIiIishK5XM5OVCIiIiJyOCyoTERERERERESN8t577yE8PBwqlQr9+vXDwYMHb9v+q6++QpcuXaBSqdCjRw/s2LHDTpESERE5DnbOExEREREREVGDbd68GUlJSZg3bx4OHz6MXr16IT4+/pbrPezbtw+PPvoopkyZgiNHjiAhIQEJCQk4fvy4nSMnIiKSFjvniYiIiIiIiKjBli5diqlTpyIxMRERERFYs2YN1Go11q1bV2/7FStWYMSIEXjxxRfRtWtXLFiwAFFRUVi1apWdIyciIpIWa87XQxRFAEBJSYnEkRARUVNhyDmGHETWxdxORET21lRyu1arRWpqKmbNmmXcJpPJEBcXh/3799e7z/79+5GUlGSyLT4+Hlu3br3l61RVVaGqqsr4e3FxMQDmdiIish9b5HZ2ztejtLQUABAaGipxJERE1NSUlpbC19dX6jBcDnM7ERFJxdVze0FBAXQ6HYKCgky2BwUF4eTJk/Xuk5ubW2/73NzcW77OwoUL8cYbb9TZztxORET2dvXqVavldnbO1yMkJAQXLlyAt7c3BEFo1LFKSkoQGhqKCxcuwMfHx0oRuiaeK8vwfJmP58oyPF/ms+a5EkURpaWlCAkJsVJ0dDPmdmnwXFmG58t8PFeW4fkyH3O745o1a5bJaPuioiKEhYUhOzvbpW9+2AM/I6yH59J6eC6th+fSeoqLi9GmTRv4+/tb7ZjsnK+HTCZD69atrXpMHx8f/gcwE8+VZXi+zMdzZRmeL/NZ61zxwtJ2mNulxXNlGZ4v8/FcWYbny3zM7eZr0aIF5HI58vLyTLbn5eUhODi43n2Cg4Mtag8ASqUSSqWyznZfX1/+XVsJPyOsh+fSengurYfn0npkMust48oFYYmIiIiIiIioQRQKBaKjo5GcnGzcptfrkZycjP79+9e7T//+/U3aA8CuXbtu2Z6IiMhVceQ8ERERERERETVYUlISJk2ahJiYGPTt2xfLly9HWVkZEhMTAQATJ05Eq1atsHDhQgDAzJkzERsbiyVLlmDUqFHYtGkTfv/9d3z44YdSvg0iIiK7Y+e8jSmVSsybN6/e6XdkiufKMjxf5uO5sgzPl/l4rpom/rubj+fKMjxf5uO5sgzPl/l4rhpm7NixuHLlCubOnYvc3FxERkZi586dxkVfs7OzTUoADBgwABs3bsTs2bPx6quvomPHjti6dSu6d+9u9mvy38p6eC6th+fSengurYfn0npscS4FURRFqx2NiIiIiIiIiIiIiIjuiDXniYiIiIiIiIiIiIjsjJ3zRERERERERERERER2xs55IiIiIiIiIiIiIiI7Y+c8EREREREREREREZGdsXPeCt577z2Eh4dDpVKhX79+OHjw4G3bf/XVV+jSpQtUKhV69OiBHTt22ClS6VlyrtauXYu7774bfn5+8PPzQ1xc3B3Praux9G/LYNOmTRAEAQkJCbYN0IFYeq6Kioowffp0tGzZEkqlEp06deL/xdtYvnw5OnfuDA8PD4SGhuIf//gHKisr7RStdH7++WeMHj0aISEhEAQBW7duveM+KSkpiIqKglKpRIcOHbB+/Xqbx0nWx9xuPuZ2yzC3m4+53XzM6+ZjbncuzMfWw3xtPczl1sNcbz38LtB4kn1HEKlRNm3aJCoUCnHdunXin3/+KU6dOlVs1qyZmJeXV2/7vXv3inK5XHznnXfEEydOiLNnzxbd3d3FY8eO2Tly+7P0XI0fP1587733xCNHjojp6eni5MmTRV9fX/HixYt2jlwalp4vg4yMDLFVq1bi3XffLT744IP2CVZilp6rqqoqMSYmRhw5cqT466+/ihkZGWJKSoqYlpZm58ilYen52rBhg6hUKsUNGzaIGRkZ4g8//CC2bNlS/Mc//mHnyO1vx44d4muvvSZu2bJFBCB+++23t21//vx5Ua1Wi0lJSeKJEyfElStXinK5XNy5c6d9AiarYG43H3O7ZZjbzcfcbj7mdcswtzsP5mPrYb62HuZy62Gutx5+F7AOqb4jsHO+kfr27StOnz7d+LtOpxNDQkLEhQsX1tv+kUceEUeNGmWyrV+/fuJTTz1l0zgdgaXn6q9qampEb29v8d///retQnQoDTlfNTU14oABA8SPPvpInDRpUpNJ+paeq9WrV4vt2rUTtVqtvUJ0KJaer+nTp4vDhg0z2ZaUlCQOHDjQpnE6GnOS80svvSR269bNZNvYsWPF+Ph4G0ZG1sbcbj7mdsswt5uPud18zOsNx9zu2JiPrYf52nqYy62Hud56+F3A+uz5HYFlbRpBq9UiNTUVcXFxxm0ymQxxcXHYv39/vfvs37/fpD0AxMfH37K9q2jIufqr8vJyVFdXw9/f31ZhOoyGnq/58+cjMDAQU6ZMsUeYDqEh52rbtm3o378/pk+fjqCgIHTv3h1vvfUWdDqdvcKWTEPO14ABA5CammqcFnf+/Hns2LEDI0eOtEvMzqSpfsa7EuZ28zG3W4a53XzM7eZjXre9pvoZLzXmY+thvrYe5nLrYa63Hn4XkI618o6bNYNqagoKCqDT6RAUFGSyPSgoCCdPnqx3n9zc3Hrb5+bm2ixOR9CQc/VXL7/8MkJCQur84buihpyvX3/9FR9//DHS0tLsEKHjaMi5On/+PP73v/9hwoQJ2LFjB86ePYtnnnkG1dXVmDdvnj3ClkxDztf48eNRUFCAQYMGQRRF1NTU4Omnn8arr75qj5Cdyq0+40tKSlBRUQEPDw+JIiNzMbebj7ndMszt5mNuNx/zuu0xt0uD+dh6mK+th7ncepjrrYffBaRjre8IHDlPTmHRokXYtGkTvv32W6hUKqnDcTilpaV47LHHsHbtWrRo0ULqcByeXq9HYGAgPvzwQ0RHR2Ps2LF47bXXsGbNGqlDc0gpKSl466238P777+Pw4cPYsmULvvvuOyxYsEDq0IjIiTG33x5zu2WY283HvE5ElmC+bjjmcutirrcefhdwLBw53wgtWrSAXC5HXl6eyfa8vDwEBwfXu09wcLBF7V1FQ86VweLFi7Fo0SL89NNP6Nmzpy3DdBiWnq9z584hMzMTo0ePNm7T6/UAADc3N5w6dQrt27e3bdASacjfVsuWLeHu7g65XG7c1rVrV+Tm5kKr1UKhUNg0Zik15HzNmTMHjz32GJ544gkAQI8ePVBWVoYnn3wSr732GmQy3uc1uNVnvI+PD0fWOQnmdvMxt1uGud18zO3mY163PeZ2aTAfWw/ztfUwl1sPc7318LuAdKz1HYFnuxEUCgWio6ORnJxs3KbX65GcnIz+/fvXu0///v1N2gPArl27btneVTTkXAHAO++8gwULFmDnzp2IiYmxR6gOwdLz1aVLFxw7dgxpaWnGxwMPPIChQ4ciLS0NoaGh9gzfrhrytzVw4ECcPXvW+MUIAE6fPo2WLVu6fEJvyPkqLy+vk5wNX4hq10khg6b6Ge9KmNvNx9xuGeZ28zG3m4953faa6me81JiPrYf52nqYy62Hud56+F1AOlbLOxYtH0t1bNq0SVQqleL69evFEydOiE8++aTYrFkzMTc3VxRFUXzsscfEV155xdh+7969opubm7h48WIxPT1dnDdvnuju7i4eO3ZMqrdgN5aeq0WLFokKhUL8+uuvxZycHOOjtLRUqrdgV5aer79qSqvAW3qusrOzRW9vb3HGjBniqVOnxO3bt4uBgYHiP//5T6negl1Zer7mzZsnent7i1988YV4/vx58ccffxTbt28vPvLII1K9BbspLS0Vjxw5Ih45ckQEIC5dulQ8cuSImJWVJYqiKL7yyiviY489Zmx//vx5Ua1Wiy+++KKYnp4uvvfee6JcLhd37twp1VugBmBuNx9zu2WY283H3G4+5nXLMLc7D+Zj62G+th7mcuthrrcefhewDqm+I7Bz3gpWrlwptmnTRlQoFGLfvn3F3377zfhcbGysOGnSJJP2X375pdipUydRoVCI3bp1E7/77js7RywdS85VWFiYCKDOY968efYPXCKW/m3drKklfUvP1b59+8R+/fqJSqVSbNeunfjmm2+KNTU1do5aOpacr+rqavH1118X27dvL6pUKjE0NFR85plnxMLCQvsHbme7d++u93PIcH4mTZokxsbG1tknMjJSVCgUYrt27cRPPvnE7nFT4zG3m4+53TLM7eZjbjcf87r5mNudC/Ox9TBfWw9zufUw11sPvws0nlTfEQRR5HwFIiIiIiIiIiIiIiJ7Ys15IiIiIiIiIiIiIiI7Y+c8EREREREREREREZGdsXOeiIiIiIiIiIiIiMjO2DlPRERERERERERERGRn7JwnIiIiIiIiIiIiIrIzds4TEREREREREREREdkZO+eJiIiIiIiIiIiIiOyMnfNERERERERERERERHbGznkiJzdkyBA899xzUodhFVu3bkWHDh0gl8uN7+mv29avX49mzZqZfczw8HAsX77cJvESERHZAnP77TG3ExEREZGrcJM6ACIig6eeegqJiYl49tln4e3tXe82Nzc3jBw50uxjHjp0CJ6enlaNc8iQIYiMjGTHABER0R0wtxMRERER3Ro754mclFarhUKhkDoMq9FoNMjPz0d8fDxCQkJuuQ0APDw8zD5uQECA1WMlIiKyBeZ28zC3ExEREZGrYFkbIiuoqqrCs88+i8DAQKhUKgwaNAiHDh0CAOj1erRu3RqrV6822efIkSOQyWTIysoCABQVFeGJJ55AQEAAfHx8MGzYMBw9etTY/vXXX0dkZCQ++ugjtG3bFiqVqt5YPvvsM8TExMDb2xvBwcEYP3488vPzjc+npKRAEAR899136NmzJ1QqFe666y4cP378tu+xqKgITz31FIKCgqBSqdC9e3ds377d+Pw333yDbt26QalUIjw8HEuWLKlzjl544QW0atUKnp6e6NevH1JSUowxGUbTDRs2DIIg3HJbfVPf//vf/6JPnz5QqVRo0aIFxowZY3zur1PfzT3Pn332GcLDw+Hr64tx48ahtLQUADB58mTs2bMHK1asgCAIEAQBmZmZKCwsxIQJExAQEAAPDw907NgRn3zyyW3PKREROS7mduZ25nYiIiIisjV2zhNZwUsvvYRvvvkG//73v3H48GF06NAB8fHxuHbtGmQyGR599FFs3LjRZJ8NGzZg4MCBCAsLAwA8/PDDyM/Px/fff4/U1FRERUXhnnvuwbVr14z7nD17Ft988w22bNmCtLS0emOprq7GggULcPToUWzduhWZmZmYPHlynXYvvvgilixZgkOHDiEgIACjR49GdXV1vcfU6/W47777sHfvXnz++ec4ceIEFi1aBLlcDgBITU3FI488gnHjxuHYsWN4/fXXMWfOHKxfv954jBkzZmD//v3YtGkT/vjjDzz88MMYMWIEzpw5gwEDBuDUqVMAajsCcnJybrntr7777juMGTMGI0eOxJEjR5CcnIy+ffvW/w9l5nk+d+4ctm7diu3bt2P79u3Ys2cPFi1aBABYsWIF+vfvj6lTpyInJwc5OTkIDQ3FnDlzcOLECXz//fdIT0/H6tWr0aJFi1vGQUREjo25nbmduZ2IiIiIbE4kokbRaDSiu7u7uGHDBuM2rVYrhoSEiO+8844oiqJ45MgRURAEMSsrSxRFUdTpdGKrVq3E1atXi6Ioir/88ovo4+MjVlZWmhy7ffv24gcffCCKoijOmzdPdHd3F/Pz803axMbGijNnzrxlfIcOHRIBiKWlpaIoiuLu3btFAOKmTZuMba5evSp6eHiImzdvrvcYP/zwgyiTycRTp07V+/z48ePF4cOHm2x78cUXxYiICFEURTErK0uUy+XipUuXTNrcc8894qxZs0RRFMXCwkIRgLh7927j8/Vt++STT0RfX1/j7/379xcnTJhwy/cfFhYmLlu2TBRF88+zWq0WS0pKTN5Lv379jL/Xd85Hjx4tJiYm3jIOIiJyHsztzO2iyNxORERERLbHkfNEjXTu3DlUV1dj4MCBxm3u7u7o27cv0tPTAQCRkZHo2rWrcYTdnj17kJ+fj4cffhgAcPToUWg0GjRv3hxeXl7GR0ZGBs6dO2c8blhY2B3rrKampmL06NFo06YNvL29ERsbCwDIzs42ade/f3/jz/7+/ujcubMx3r9KS0tD69at0alTp3qfT09PN3n/ADBw4ECcOXMGOp0Ox44dg06nQ6dOnUze3549e0zeX0OkpaXhnnvuMautuec5PDzcOO0eAFq2bGlSPqA+06ZNw6ZNmxAZGYmXXnoJ+/bta9gbIiIiyTG3M7cDzO1EREREZHtcEJbITiZMmICNGzfilVdewcaNGzFixAg0b94cQO3iaC1btjTWab3ZzTVYPT09b/saZWVliI+PR3x8PDZs2ICAgABkZ2cjPj4eWq22wbFbskhbfTQaDeRyOVJTU43T5Q28vLwadWxLYjP3PLu7u5s8JwgC9Hr9bY993333ISsrCzt27MCuXbtwzz33YPr06Vi8eLHZ8RERkXNhbmduJyIiIiJqDI6cJ2qk9u3bQ6FQYO/evcZt1dXVOHToECIiIozbxo8fj+PHjyM1NRVff/01JkyYYHwuKioKubm5cHNzQ4cOHUweltQ2PXnyJK5evYpFixbh7rvvRpcuXW45Kuy3334z/lxYWIjTp0+ja9eu9bbt2bMnLl68iNOnT9f7fNeuXU3ePwDs3bsXnTp1glwuR+/evaHT6ZCfn1/n/QUHB5v9/m4VW3JyslltrXWeFQoFdDpdne0BAQGYNGkSPv/8cyxfvhwffvih2cckIiLHwdzO3G7A3E5EREREtsSR80SN5OnpiWnTpuHFF1+Ev78/2rRpg3feeQfl5eWYMmWKsV14eDgGDBiAKVOmQKfT4YEHHjA+FxcXh/79+yMhIQHvvPMOOnXqhMuXLxsXRIuJiTErljZt2kChUGDlypV4+umncfz4cSxYsKDetvPnz0fz5s0RFBSE1157DS1atEBCQkK9bWNjYzF48GA89NBDWLp0KTp06ICTJ09CEASMGDECzz//PPr06YMFCxZg7Nix2L9/P1atWoX3338fANCpUydMmDABEydOxJIlS9C7d29cuXIFycnJ6NmzJ0aNGmXm2a5r3rx5uOeee9C+fXuMGzcONTU12LFjB15++eU6ba11nsPDw3HgwAFkZmbCy8sL/v7+eP311xEdHY1u3bqhqqoK27dvv2WHCBEROTbmduZ25nYiIiIisgeOnCeygkWLFuGhhx7CY489hqioKJw9exY//PAD/Pz8TNpNmDABR48exZgxY0ymbAuCgB07dmDw4MFITExEp06dMG7cOGRlZSEoKMjsOAICArB+/Xp89dVXiIiIwKJFi2459XrRokWYOXMmoqOjkZubi//+979QKBS3PPY333yDPn364NFHH0VERAReeukl4wizqKgofPnll9i0aRO6d++OuXPnYv78+Zg8ebJx/08++QQTJ07E888/j86dOyMhIQGHDh1CmzZtzH5/9RkyZAi++uorbNu2DZGRkRg2bBgOHjxYb1trnecXXngBcrkcERERxvICCoUCs2bNQs+ePTF48GDI5XJs2rSpUe+NiIikw9zO3M7cTkRERES2JoiiKEodBBHZT0pKCoYOHYrCwkKTWqxERETknJjbiYiIiIicE0fOExERERERERERERHZGTvniYiIiIiIiIiIiIjsjGVtiIiIiIiIiIiIiIjsjCPniYiIiIiIiIiIiIjsjJ3zRERERERERERERER2xs55IiIiIiIiIiIiIiI7Y+c8EREREREREREREZGdsXOeiIiIiIiIiIiIiMjO2DlPRERERERERERERGRn7JwnIiIiIiIiIiIiIrIzds4TEREREREREREREdnZ/wdBGqV3ldDsfwAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, axs = plt.subplots(2, 3, figsize=(15, 9), layout='constrained')\n", + "\n", + "\n", + "axs[0][0].plot(list_overlap_coefficients, total_effect_df['Truth'], label='Truth')\n", + "axs[0][0].plot(list_overlap_coefficients, total_effect_df['IPW'], label='IPW')\n", + "axs[0][0].plot(list_overlap_coefficients, total_effect_df['SNIPW'], label='SNIPW')\n", + "axs[0][0].plot(list_overlap_coefficients, total_effect_df['linear'], label='linear')\n", + "axs[0][0].plot(list_overlap_coefficients, total_effect_df['G-computation'], label='G-computation')\n", + "axs[0][0].plot(list_overlap_coefficients, total_effect_df['MR'], label='MR')\n", + "axs[0][0].set_xlabel('overlap coefficients')\n", + "axs[0][0].set_ylabel('Total average effect')\n", + "axs[0][0].legend()\n", + "axs[0][0].set_title('Total average effect')\n", + "\n", + "axs[0][1].plot(list_overlap_coefficients, direct_effect_treated_df['Truth'], label='Truth')\n", + "axs[0][1].plot(list_overlap_coefficients, direct_effect_treated_df['IPW'], label='IPW')\n", + "axs[0][1].plot(list_overlap_coefficients, direct_effect_treated_df['SNIPW'], label='SNIPW')\n", + "axs[0][1].plot(list_overlap_coefficients, direct_effect_treated_df['linear'], label='linear')\n", + "axs[0][1].plot(list_overlap_coefficients, direct_effect_treated_df['G-computation'], label='G-computation')\n", + "axs[0][1].plot(list_overlap_coefficients, direct_effect_treated_df['MR'], label='MR')\n", + "axs[0][1].set_xlabel('overlap coefficients')\n", + "axs[0][1].set_ylabel('Direct effect treated')\n", + "axs[0][1].legend()\n", + "axs[0][1].set_title('Direct effect treated')\n", + "\n", + "axs[0][2].plot(list_overlap_coefficients, direct_effect_non_treated_df['Truth'], label='Truth')\n", + "axs[0][2].plot(list_overlap_coefficients, direct_effect_non_treated_df['IPW'], label='IPW')\n", + "axs[0][2].plot(list_overlap_coefficients, direct_effect_non_treated_df['SNIPW'], label='SNIPW')\n", + "axs[0][2].plot(list_overlap_coefficients, direct_effect_non_treated_df['linear'], label='linear')\n", + "axs[0][2].plot(list_overlap_coefficients, direct_effect_non_treated_df['G-computation'], label='G-computation')\n", + "axs[0][2].plot(list_overlap_coefficients, direct_effect_non_treated_df['MR'], label='MR')\n", + "axs[0][2].set_xlabel('overlap coefficients')\n", + "axs[0][2].set_ylabel('Direct effect non treated')\n", + "axs[0][2].legend()\n", + "axs[0][2].set_title('Direct effect non treated')\n", + "\n", + "\n", + "axs[1][0].plot(list_overlap_coefficients, indirect_effect_treated_df['Truth'], label='Truth')\n", + "axs[1][0].plot(list_overlap_coefficients, indirect_effect_treated_df['IPW'], label='IPW')\n", + "axs[1][0].plot(list_overlap_coefficients, indirect_effect_treated_df['SNIPW'], label='SNIPW')\n", + "axs[1][0].plot(list_overlap_coefficients, indirect_effect_treated_df['linear'], label='linear')\n", + "axs[1][0].plot(list_overlap_coefficients, indirect_effect_treated_df['G-computation'], label='G-computation')\n", + "axs[1][0].plot(list_overlap_coefficients, indirect_effect_treated_df['MR'], label='MR')\n", + "axs[1][0].set_xlabel('overlap coefficients')\n", + "axs[1][0].set_ylabel('Undirect effect treated')\n", + "axs[1][0].legend()\n", + "axs[1][0].set_title('Undirect effect treated')\n", + "\n", + "axs[1][1].plot(list_overlap_coefficients, indirect_effect_non_treated_df['Truth'], label='Truth')\n", + "axs[1][1].plot(list_overlap_coefficients, indirect_effect_non_treated_df['IPW'], label='IPW')\n", + "axs[1][1].plot(list_overlap_coefficients, indirect_effect_non_treated_df['SNIPW'], label='SNIPW')\n", + "axs[1][1].plot(list_overlap_coefficients, indirect_effect_non_treated_df['linear'], label='linear')\n", + "axs[1][1].plot(list_overlap_coefficients, indirect_effect_non_treated_df['G-computation'], label='G-computation')\n", + "axs[1][1].plot(list_overlap_coefficients, indirect_effect_non_treated_df['MR'], label='MR')\n", + "axs[1][1].set_xlabel('overlap coefficients')\n", + "axs[1][1].set_ylabel('Undirect effect non treated')\n", + "axs[1][1].legend()\n", + "axs[1][1].set_title('Undirect effect non treated')" + ] + }, + { + "cell_type": "code", + "execution_count": 265, + "id": "c490ff5b-d8c7-449a-b03f-1cb4d27bf386", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
TruthIPWSNIPWlinearG-computationMR
causal_effects
total effect $\\tau$0.3615310.3510760.3510720.3507340.3001380.350750
direct effect treated $\\theta(1)$0.2000000.1960000.1959050.1958930.1958930.195904
direct effect non treated $\\theta(0)$0.2000000.1959630.1958300.1958930.1958930.195913
indirect effect treated $\\delta(1)$0.1615310.1551130.1552420.1548410.1042460.154838
indirect effect untreated $\\delta(0)$0.1615310.1550760.1551660.1548410.1042460.154846
\n", + "
" + ], + "text/plain": [ + " Truth IPW SNIPW linear \\\n", + "causal_effects \n", + "total effect $\\tau$ 0.361531 0.351076 0.351072 0.350734 \n", + "direct effect treated $\\theta(1)$ 0.200000 0.196000 0.195905 0.195893 \n", + "direct effect non treated $\\theta(0)$ 0.200000 0.195963 0.195830 0.195893 \n", + "indirect effect treated $\\delta(1)$ 0.161531 0.155113 0.155242 0.154841 \n", + "indirect effect untreated $\\delta(0)$ 0.161531 0.155076 0.155166 0.154841 \n", + "\n", + " G-computation MR \n", + "causal_effects \n", + "total effect $\\tau$ 0.300138 0.350750 \n", + "direct effect treated $\\theta(1)$ 0.195893 0.195904 \n", + "direct effect non treated $\\theta(0)$ 0.195893 0.195913 \n", + "indirect effect treated $\\delta(1)$ 0.104246 0.154838 \n", + "indirect effect untreated $\\delta(0)$ 0.104246 0.154846 " + ] + }, + "execution_count": 265, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "direct_effect_treated_dic ={\n", + " 'Truth': [],\n", + " 'IPW': [],\n", + " 'SNIPW': [],\n", + " 'linear': [],\n", + " 'G-computation': [],\n", + " 'MR': []\n", + "}\n", + "\n", + "direct_effect_df = pd.DataFrame(direct_effect_treated_dic)\n", + "results_df" + ] + }, + { + "cell_type": "code", + "execution_count": 284, + "id": "d931d30d-f042-451f-8fcd-28ce76e05ef8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0.2 , 0.19599953, 0.1959052 , 0.19589261, 0.19589261,\n", + " 0.19590424])" + ] + }, + "execution_count": 284, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "results_df.iloc[1].values" + ] + }, + { + "cell_type": "code", + "execution_count": 285, + "id": "7b01bd07-0957-45b7-99f6-96e44ca1b08f", + "metadata": {}, + "outputs": [], + "source": [ + "direct_effect_df.loc[len(direct_effect_df.index)] = results_df.iloc[1].values" + ] + }, + { + "cell_type": "code", + "execution_count": 286, + "id": "a9af9306-23d8-475a-a569-5e7674d34b7d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
TruthIPWSNIPWlinearG-computationMR
00.20.1960.1959050.1958930.1958930.195904
\n", + "
" + ], + "text/plain": [ + " Truth IPW SNIPW linear G-computation MR\n", + "0 0.2 0.196 0.195905 0.195893 0.195893 0.195904" + ] + }, + "execution_count": 286, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "direct_effect_df" + ] + }, + { + "cell_type": "code", + "execution_count": 280, + "id": "04456141-479d-454e-a03e-e3103e7d5acc", + "metadata": {}, + "outputs": [ + { + "ename": "IndexError", + "evalue": "iloc cannot enlarge its target object", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[280], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mdirect_effect_df\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43miloc\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m]\u001b[49m \u001b[38;5;241m=\u001b[39m results_df\u001b[38;5;241m.\u001b[39miloc[\u001b[38;5;241m1\u001b[39m]\n", + "File \u001b[0;32m~/miniconda3/envs/mind/lib/python3.9/site-packages/pandas/core/indexing.py:882\u001b[0m, in \u001b[0;36m_LocationIndexer.__setitem__\u001b[0;34m(self, key, value)\u001b[0m\n\u001b[1;32m 880\u001b[0m key \u001b[38;5;241m=\u001b[39m com\u001b[38;5;241m.\u001b[39mapply_if_callable(key, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mobj)\n\u001b[1;32m 881\u001b[0m indexer \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_get_setitem_indexer(key)\n\u001b[0;32m--> 882\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_has_valid_setitem_indexer\u001b[49m\u001b[43m(\u001b[49m\u001b[43mkey\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 884\u001b[0m iloc \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mname \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124miloc\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mobj\u001b[38;5;241m.\u001b[39miloc\n\u001b[1;32m 885\u001b[0m iloc\u001b[38;5;241m.\u001b[39m_setitem_with_indexer(indexer, value, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mname)\n", + "File \u001b[0;32m~/miniconda3/envs/mind/lib/python3.9/site-packages/pandas/core/indexing.py:1608\u001b[0m, in \u001b[0;36m_iLocIndexer._has_valid_setitem_indexer\u001b[0;34m(self, indexer)\u001b[0m\n\u001b[1;32m 1606\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m is_integer(i):\n\u001b[1;32m 1607\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m i \u001b[38;5;241m>\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;28mlen\u001b[39m(ax):\n\u001b[0;32m-> 1608\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mIndexError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124miloc cannot enlarge its target object\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 1609\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(i, \u001b[38;5;28mdict\u001b[39m):\n\u001b[1;32m 1610\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mIndexError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124miloc cannot enlarge its target object\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", + "\u001b[0;31mIndexError\u001b[0m: iloc cannot enlarge its target object" + ] + } + ], + "source": [ + "direct_effect_df.iloc[0] = results_df.iloc[1]" + ] + }, + { + "cell_type": "code", + "execution_count": 317, + "id": "49e3480f", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n" + ] + } + ], + "source": [ + "n_samples = 10000\n", + "causal_data, causal_effects = generate_causal_data(dataset_name, n_samples, False)\n", + "x, t, m, y = causal_data\n", + "classifier_x, classifier_xm = get_classifier(params['regularization'], params['forest'], params['calibration'])\n", + "p_x, p_xm = estimate_probabilities(t, m, x, params['crossfit'], classifier_x, classifier_xm)" + ] + }, + { + "cell_type": "code", + "execution_count": 318, + "id": "024d4e12", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[1.2988589 ],\n", + " [1.35519484],\n", + " [0.43082362],\n", + " ...,\n", + " [1.50852977],\n", + " [0.61602638],\n", + " [0.39563278]])" + ] + }, + "execution_count": 318, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m" + ] + }, + { + "cell_type": "code", + "execution_count": 319, + "id": "d4a0427a-37cd-4194-91da-d6348ed1bc62", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n" + ] + } + ], + "source": [ + "x_clf = LogisticRegressionCV(Cs=cs, cv=CV_FOLDS)\n", + "xm_clf = LogisticRegressionCV(Cs=cs, cv=CV_FOLDS)\n", + "# x_clf = RandomForestClassifier(n_estimators=100, min_samples_leaf=10)\n", + "# xm_clf = RandomForestClassifier(n_estimators=100, min_samples_leaf=10)\n", + "# calib_method = 'sigmoid'\n", + "# x_clf = CalibratedClassifierCV(x_clf, method=calib_method)\n", + "# xm_clf = CalibratedClassifierCV(xm_clf, method=calib_method)\n", + " \n", + "n = len(t)\n", + "train_test_list = [[np.arange(n), np.arange(n)]]\n", + "\n", + "p_x, p_xm = [np.zeros(n) for h in range(2)]\n", + "# compute propensity scores\n", + "if len(x.shape) == 1:\n", + " x = x.reshape(-1, 1)\n", + "if len(m.shape) == 1:\n", + " m = m.reshape(-1, 1)\n", + "\n", + "train_test_list = get_train_test_lists(crossfit, n)\n", + "\n", + "for train_index, test_index in train_test_list:\n", + " x_clf = x_clf.fit(x[train_index, :], t[train_index])\n", + " xm_clf = xm_clf.fit(np.hstack((x, m))[train_index, :], t[train_index])\n", + " p_x[test_index] = x_clf.predict_proba(x[test_index, :])[:, 1]\n", + " p_xm[test_index] = xm_clf.predict_proba(\n", + " np.hstack((x, m))[test_index, :])[:, 1]\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 231, + "id": "a77836ed-b11f-4a99-b670-d50a13fc55c6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0.55134251, 0.54009824, 0.44951737, ..., 0.47679434, 0.54150298,\n", + " 0.44453564])" + ] + }, + "execution_count": 231, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "p_xm" + ] + }, + { + "cell_type": "code", + "execution_count": 232, + "id": "af950b01-7d74-4f3d-9eb0-892da36255db", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(array([[-0.14573364, 1.14127987],\n", + " [ 0.1143222 , 0.41886898],\n", + " [ 0.41700926, 0.1057243 ],\n", + " ...,\n", + " [-0.97086447, -1.2636025 ],\n", + " [-0.1728669 , 0.58630943],\n", + " [ 0.27764468, 0.1388676 ]]),\n", + " array([[1.29800425],\n", + " [1.2368184 ],\n", + " [0.55538922],\n", + " ...,\n", + " [0.83712826],\n", + " [1.24495826],\n", + " [0.51778423]]))" + ] + }, + "execution_count": 232, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x, m" + ] + }, + { + "cell_type": "code", + "execution_count": 219, + "id": "cd147283-d205-46d6-a9d8-a2b09d30dd27", + "metadata": {}, + "outputs": [], + "source": [ + "# effects_SNIPW = SNIPW(y, t, m, x, params['trim'], p_x, p_xm, params['clip'])\n", + "# effects_IPW = IPW(y, t, m, x, params['trim'], p_x, p_xm, params['clip'])\n", + "# effects_linear = ols_mediation(y, t, m, x)\n", + "# data = {'causal_effects': list_causal_effects}\n", + "# data['Truth'] = causal_effects\n", + "# data['IPW'] = effects_IPW\n", + "# data['SNIPW'] = effects_SNIPW\n", + "# data['linear'] = effects_linear\n", + "# # data['G-computation'] = effects_g_computation\n", + "# # data['MR'] = effects_MR\n", + "# df = pd.DataFrame(data)\n", + "# df = df[:-1]\n", + "# df.set_index('causal_effects', inplace=True)\n", + "# df" + ] + }, + { + "cell_type": "code", + "execution_count": 220, + "id": "af23121c-d339-4c03-832d-134f132facb0", + "metadata": {}, + "outputs": [], + "source": [ + "# effects_SNIPW" + ] + }, + { + "cell_type": "code", + "execution_count": 320, + "id": "288ce26d", + "metadata": {}, + "outputs": [], + "source": [ + "# p_x = np.ones_like(p_x)*0.5\n", + "# p_xm = np.ones_like(p_x)*0.5\n", + "\n", + "t = t.squeeze()\n", + "m = m.squeeze()\n", + "\n", + "trim, clip = params['trim'], params['clip']\n", + "ind = ((p_xm > trim) & (p_xm < (1 - trim)))\n", + "y, t, p_x, p_xm = y[ind], t[ind], p_x[ind], p_xm[ind]\n", + "\n", + "# note on the names, ytmt' = Y(t, M(t')), the treatment needs to be\n", + "# binary but not the mediator\n", + "# p_x = np.clip(p_x, clip, 1 - clip)\n", + "# p_xm = np.clip(p_xm, clip, 1 - clip)" + ] + }, + { + "cell_type": "code", + "execution_count": 321, + "id": "30c07386-25ab-4a7d-8e3d-73fe7beccc6e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0.87468474, 0.86611361, 0.10836141, ..., 0.85700136, 0.24415944,\n", + " 0.09631354])" + ] + }, + "execution_count": 321, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "p_xm" + ] + }, + { + "cell_type": "code", + "execution_count": 322, + "id": "f1d1d9e9-cfca-460e-8b34-e2c173440f4a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(array([1, 1, 0, ..., 1, 0, 0]),\n", + " array([1.2988589 , 1.35519484, 0.43082362, ..., 1.50852977, 0.61602638,\n", + " 0.39563278]))" + ] + }, + "execution_count": 322, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t, m" + ] + }, + { + "cell_type": "code", + "execution_count": 323, + "id": "cf21bee8-16b9-4340-a1a2-0957480e57be", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(array([0.49911269, 0.49910858, 0.49911134, ..., 0.49905853, 0.4991041 ,\n", + " 0.49910848]),\n", + " array([0.87468474, 0.86611361, 0.10836141, ..., 0.85700136, 0.24415944,\n", + " 0.09631354]))" + ] + }, + "execution_count": 323, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "p_x, p_xm" + ] + }, + { + "cell_type": "code", + "execution_count": 249, + "id": "adf32072-9df7-421c-ab14-6ea6568f1017", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(1.459935393087433,\n", + " 1.4510845752122383,\n", + " 0.45031871376382127,\n", + " 0.4592350721494876)" + ] + }, + "execution_count": 249, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "y1m1, y1m0, y0m0, y0m1" + ] + }, + { + "cell_type": "code", + "execution_count": 251, + "id": "aba4768d-6dd8-4409-b00a-052650e28df6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1.0096386399749133" + ] + }, + "execution_count": 251, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.mean(y[t==1]) - np.mean(y[t==0])" + ] + }, + { + "cell_type": "code", + "execution_count": 242, + "id": "bdec14fd-17f1-4798-9183-3c9afc691ee1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(array([0.52450131, 0.52802596, 0.42351199, ..., 0.41328875, 0.75890838,\n", + " 0.31698331]),\n", + " array([0.44951737, 0.44707598, 0.43042701, ..., 0.44875362, 0.47679434,\n", + " 0.44453564]),\n", + " array([[0.55538922],\n", + " [0.50750763],\n", + " [0.36399668],\n", + " ...,\n", + " [0.53309387],\n", + " [0.83712826],\n", + " [0.51778423]]))" + ] + }, + "execution_count": 242, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "y[t == 0], p_xm[t==0], m[t==0]" + ] + }, + { + "cell_type": "code", + "execution_count": 229, + "id": "56cf00d5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(array([0.49992031, 0.49999308, 0.50004991, ..., 0.49993754, 0.49994602,\n", + " 0.50002961]),\n", + " array([0.55134251, 0.54009824, 0.44951737, ..., 0.47679434, 0.54150298,\n", + " 0.44453564]))" + ] + }, + "execution_count": 229, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "p_x, p_xm" + ] + }, + { + "cell_type": "code", + "execution_count": 324, + "id": "77e2e82a", + "metadata": {}, + "outputs": [], + "source": [ + "y1m1 = np.sum(y * t / p_x) / np.sum(t / p_x)\n", + "y1m0 = np.sum(y * t * (1 - p_xm) / (p_xm * (1 - p_x))) / np.sum(t * (1 - p_xm) / (p_xm * (1 - p_x)))\n", + "y0m0 = np.sum(y * (1 - t) / (1 - p_x)) / np.sum((1 - t) / (1 - p_x))\n", + "y0m1 = np.sum(y * (1 - t) * p_xm / ((1 - p_xm) * p_x)) / np.sum((1 - t) * p_xm / ((1 - p_xm) * p_x))" + ] + }, + { + "cell_type": "code", + "execution_count": 325, + "id": "5222f22d", + "metadata": {}, + "outputs": [], + "source": [ + "total = y1m1 - y0m0\n", + "direct1 = y1m1 - y0m1\n", + "direct0 = y1m0 - y0m0\n", + "indirect1 = y1m1 - y1m0\n", + "indirect0 = y0m1 - y0m0" + ] + }, + { + "cell_type": "code", + "execution_count": 326, + "id": "85639584", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(1.0135569515076976,\n", + " 0.9705545005708663,\n", + " 0.9718376688842252,\n", + " 0.041719282623472465,\n", + " 0.04300245093683125)" + ] + }, + "execution_count": 326, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "total, direct1, direct0, indirect1, indirect0" + ] + }, + { + "cell_type": "code", + "execution_count": 327, + "id": "fc1d458c-cc45-46f6-8ec5-d928edf9d24c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[1.01, 0.2, 0.2, array([0.81]), array([0.81]), 0]" + ] + }, + "execution_count": 327, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "causal_effects" + ] + }, + { + "cell_type": "code", + "execution_count": 328, + "id": "b7ba814d-7537-404e-aaa9-cd08db28324f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[1.0137213660591147,\n", + " 0.20538623501610792,\n", + " 0.20538623501610792,\n", + " 0.8083351310430068,\n", + " 0.8083351310430068,\n", + " None]" + ] + }, + "execution_count": 328, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "effects_linear = ols_mediation(y, t, m, x)\n", + "effects_linear" + ] + }, + { + "cell_type": "code", + "execution_count": 213, + "id": "b2406285", + "metadata": {}, + "outputs": [], + "source": [ + "buckets = np.array([0., 0.2, 0.4, 0.6, 0.8, 1, 2])\n", + "inds_bucketized = np.digitize(m, buckets)\n", + "m_bucketized = buckets[inds_bucketized]" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "3b8f735b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0, 0, 0, ..., 0, 0, 1])" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "ae29514c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(0.7604472500700034, 0.9298412249266818)" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "y1m0, y1m1" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "6bec18fc", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(0.9298412249266818, 0.561811808050858)" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "y1m1, y0m0" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "4c714f42", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.7304799154421578" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "y0m1" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "f9a6ae12", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0.50738952, 0.50589069, 0.5043246 , ..., 0.51055525, 0.5073326 ,\n", + " 0.5050081 ])" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "p_x" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "9fbc7b80", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0.3441798 , 0.57279379, 0.56999283, ..., 0.34006814, 0.34241638,\n", + " 0.33865712])" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "p_xm" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "03dd5fc9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([-0.01977597, 0.83585177, 1.01397798, ..., 0.05477241,\n", + " -0.0568483 , 0.21183378])" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "y" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "f41cd741", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([1.06728555, 0.97410996, 1.02338864, ..., 0.20753601, 1.15600895,\n", + " 0.21183378])" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "y[t==1]" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "1d41ed95", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([False, False, False, ..., False, False, True])" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t.squeeze()==[1]" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "id": "f8173cc4", + "metadata": {}, + "outputs": [], + "source": [ + "n = y.shape[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "1c5246e4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.4708003280218567" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "y[t.squeeze()==[1]].sum()/n" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "1ac06044", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.2774302058941099" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "y[t.squeeze()==[0]].sum()/n" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "id": "dd96e9b3", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0.3441798 , 0.57279379, 0.56999283, ..., 0.34006814, 0.34241638,\n", + " 0.33865712])" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "p_xm" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "id": "8a42f190", "metadata": {}, "outputs": [], - "source": [] + "source": [ + "import matplotlib.pyplot as plt\n", + "import pandas as pd\n", + "from itertools import combinations\n", + "\n", + "import seaborn as sns\n", + "# sns.set_context('talk')\n", + "# sns.set_style('whitegrid')" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "3653e203", + "metadata": {}, + "outputs": [], + "source": [ + "p_t = 0.5*np.ones_like(p_x)\n", + "th_p_t_mx = 0.5*np.ones_like(p_x)" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "e1559733", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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hKtq3rFjh7p3766//vrLo8spDBw4UM2bN3eoWz0/P1+tWrXSsmXL1KFDB/cVBwAAUBv5UGAmEZoBcIPCwlMDshOi0wyHDx/TrbeurbHnLVlyaY09a+/evUpKStKWLVt0wQUX2I+/9NJLslgsbn9+TYZzK1eu1OWXX27/vn79+urYsaOeeeYZtWvXzn583LhxevDBBxUVFaWBAwdq4cKFFd7XmZ/T3Llz9e6772rz5s3Kzs5WRkaGYmNjKxwzZswYLV68WL/++muJMO+GG25QZmamVq5cqdDQUI0ePVqPP/64vv76a4frAgAAQDl8LDCTmJ4JwA1s65lZnTo9k90zUXvExMRUGuL4qh07dig1NVWfffaZMjIydM011yjzn90/Dhw4oE8++USDBg2SZA0PU1NT7S9Jmj9/fqljjsrJydE111yjsWPHVnnMU089pcjISI0aNcp+bN68efruu+80f/58BQRY/1h05513as2aNdq+fbtTtQEAAOA0PhiYSYRmANygODTLkWGYVDw9M9RTJQEVslgsmj59ulq0aKHw8HC1a9dOH374of18RkaG7rzzTjVo0EDh4eFq1aqV5s+fL0lKSkqSJLVv316GYahHjx6SrB1gN998s/0ePXr00MMPP6wRI0bojDPOUHx8vObOnauTJ09q0KBBioqK0plnnqnPP//cPsZkMmnw4MFKSkpSeHi4zj77bL300kv285MmTdLChQv18ccfyzAMGYahlStXSpIOHjyofv366YwzzlC9evV00003ae/evSXuPWrUKMXGxqpevXoaM2ZMlTu+4uLilJCQoIsvvlgvvPCC0tLStH79eknS4sWL1a5dOzVp0kSSNTxMSEiwvyQpNja21DFHjRgxQk888YQ6depU5TGhoaFauHChFi5cqC+++EIpKSkaOXKkpk+frjPPPNN+Xb169dSlSxe99957TtUGAACAU/hoYCYRmgFwg+LQLPufr7n/fKXTDN5p/Pjxmj9/vmbPnq3ff/9dI0eO1F133aVVq1ZJkp588klt27ZNn3/+ubZv367Zs2erfv36kqSffvpJkvT1118rNTVVS5cuLfc5CxcuVP369fXTTz/p4Ycf1gMPPKDbb79dXbp00ebNm9WrVy/dfffdysnJkSSZzWY1adJEixcv1rZt2zRhwgSNHTtWixcvliSNHj1affv21TXXXGPv2urSpYtycnJ0+eWXKzIyUqtXr9batWsVGRmpa665RgUFBZKkF154QfPmzdObb76ptWvX6tixY1q2bJnDP7vwcOuv68LCQknS6tWr1bFjR4fvM3XqVEVGRlb4WrNmjcP3PV2HDh2UnJysIUOG6O6779ZFF12kBx54oNR1F198sUueBwAAUKv5cGAmsaYZADf4Z5aWDOPEP0fy//lKpxm8z8mTJzVjxgx9++236ty5sySpRYsWWrt2rV5//XV1795dKSkpat++vT0Mat68uX18gwYNJFm7kyrrmmrXrp3Gjx8vSUpOTtYzzzyj+vXra+jQoZKkCRMmaPbs2frll1/UqVMnBQcHa/LkyfbxSUlJWrdunRYvXqy+ffsqMjJS4eHhys/PL/Hst99+WwEBAXrjjTdkGIYk65TI2NhYrVy5Uj179tTMmTOVnJysW2+9VZI0Z84cffnllw797I4eParJkycrKipKF198sSTrGm/OLKA/bNgw9e3bt8JrGjdu7PB9y2ILSX/88Uf9+eef9p/R6c86tTMPAAAADvLxwEwiNAPgBsWdZrY3tumZdJrB+2zbtk15eXm6+uqrSxwvKChQ+/btJUkPPPCAbr31Vm3evFk9e/bUzTffrC5dujj8rPPPP9/+PjAwUPXq1dN5551nPxYfHy9JSk9Ptx+bM2eO3njjDe3bt0+5ubkqKCgoseFAWTZt2qSdO3eW2rkyLy9Pu3btUmZmplJTU+0hoSQFBQWpY8eOVZqiaZt6efLkSbVq1UoffPCB4uLiJEm5ubkKC3N804+6deuqbt26Do9zxooVK5SamqqAgABt2LBBTZs2LXVNeHi4veMPAAAADvKDwEwiNAPgBsWhma3TjN0z4b3MZrMk6bPPPivVyRQaau2O7N27t/bt26fPPvtMX3/9ta688ko9+OCDev755x16VnBwcInvDcMocczW8WSrafHixRo5cqReeOEFde7cWVFRUXruuef0448/VvqZOnTooHfeeafUOVtnXHWsWbNG0dHRatCggaKjo0ucq1+/vjIyMhy+59SpUzV16tQKr/n888/VrVs3h+99qoyMDA0dOlRjx45VcHCwhg8fru7du9un29ocO3bMJT8rAACAWsdPAjOJ0AyAGxRPz7StaUZoBu917rnnKjQ0VCkpKerevXu51zVo0EADBw7UwIED1a1bNz322GN6/vnnFRISIsm6sL6rrVmzRl26dNHw4cPtx3bt2lXimpCQkFLPvvDCC7Vo0SLFxcWVCrVsGjZsqPXr1+uyyy6TJBUVFWnTpk268MILK60rKSmp3J1B27dvr23btlV6j9PV1PTMhx9+WHFxcRo/frwMw9BHH32khx56SO+//36J63777Td7pyEAAACqyI8CM4nQDIAblL8RQLCKiqQgfuepdeLj62rJkktr9HlVFRUVpdGjR2vkyJEym8269NJLlZWVpXXr1ikyMlL33HOPJkyYoA4dOqhNmzbKz8/X//3f/6l169aSrDtJhoeH64svvlCTJk0UFhammJgYl3yOli1b6q233tKXX36ppKQk/e9//9OGDRvsO3ZK1vXVvvzyS+3YsUP16tVTTEyM7rzzTj333HO66aabNGXKFDVp0kQpKSlaunSpHnvsMTVp0kSPPvqonnnmGbVq1UqtW7fWjBkzdPz48WrX3KtXLw0ZMkQmk0mBgYFVHufo9My0tDSlpaVp586dkqRff/1VUVFRatq0abn3WbZsmT744ANt2LDB3uG3YMECdejQQUuWLLGv7yZZA8unnnqqyvUAAADUen4WmEmEZgDcwBaaFXea5dvP5eZKpy2zhFrg668/8XQJFXrqqacUFxenadOmaffu3YqNjdWFF16osWPHSrJ2cyUnJ2vv3r0KDw9Xt27d7J1JQUFBevnllzVlyhRNmDBB3bp108qVK11S17Bhw7R161b169dPhmHojjvu0PDhw/X555/brxk6dKhWrlypjh076sSJE/ruu+/Uo0cPrV69Wo8//rj69Omj7OxsNW7cWFdeeaW98+zf//63UlNTNXDgQAUEBOjee+/VLbfcokxbq6iTrr32WgUHB+vrr79Wr169qnWvisyZM6fEJgm2jrn58+dr4MCBpa4/cuSIhg0bpokTJ5ZYW65t27aaOHFiiWmaP/zwgzIzM3Xbbbe5rX4AAAC/4oeBmSQZlqqs+OvDsrKyFBMTo8zMzHKnqABwrUcekV55RQoMfElBQc8qPz9f0lFJUnq6xDJBvq2i31fz8vK0Z88eJSUlObUYPPzDrFmz9PHHHzu8G6erDRw4UM2bN9ekSZMcGnf77berffv29tC0pvDrB0B5+DsNAK/mg4FZVX9fpdMMgMvl5trfSZIMwyKLJU9S2CnnAPir++67TxkZGcrOzi61g6e3y8/PV7t27TRy5EhPlwIAAOD9fDAwcwShGQCXy8mxvcs75WiBpDDl55e+HoB/CQoK0rhx4zxdhlNCQ0M1fvx4T5cBAADg/fw8MJMIzQC4gS00M4xT28oKJYnQDECNufnmm8vd5RMAAADVUAsCM4nQDIAbFE/BPLXTzJqWFRTUdDUAaqubb77Z0yUAAAD4n1oSmElSgKcLAOB/bJ1mZvOJU45a0zI6zQAAAADAR9WiwEwiNAPgBrZOM7P5pP2YYRCaAQAAAIDPqmWBmURoBsANijcCOHVNM0IzAAAAAPBJtTAwkwjNALhB2WuaEZoBAAAAgM+ppYGZRGgGwA2KO81yTjlqDc3YCAAAAAAAfEQtDswkQjMAbkCnGU53dqsWiogIq7HX2a1aePoja+DAgT63e6Orat6xY4cSEhKUnZ1d/aKqYeDAgZo0aZJHa5CkX3/9VU2aNNHJkycrvxgAAMBb1PLATJKCPF0AAP9T1ppmhpEvi4XQrLbaf/CQctY/UWPPi+j0TI09a+/evUpKStKWLVt0wQUX2I+/9NJLslgsbn/+wIEDdfz4cX300Uduf9bKlSt1+eWX27+vX7++OnbsqGeeeUbt2rWzHx83bpwefPBBRUVFaeDAgVq4cGGF93Xm5zR37ly9++672rx5s7Kzs5WRkaHY2NgKx4wZM0aLFy/Wr7/+qqioKPvxG264QZmZmVq5cqUCAir/90Tb/+aBgYHat2+fGjdubD+XmpqqxMREmUwm7dmzR82bN9d5552niy++WC+++KLGjx/v8GcFAACocQRmkug0A+BihYVSUZHtOzYCQO0VExNTaYjjq3bs2KHU1FR99tlnysjI0DXXXKPMzExJ0oEDB/TJJ59o0KBBkqzhYWpqqv0lSfPnzy91zFE5OTm65pprNHbs2CqPeeqppxQZGalRo0bZj82bN0/fffed5s+fX6XA7FSNGjXSW2+9VeLYwoULS4RoNoMGDdLs2bNlMpkcegYAAECNIzCzIzQD4FK5uSW+O+V9oSRCM3gni8Wi6dOnq0WLFgoPD1e7du304Ycf2s9nZGTozjvvVIMGDRQeHq5WrVpp/vz5kqSkpCRJUvv27WUYhnr06CGp9FTHHj166OGHH9aIESN0xhlnKD4+XnPnztXJkyc1aNAgRUVF6cwzz9Tnn39uH2MymTR48GAlJSUpPDxcZ599tl566SX7+UmTJmnhwoX6+OOPZRiGDMPQypUrJUkHDx5Uv379dMYZZ6hevXq66aabtHfv3hL3HjVqlGJjY1WvXj2NGTOmyh1fcXFxSkhI0MUXX6wXXnhBaWlpWr9+vSRp8eLFateunZo0aSLJGh4mJCTYX5IUGxtb6pijRowYoSeeeEKdOnWq8pjQ0FAtXLhQCxcu1BdffKGUlBSNHDlS06dP15lnnulwDffcc4/9/wc2CxYs0D333FPq2l69euno0aNatWqVw88BAACoMQRmJRCaAXCpkqHZqWuaWdMyNgKANxo/frzmz5+v2bNn6/fff9fIkSN111132QOOJ598Utu2bdPnn3+u7du3a/bs2apfv74k6aeffpIkff3110pNTdXSpUvLfc7ChQtVv359/fTTT3r44Yf1wAMP6Pbbb1eXLl20efNm9erVS3fffbdy/pnjbDab1aRJEy1evFjbtm3ThAkTNHbsWC1evFiSNHr0aPXt21fXXHONvWurS5cuysnJ0eWXX67IyEitXr1aa9euVWRkpK655hoV/POL8IUXXtC8efP05ptvau3atTp27JiWLVvm8M8uPDxcklRYaA3GV69erY4dOzp8n6lTpyoyMrLC15o1axy+7+k6dOig5ORkDRkyRHfffbcuuugiPfDAA07d68Ybb1RGRobWrl0rSfaf4w033FDq2pCQELVr184lnwEAAMAtCMxKYU0zAC5lW8/MMPJOO8P0THinkydPasaMGfr222/VuXNnSVKLFi20du1avf766+revbtSUlLUvn17exjUvHlz+/gGDRpIkurVq1dp11S7du3sa1olJyfrmWeeUf369TV06FBJ0oQJEzR79mz98ssv6tSpk4KDgzV58mT7+KSkJK1bt06LFy9W3759FRkZqfDwcOXn55d49ttvv62AgAC98cYbMgxDknVKZGxsrFauXKmePXtq5syZSk5O1q233ipJmjNnjr788kuHfnZHjx7V5MmTFRUVpYsvvliSdb2vDh06OHQfSRo2bJj69u1b4TVlTXt0hi0k/fHHH/Xnn3/af0aOCg4O1l133aV58+bp0ksv1bx583TXXXcpODi4zOsbN25cotsPAADAaxCYlYnQDIBL2TrNAgLyZTYXHzcMQjN4p23btikvL09XX311ieMFBQVq3769JOmBBx7Qrbfeqs2bN6tnz566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e65Zs0a7d+/WVVddpUWLFumKK67QHXfcIUlKTExUTEyM2rVrJ0nq2rWrLrzwQr300kv68ccfNXny5FIdZqc+o6xnm0wmFRUVafLkyTrrrLN06NChMseX9+xXXnlFL7/8ss4++2z72Mcee0yFhYV6/vnnddlll1X4uQMCAjR06FBJUkJCgv3etrGVPdtsNsswDL3zzjs6efKkJOnRRx/VuHHj9Nprrym8nLVebD/zU8fHxMRIkmbMmKHbbrvNPr5Tp07q1KmTfezpnx3+iU4zH+XyrpI6zaTOC6Ubd0lnj7B26WT+Lm15TPo40dp99seLUuYfdKDVIhMmWL8GBCyTYeyt8ecbxi8yjB3KyZHmzDnlRFGOdOATafUt0kdNrFMxC45JUa2sU48v/6pWBWYAAABwj/r16yswMLBUV1l6enqpjqnTXXjhhQoMDNQll1yikSNHatKkSfaxoaGhFd4zKSlJ3bp1U2BgoK6//nr72LKeHRAQoIsuukh//PGHNm7cqIceekiJiYmSpHnz5unnn39WUFCQvv3223KfvX//flksFj300EMKCgqyj9+5c6d9bEXPPrXb6tSfWadOneznqvK5Tx3frFmzEvet6NkNGzZU48aNFRMTYx8fGRkpi8WiAwcOSJIiIiJKhWe2e5463qZ169Ylxp+urM8O/+MToZkj2/vWFiaTypwauv9g2f8iUGV1mkkdXpRuPiBd/LrUoKt1XajD30ibR0mftZY+biat7Sdtf0FKXy3lH3XNh4JX+f576bPPJKlIhjHdIzVY/xFqpqLDM/XNe18pc/3z0rc9pQ/rSqtvkg58JFlMUv0uUue3peu2S4k3s6EFAAAAXCIkJEQdOnTQihUrShxfsWKFunTpUuWxFotF+f+sfb1ixQolJSWVuudXX31V4p628Tt37rSPLevZFotFW7duVWJion799Vdt3bpVP//8s8477zy1adNGZ599trZu3apLLrmk3GevXr1a11xzjbZu3WofHxcXp9jYWPvYip596vpjp37uLVu22M85+rnXr19f4r4VPbtr1646dOiQTpw4YR+/fPlyBQQEqEmTJpKsIdfpbM8+dbzNn3/+WWL86cr67PA/Xj8907a976xZs9S1a1e9/vrr6t27t7Zt26amTZt6ujz/FRIrtbzP+sreZd1pM/ULKX2VlLNfStkvpSwuvj60nhR1thSRKIU3lMIbWV9hcVJwlBQUZf1qex/g9f/Xq5V++UUKCJDy86VBg6zHzjhjuY4f/0uSK7dStigoUIoMMyswzKy42CJFhxYp4Yw8xYTlq1HdIiWeka8W8SfVosFcnRn/T5vZ7lPuEJEoI/FW6cwhUmwbF9YGAAAAFBs1apTuvvtudezYUZ07d9bcuXOVkpKiYcOGSZKSk5N18OBBvfXWW5Kk1157TU2bNtU555yjO+64Q6NHj1ZwcLDuuecejRw5UikpKXrrrbfUt29fXX755YqOjlaXLl309ddfa8SIEfr00091zjnnSLJ2q82ZM0fXXXedtm/frrlz52rnzp1q3bq1du/eraefflqrV6/Wvn379Nprr6lt27b2useNG6f+/furUaNGCgwM1Pjx48t99jfffKO1a9eWGN+tWzctXbpUP/30kwIDAyt99syZM9W8eXO1adNGt99+ux5//HGZzWa99NJLlX7uhx56SB999JHatGmjgoICNWzYUD/99JOuueaaKn3uc889V0899ZQGDRqkyZMnq3fv3po8ebK6deumvXv3au7cuSosLNTevXv17LPPateuXdq4caN+/fVXrV27Vm3atCkx/siRI3rsscd077332rvTJk+erE6dOqlVq1bKysrSyy+/rK1bt+q1116rqf8rwgO8PrmYMWOGBg8ebF/4cObMmfryyy81e/bsMrf3zc/PL5HCZ2ZmSpKysrJcXpvFYlHWidI7ZVoscslx5+5lccNnbSA1HmJ9FZ2Ujm6Qjm2yvjK2SjkHpZyjUkbFu8eUEBDyzytIMgL/+Rp8yvfBkhEkGaf+a4BRztdT3pfZYXT6ufK6kMqYdlpqKmoVpqaWOX21KvdxclyVajztWDk15u+wdjFK0v/ussgwihQckqaC/BwZRoCsa5sFyGKxfpXFOvffthaAdT2C0t8HBlgUGiSFBVkUGiKFBUuBDjSDZeVIKccS9Mu+C7Xmz2765rcrFd34LH377T83ccOv7wvbn6+Dh1LLPFeQX+CFv/Zr7vcE2/0sTNUGAAC1QL9+/XT06FFNmTJFqampatu2rZYvX65mzZpJklJTU5WSkmK/3mw2Kzk5WXv27FFQUJAaNmyonJwczZ8/3z72sssu0/vvv6/BgwcrOztbf/75pxYtWqSDBw+WGHvmmWeqX79+Wr9+vS644AK1bdtWN910k5588kmlpaXJMAxFRERo9erVuvjii0vV/dZbb2nFihX2sRU929ZNZtO2bVutX7++xOeu6NkrV67U6NGjdfDgQYWHhyspKUnZ2dl67LHHKn32zp07S4xt06aNHnjgAX322Wd64403qvS5V6xYoYcfflgdO3ZUvXr1dMUVV2jnzp32z/7FF18oPT1d48eP159//qmwsLASn/v08X379tXTTz9t/3kcP35c9913n9LS0hQTE6P27duX+XOHfzEsXvy3noKCAkVEROiDDz7QLbfcYj/+6KOPauvWrVq1alWpMZMmTdLkyZNrskwAqJX2799fbrs6AAAAAPg6r+40c2Z73+TkZI0aNcr+vdls1rFjx1SvXr1KdzfxdllZWUpMTNT+/fsVHR3t6XJczp8/nz9/Nsm/P58/fzbJuc9nsViUnZ2tRo3YVRcAAACA//Lq0MzGke19Q0NDFRoaWuJYbGysu0rziOjoaL/8y7uNP38+f/5skn9/Pn/+bJLjn+/UnYUAAAAAwB959e6Z1dneFwAAAAAAAHCWV4dm1dneFwAAAAAAAHCW10/PrGx739okNDRUEydOLDX91F/48+fz588m+ffn8+fPJvn/5wMAAAAAZ3n17pk2s2bN0vTp0+3b3L744ou67LLLPF0WAAAAAAAA/JRPhGYAAAAAAABATfLqNc0AAAAAAAAATyA0AwAAAACgHCtXrpRhGDp+/LinS3GIYRj66KOPXHa/5s2ba+bMmdW+z5tvvqmePXtWv6Bqat68uVauXOnpMvTqq6/qxhtv9HQZKAehGQAAAAAAknr06KERI0Z4ugyHTJo0SRdccEGp46mpqerdu3eN1mEYhgzDUGBgoBITEzVkyBD9/fff9mvy8/M1YcIEPfnkk5KswZVtTFmvHj16OFXLo48+qg4dOig0NLTMn83pTCaTunTpoltvvbXE8czMTCUmJmr8+PFVfvaCBQtkGIZat25d6tzixYtlGIaaN29uPzZ06FBt2LBBa9eurfIzUHMIzQAAAAAA8DKFhYXVGp+QkFDjO6S3adNGqampSklJ0ezZs/Xpp59qwIAB9vNLlixRZGSkunXrJknasGGDUlNTlZqaqiVLlkiSduzYYT+2dOlSp+qwWCy699571a9fvypdHxgYqIULF+qLL77QO++8Yz/+8MMPq27dupowYYJDz69Tp47S09P1ww8/lDg+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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(15, 5))\n", + "# sns.kdeplot(p_t, color=\"blue\", ls='--', ax=axes[0], label='theoretical P(T=1|X)')\n", + "sns.histplot(p_x, color=\"blue\", kde=True, stat='density', ax=axes[0], label='estimated P(T=1|X)')\n", + "# sns.kdeplot(th_p_t_mx, color=\"orange\", ls='--', ax=axes[0], label='theoretical P(T=1|X, M)')\n", + "sns.histplot(p_xm, color=\"orange\", kde=True, bins=50, stat='density', ax=axes[0], label='estimated P(T=1|X, M)')\n", + "\n", + "axes[0].legend(bbox_to_anchor=[1, 0.9])\n", + "\n", + "ax = axes[1]\n", + "sns.scatterplot(x=th_p_t_mx[ind], y=p_xm, ax=ax)\n", + "ax.set_xticks(ax.get_yticks())\n", + "ax.set_aspect('equal', adjustable='box')\n", + "plt.plot([0, 1], [0, 1], 'red')\n", + "plt.ylabel('estimated P(T=1|X, M)')\n", + "plt.xlabel('theoretical P(T=1|X, M)')\n", + "plt.subplots_adjust(wspace=1.4)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "92f6704d", + "metadata": {}, + "outputs": [], + "source": [ + "interaction=False\n", + "forest=False\n", + "crossfit=0\n", + "calibration=True\n", + "regularization=True\n", + "calib_method='sigmoid'" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "21010053", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[2. ],\n", + " [0.6],\n", + " [0.8],\n", + " ...,\n", + " [2. ],\n", + " [2. ],\n", + " [0.8]])" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m_bucketized" + ] }, { "cell_type": "code", - "execution_count": 134, - "id": "03bed34d", + "execution_count": 31, + "id": "6072f13b", "metadata": {}, "outputs": [ { - "name": "stdout", + "name": "stderr", "output_type": "stream", "text": [ - "Linear coefficients\n", - "Direct effects\n", - "True theta1:[0.2], estimated theta1: 0.195\n", - "True theta0:[0.2], estimated theta0: 0.195\n", - "\\\n", - "Indirect effects\n", - "True delta1:[0.81], estimated delta1: 0.818\n", - "True delta0:[0.81], estimated delta0: 0.818\n", - "\\\n", - "Total effect\n", - "True tau:[1.01], estimated tau: 1.013\n" + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/model_selection/_split.py:737: UserWarning: The least populated class in y has only 4 members, which is less than n_splits=5.\n", + " warnings.warn(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/model_selection/_split.py:737: UserWarning: The least populated class in y has only 4 members, which is less than n_splits=5.\n", + " warnings.warn(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/model_selection/_split.py:737: UserWarning: The least populated class in y has only 4 members, which is less than n_splits=5.\n", + " warnings.warn(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/model_selection/_split.py:737: UserWarning: The least populated class in y has only 4 members, which is less than n_splits=5.\n", + " warnings.warn(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/model_selection/_split.py:737: UserWarning: The least populated class in y has only 4 members, which is less than n_splits=5.\n", + " warnings.warn(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n", + "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", + "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", + "\n", + "Increase the number of iterations (max_iter) or scale the data as shown in:\n", + " https://scikit-learn.org/stable/modules/preprocessing.html\n", + "Please also refer to the documentation for alternative solver options:\n", + " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", + " n_iter_i = _check_optimize_result(\n" ] } ], "source": [ - "effects_linear = ols_mediation(y, t, m, x)\n", + "if regularization:\n", + " alphas = ALPHAS\n", + " cs = ALPHAS\n", + "else:\n", + " alphas = [0.0]\n", + " cs = [np.inf]\n", + "m = inds_bucketized\n", + "n = len(y)\n", + "if len(x.shape) == 1:\n", + " x = x.reshape(-1, 1)\n", + "if len(m.shape) == 1:\n", + " mr = m.reshape(-1, 1)\n", + "else:\n", + " mr = np.copy(m)\n", + "if len(t.shape) == 1:\n", + " t = t.reshape(-1, 1)\n", + "\n", + "t0 = np.zeros((n, 1))\n", + "t1 = np.ones((n, 1))\n", + "m0 = np.zeros((n, 1))\n", + "m1 = np.ones((n, 1))\n", + "\n", + "if crossfit < 2:\n", + " train_test_list = [[np.arange(n), np.arange(n)]]\n", + "else:\n", + " kf = KFold(n_splits=crossfit)\n", + " train_test_list = list()\n", + " for train_index, test_index in kf.split(x):\n", + " train_test_list.append([train_index, test_index])\n", + "mu_1bx, mu_0bx, f_0bx, f_1bx = \\\n", + " [np.zeros(n) for h in range(4)]\n", + "\n", + "for train_index, test_index in train_test_list:\n", + " if not forest:\n", + " y_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS)\\\n", + " .fit(get_interactions(interaction, x, t, mr)[train_index, :], y[train_index])\n", + " pre_m_prob = LogisticRegressionCV(Cs=cs, cv=CV_FOLDS)\\\n", + " .fit(get_interactions(interaction, t, x)[train_index, :], m.ravel()[train_index])\n", + " else:\n", + " y_reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10)\\\n", + " .fit(get_interactions(interaction, x, t, mr)[train_index, :], y[train_index])\n", + " pre_m_prob = RandomForestClassifier(n_estimators=100, min_samples_leaf=10)\\\n", + " .fit(get_interactions(interaction, t, x)[train_index, :], m.ravel()[train_index])\n", + " if calibration:\n", + " m_prob = CalibratedClassifierCV(pre_m_prob, method=calib_method)\\\n", + " .fit(get_interactions(\n", + " interaction, t, x)[train_index, :], m.ravel()[train_index])\n", + " else:\n", + " m_prob = pre_m_prob\n", + "# mu_11x[test_index] = y_reg.predict(get_interactions(interaction, x, t1, m1)[test_index, :])\n", + "# mu_10x[test_index] = y_reg.predict(get_interactions(interaction, x, t1, m0)[test_index, :])\n", + "# mu_01x[test_index] = y_reg.predict(get_interactions(interaction, x, t0, m1)[test_index, :])\n", + "# mu_00x[test_index] = y_reg.predict(get_interactions(interaction, x, t0, m0)[test_index, :])\n", + "# f_00x[test_index] = m_prob.predict_proba(get_interactions(interaction, t0, x)[test_index, :])[:, 0]\n", + "# f_01x[test_index] = m_prob.predict_proba(get_interactions(interaction, t0, x)[test_index, :])[:, 1]\n", + "# f_10x[test_index] = m_prob.predict_proba(get_interactions(interaction, t1, x)[test_index, :])[:, 0]\n", + "# f_11x[test_index] = m_prob.predict_proba(get_interactions(interaction, t1, x)[test_index, :])[:, 1]\n", + "\n", + " buckets = [0., 0.2, 0.4, 0.6, 0.8, 1]\n", + "\n", + " direct_effect_treated = 0\n", + " direct_effect_control = 0\n", + " indirect_effect_treated = 0\n", + " indirect_effect_control = 0\n", + "\n", + " for i, b in enumerate(buckets):\n", + "\n", + " mb = m1 * b\n", + " mu_1bx = y_reg.predict(get_interactions(interaction, x, t1, mb)[test_index, :])\n", + " mu_0bx = y_reg.predict(get_interactions(interaction, x, t0, mb)[test_index, :])\n", + " f_1bx[test_index] = m_prob.predict_proba(get_interactions(interaction, t1, x)[test_index, :])[:, i]\n", + " f_0bx[test_index] = m_prob.predict_proba(get_interactions(interaction, t0, x)[test_index, :])[:, i]\n", + " direct_effect_ib = mu_1bx - mu_0bx\n", + " direct_effect_treated += direct_effect_ib * f_1bx\n", + " direct_effect_control += direct_effect_ib * f_0bx\n", + " indirect_effect_ib = f_1bx - f_0bx\n", + " indirect_effect_treated += indirect_effect_ib * mu_1bx\n", + " indirect_effect_control += indirect_effect_ib * mu_0bx\n", + "\n", + " direct_effect_treated = direct_effect_treated.sum() / n\n", + " direct_effect_control = direct_effect_control.sum() / n\n", + " indirect_effect_treated = indirect_effect_treated.sum() / n\n", + " indirect_effect_control = indirect_effect_control.sum() / n\n" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "e85e881c-e82a-42d2-b465-636566e21f9b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[1.01, 0.2, 0.2, array([0.81]), array([0.81]), 0]" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "causal_effects" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "84006a50-43a5-464e-90e9-f56fe2d68d6d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(0.06149657232696939,\n", + " 0.734283505124638,\n", + " -0.8715992158774716,\n", + " -0.19881228307980306)" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "direct_effect_treated, direct_effect_control, indirect_effect_treated, indirect_effect_control" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "ab3b83fe", + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (619621430.py, line 3)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m Cell \u001b[0;32mIn[20], line 3\u001b[0;36m\u001b[0m\n\u001b[0;31m direct effect_treated = 0\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + "buckets = [0., 0.2, 0.4, 0.6, 0.8, 1]\n", "\n", - "tau_hat, theta_1_hat, theta_0_hat, delta_1_hat, delta_0_hat, n_non_trimmed = effects_linear\n", - "print(\"Linear coefficients\")\n", - "print(\"Direct effects\")\n", - "print(\"True theta1:{}, estimated theta1: {}\".format(theta_1, round(theta_1_hat,3)))\n", - "print(\"True theta0:{}, estimated theta0: {}\".format(theta_0, round(theta_0_hat,3)))\n", - "print(\"\\\\\")\n", - "print(\"Indirect effects\")\n", - "print(\"True delta1:{}, estimated delta1: {}\".format(delta_1, round(delta_1_hat,3)))\n", - "print(\"True delta0:{}, estimated delta0: {}\".format(delta_0, round(delta_0_hat,3)))\n", - "print(\"\\\\\")\n", - "print(\"Total effect\")\n", - "print(\"True tau:{}, estimated tau: {}\".format(tau, round(tau_hat,3)))" + "direct effect_treated = 0\n", + "direct_effect_control = 0\n", + "indirect_effect_treated = 0\n", + "indirect_effect_control = 0\n", + "\n", + "for i, b in enumerate(buckets):\n", + " \n", + " mb = m1 * b\n", + " mu_1bx = y_reg.predict(get_interactions(interaction, x, t1, mb)[test_index, :])\n", + " mu_0bx = y_reg.predict(get_interactions(interaction, x, t0, mb)[test_index, :])\n", + " f_1bx[test_index] = m_prob.predict_proba(get_interactions(interaction, t1, x)[test_index, :])[:, i]\n", + " f_0bx[test_index] = m_prob.predict_proba(get_interactions(interaction, t0, x)[test_index, :])[:, i]\n", + " direct_effect_ib = mu_1bx - mu_0bx\n", + " direct_effect_treated += direct_effect_ib * f_1bx\n", + " direct_effect_control += direct_effect_ib * f_0bx\n", + " indirect_effect_ib = f_1bx - f_0bx\n", + " indirect_effect_treated += indirect_effect_ib * mu_1bx\n", + " indirect_effect_control += indirect_effect_ib * mu_0bx\n", + " \n", + "direct_effect_treated = direct_effect_treated.sum() / n\n", + "direct_effect_control = direct_effect_control.sum() / n\n", + "indirect_effect_treated = indirect_effect_treated.sum() / n\n", + "indirect_effect_control = indirect_effect_control.sum() / n" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "id": "eb1adce2", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 0, 1, 2, ..., 9997, 9998, 9999])" + ] + }, + "execution_count": 62, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "test_index" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3632820b", + "metadata": {}, + "outputs": [], + "source": [ + "direct_effect_i1 = mu_11x - mu_01x\n", + "direct_effect_i0 = mu_10x - mu_00x\n", + "direct_effect_treated = (direct_effect_i1 * f_11x + direct_effect_i0 * f_10x).sum() / n\n", + "direct_effect_control = (direct_effect_i1 * f_01x + direct_effect_i0 * f_00x).sum() / n\n", + "indirect_effect_i1 = f_11x - f_01x\n", + "indirect_effect_i0 = f_10x - f_00x\n", + "indirect_effect_treated = (indirect_effect_i1 * mu_11x + indirect_effect_i0 * mu_10x).sum() / n\n", + "indirect_effect_control = (indirect_effect_i1 * mu_01x + indirect_effect_i0 * mu_00x).sum() / n\n", + "total_effect = direct_effect_control + indirect_effect_treated" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "id": "681bfa5f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[0],\n", + " [1],\n", + " [1],\n", + " ...,\n", + " [0],\n", + " [0],\n", + " [0]])" + ] + }, + "execution_count": 63, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "21bcc8b3", + "metadata": {}, + "outputs": [], + "source": [ + "zmar = np.array([0.2, 6.4, 3.0, 1.6])\n", + "bins = np.array([-np.inf, 0.0, 1.0, 2.5, 4.0, 10.0])\n", + "inds = np.digitize(zmar, bins)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "9f065267", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([2, 5, 4, 3])" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "inds" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "07d3c72f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 1. , 10. , 4. , 2.5])" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bins[inds]" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "f1546dec", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([2, 5, 4, 3])" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "inds" + ] + }, + { + "cell_type": "code", + "execution_count": 92, + "id": "60fa05b5", + "metadata": {}, + "outputs": [], + "source": [ + "m_classes = np.arange(buckets.shape[0])" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "c2f431ab", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 1. , 10. , 4. , 2.5])" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bins[inds]" ] }, { "cell_type": "code", "execution_count": null, - "id": "7c0c2b68", + "id": "049fa7d3-c25f-456e-a4b3-762e1c78af5e", "metadata": {}, "outputs": [], "source": [] @@ -1199,7 +3523,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -1213,7 +3537,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.8" + "version": "3.9.18" } }, "nbformat": 4, From 435ed256f8f95b2099796a15d520b279551affaf Mon Sep 17 00:00:00 2001 From: houssamzenati Date: Wed, 6 Nov 2024 17:00:21 +0100 Subject: [PATCH 41/84] line formatting --- notebooks/noisymoons.pdf | Bin 161254 -> 0 bytes notebooks/toy_example.ipynb | 3545 ----------------------------------- 2 files changed, 3545 deletions(-) delete mode 100644 notebooks/noisymoons.pdf delete mode 100644 notebooks/toy_example.ipynb diff --git a/notebooks/noisymoons.pdf b/notebooks/noisymoons.pdf deleted file mode 100644 index 4d38723c1ae6e409fb862bc3554672333a34394d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 161254 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 Uq0h_>kT4MTK%ATkT8g0m0~{)C?*IS* diff --git a/notebooks/toy_example.ipynb b/notebooks/toy_example.ipynb deleted file mode 100644 index f6308f6..0000000 --- a/notebooks/toy_example.ipynb +++ /dev/null @@ -1,3545 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "85ea6472", - "metadata": {}, - "source": [ - "# Causal mediation analysis \n", - "\n", - "The objective of this notebook is to develop a basic understanding of causal mediation analysis on a toy example." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "1a98b2a7", - "metadata": {}, - "outputs": [], - "source": [ - "import sklearn\n", - "from sklearn import cluster, datasets\n", - "import matplotlib.pyplot as plt\n", - "from sklearn.preprocessing import StandardScaler\n", - "from itertools import cycle, islice\n", - "import numpy as np\n", - "from sklearn.linear_model import LinearRegression, LogisticRegression\n", - "from sklearn.linear_model import LogisticRegressionCV, RidgeCV, LassoCV\n", - "from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor\n", - "from sklearn.calibration import CalibratedClassifierCV\n", - "from scipy.special import expit\n", - "import pandas as pd" - ] - }, - { - "cell_type": "markdown", - "id": "7f8d439c", - "metadata": {}, - "source": [ - "## Dataset" - ] - }, - { - "cell_type": "code", - "execution_count": 252, - "id": "23644e4c", - "metadata": {}, - "outputs": [], - "source": [ - "rng = np.random.RandomState(170)\n", - "\n", - "def get_features_and_labels(dataset_name='blobs_overlap', n_samples=10000, overlap_coefficient=1):\n", - " ### Create dataset features\n", - "\n", - " if dataset_name == 'noisymoons':\n", - " X, l = datasets.make_moons(n_samples=n_samples, noise=0.05, random_state=170)\n", - "\n", - " elif dataset_name == 'blobs_no_overlap':\n", - " X, l = datasets.make_blobs(\n", - " n_samples=n_samples, centers=2, cluster_std=[2., 2.], random_state=170\n", - " )\n", - "\n", - " elif dataset_name == 'blobs_overlap':\n", - " X, l = datasets.make_blobs(\n", - " n_samples=n_samples, centers=[[0., 1.], [0.,0.]], cluster_std=[2.*overlap_coefficient, 2.*overlap_coefficient], random_state=170\n", - " )\n", - "\n", - " else:\n", - " raise NotImplementedError\n", - "\n", - " scaler = StandardScaler()\n", - " X = scaler.fit_transform(X)\n", - " \n", - " return X, l" - ] - }, - { - "cell_type": "code", - "execution_count": 253, - "id": "2d205352", - "metadata": {}, - "outputs": [], - "source": [ - "### Plot options\n", - "\n", - "number_classes = [2]\n", - "\n", - "colors = np.array(\n", - " list(\n", - " islice(\n", - " cycle(\n", - " [\n", - " \"#377eb8\",\n", - " \"#ff7f00\",\n", - " \"#4daf4a\",\n", - " \"#f781bf\",\n", - " \"#a65628\",\n", - " \"#984ea3\",\n", - " \"#999999\",\n", - " \"#e41a1c\",\n", - " \"#dede00\",\n", - " ]\n", - " ),\n", - " int(max(number_classes) + 1),\n", - " )\n", - " )\n", - ")\n", - "\n", - "markers = np.array(\n", - " list(\n", - " islice(\n", - " cycle(\n", - " [\n", - " \".\",\n", - " \"+\",\n", - " \"x\",\n", - " \"v\",\n", - " \"s\",\n", - " \"p\",\n", - " ]\n", - " ),\n", - " int(max(number_classes) + 1),\n", - " )\n", - " )\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 315, - "id": "e6a2752e", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAgMAAAGbCAYAAABZBpPkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOyddXwUd/rH37MWd0+IEYIEgju00JYW6kbd26tf5apX+dXuKneVa6/uLlDq1HB3SZAEIsTdfXXm98dkJ9nsbrKBYMe8X6/KTmZnZmdnv9/n+8jnESRJklBRUVFRUVE5YdEc7QtQUVFRUVFRObqoxoCKioqKisoJjmoMqKioqKionOCoxoCKioqKisoJjmoMqKioqKionOCoxoCKioqKisoJjmoMqKioqKionOCoxoCKioqKisoJjmoMqKioqKionOCoxoCKigc89dRTCIJAbW1tr/slJSVx/fXX9/v4q1atQhAEFi1adJBXePzzySefIAgChYWFR/tSVFROOFRjQEVFRUVF5QRHNQZUVFRUVFROcFRjQEVF5ajS1tZ2tC9BReWERzUGVFT6QW1tLZdeeimBgYGEhYVxzz33YDQae33PgQMHuOSSSwgNDcXX15epU6fy66+/utzXZrPx6KOPEh0djZ+fH+eddx4lJSUO++Tm5nLxxRcTHR2Nt7c3gwYN4vLLL6epqalfn2XFihWcdNJJ+Pn5ERwczPnnn092drby90WLFiEIAqtXr3Z677vvvosgCOzZs0fZtm/fPubPn09oaCje3t5MnDiRn3/+2eF99ryA1atXc8cddxAZGcmgQYPcXuNPP/3E2WefTWxsLF5eXqSkpPCPf/wDm83msN/s2bMZNWoU27dvZ/r06fj4+JCcnMw777zTr3uionKiojvaF6Cicjxx6aWXkpSUxPPPP8+mTZv473//S0NDA5999pnL/auqqpg+fTrt7e3cfffdhIWF8emnn3LeeeexaNEiLrzwQof9n332WQRB4OGHH6a6uppXX32VOXPmkJGRgY+PD2azmblz52IymbjrrruIjo6mrKyMxYsX09jYSFBQkEefY9myZZx55pkMHjyYp556io6ODl5//XVmzJjBjh07SEpK4uyzz8bf35+FCxcya9Ysh/cvWLCAkSNHMmrUKAD27t3LjBkziIuL4+9//zt+fn4sXLiQCy64gO+++87p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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "def visualise_data(dataset_name='blobs_overlap'):\n", - "\n", - " X, l = get_features_and_labels(dataset_name, overlap_coefficient=0.1)\n", - " ### Dataset visualisation\n", - "\n", - " reg = LogisticRegression().fit(X, l)\n", - " l_fitted = reg.predict(X)\n", - " l_fitted\n", - " markers = np.array(['.', '+'], dtype=str)\n", - " labels = ['nonsocial', 'social']\n", - "\n", - " # plt.scatter(X[:, 0], X[:, 1], s=10, color=colors[y_fitted], marker=markers[y])\n", - " for i, c in enumerate(np.unique(l)):\n", - " plt.scatter(X[:,0][l==c],X[:,1][l==c],color=colors[l][l==c], marker=markers[i], label=labels[i])\n", - "\n", - " plt.plot()\n", - " plt.xlim(-2.5, 2.5)\n", - " plt.ylim(-2.5, 2.5)\n", - " plt.xticks(())\n", - " plt.yticks(())\n", - " plt.title(dataset_name)\n", - " plt.legend()\n", - " plt.savefig('{}.pdf'.format(dataset_name))\n", - "\n", - "visualise_data()" - ] - }, - { - "cell_type": "code", - "execution_count": 258, - "id": "55d8284a", - "metadata": {}, - "outputs": [], - "source": [ - "def generate_causal_data(dataset_name, n_samples, mediator_binary, overlap_coefficient=1):\n", - " \n", - " X, l = get_features_and_labels(dataset_name, n_samples, overlap_coefficient=overlap_coefficient)\n", - " # Treatments and other quantities\n", - "\n", - " T = rng.choice([0,1], size=(n_samples,1))\n", - " np.mean(X, axis=0)\n", - " #mean_X = np.array([0.5, 0.25])\n", - " mean_X = np.array([0., 0.])\n", - " \n", - " # Coefficients\n", - " reg = LinearRegression().fit(X, l)\n", - " reg.score(X, l), reg.coef_, reg.intercept_\n", - " beta_0 = reg.intercept_\n", - " beta_X = reg.coef_\n", - "\n", - " beta_T = np.array([1])\n", - " beta_TX = np.array([0,0])\n", - " omega_T = 0.9\n", - "\n", - " gamma_0 = 0\n", - " gamma_X = np.array([0,0]) \n", - " gamma_T = np.array([0.2])\n", - " gamma_M = np.array([1])\n", - " gamma_MT = np.array([0])\n", - " omega_M = 0.9\n", - " \n", - " ### Mediator generation\n", - "\n", - " if mediator_binary:\n", - " p = expit(beta_0 + X.dot(beta_X) + omega_T*T.dot(beta_T) + (T*X).dot(beta_TX) )\n", - " M_ = rng.binomial(1, p)\n", - " M = np.expand_dims(M_, axis=-1) \n", - "\n", - " else:\n", - " M_ = beta_0 + X.dot(beta_X) + omega_T*T.dot(beta_T) + (T*X).dot(beta_TX) + rng.normal(0, 0.1, size=T.shape[0])\n", - " M = np.expand_dims(M_, axis=-1)\n", - "\n", - " Y = gamma_0 + X.dot(gamma_X) + T.dot(gamma_T) + omega_M*M.dot(gamma_M) + (T*M).dot(gamma_MT) + rng.normal(0, 0.1, size=T.shape[0])\n", - " \n", - " causal_data = X, T, M, Y\n", - " \n", - " ### Causal quantities\n", - " \n", - " if mediator_binary:\n", - " mean_M_t1 = np.mean(expit(beta_0 + X.dot(beta_X) + X.dot(beta_TX) + omega_T *beta_T), axis=0)\n", - " mean_M_t0 = np.mean(expit(beta_0 + X.dot(beta_X)), axis=0)\n", - " theta_1 = gamma_T + gamma_MT.T.dot(mean_M_t1) # to do mean(m1) pour avoir un vecteur de taille dim_m\n", - " theta_0 = gamma_T + gamma_MT.T.dot(mean_M_t0)\n", - " product_mean_term = expit(beta_0 + X.dot(beta_X) + X.dot(beta_TX) + omega_T *beta_T) - expit(beta_0 + X.dot(beta_X))\n", - "\n", - " delta_1 = np.mean(product_mean_term*(omega_M * gamma_M+gamma_MT), axis=0)\n", - " delta_0 = np.mean(product_mean_term*(omega_M * gamma_M), axis=0)\n", - " tau = delta_0 + theta_1\n", - "\n", - " else:\n", - " mean_M_t1 = beta_0 + mean_X.dot(beta_X) + mean_X.dot(beta_TX) + omega_T *beta_T\n", - " mean_M_t0 = beta_0 + mean_X.dot(beta_X)\n", - "\n", - " theta_1 = gamma_T + gamma_MT.T.dot(mean_M_t1) # to do mean(m1) pour avoir un vecteur de taille dim_m\n", - " theta_0 = gamma_T + gamma_MT.T.dot(mean_M_t0)\n", - " #delta_1 = (gamma_T * t1 + m1.dot(gamma_m) + m1.dot(gamma_t_m) * t1 - gamma_t * t1 + m0.dot(gamma_m) + m0.dot(gamma_t_m) * t1).mean()\n", - " #delta_0 = (gamma_T * t0 + m1.dot(gamma_m) + m1.dot(gamma_t_m) * t0 - gamma_t * t0 + m0.dot(gamma_m) + m0.dot(gamma_t_m) * t0).mean()\n", - " delta_1 = (mean_X.dot(beta_TX) + omega_T * beta_T) * (omega_M * gamma_M + gamma_MT)\n", - " delta_0 = (mean_X.dot(beta_TX) + omega_T * beta_T) * (omega_M * gamma_M)\n", - "\n", - " tau = gamma_T + omega_M * gamma_M * omega_T * beta_T\n", - " \n", - " causal_effects = [tau[0], theta_1[0], theta_0[0], delta_1, delta_0, 0]\n", - " \n", - " return causal_data, causal_effects" - ] - }, - { - "cell_type": "code", - "execution_count": 259, - "id": "a24af6c3", - "metadata": {}, - "outputs": [], - "source": [ - "#((T*X).dot(beta_TX)).shape\n", - "#linear_X = beta_0 + X.dot(beta_X)\n", - "#linear_T = omega_T*T.dot(beta_T)\n", - "#linear_TX = (T*X).dot(beta_TX)\n", - "#noise = rng.normal(0, 0.1, size=T.shape[0])\n", - "dataset_name='blobs_overlap'\n", - "n_samples=10000\n", - "mediator_binary=False" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "08c288e2", - "metadata": {}, - "outputs": [], - "source": [ - "causal_data, causal_effects = generate_causal_data(dataset_name, n_samples, mediator_binary)" - ] - }, - { - "cell_type": "markdown", - "id": "82292fa9", - "metadata": {}, - "source": [ - "## Causal effect estimation" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "fa63c8d4", - "metadata": {}, - "outputs": [], - "source": [ - "CV_FOLDS = 5\n", - "ALPHAS = np.logspace(-5, 5, 8)" - ] - }, - { - "cell_type": "markdown", - "id": "610ccc7b", - "metadata": {}, - "source": [ - "### Importance weighting" - ] - }, - { - "cell_type": "code", - "execution_count": 163, - "id": "cfdb2b86", - "metadata": {}, - "outputs": [], - "source": [ - "def get_classifier(regularization=False, forest=False, calibration=True, calib_method='sigmoid'):\n", - " if regularization:\n", - " cs = ALPHAS\n", - " else:\n", - " cs = [np.inf]\n", - " \n", - " if not forest:\n", - " x_clf = LogisticRegressionCV(Cs=cs, cv=CV_FOLDS)\n", - " xm_clf = LogisticRegressionCV(Cs=cs, cv=CV_FOLDS)\n", - " else:\n", - " x_clf = RandomForestClassifier(n_estimators=100,\n", - " min_samples_leaf=10)\n", - " xm_clf = RandomForestClassifier(n_estimators=100, min_samples_leaf=10)\n", - " if calibration:\n", - " x_clf = CalibratedClassifierCV(x_clf,\n", - " method=calib_method)\n", - " xm_clf = CalibratedClassifierCV(xm_clf, method=calib_method)\n", - " \n", - " return x_clf, xm_clf\n", - " \n", - "def get_train_test_lists(crossfit, n): \n", - " if crossfit < 2:\n", - " train_test_list = [[np.arange(n), np.arange(n)]]\n", - " else:\n", - " kf = KFold(n_splits=crossfit)\n", - " train_test_list = list()\n", - " for train_index, test_index in kf.split(x):\n", - " train_test_list.append([train_index, test_index])\n", - " return train_test_list\n", - "\n", - "def estimate_probabilities(t, m, x, crossfit, classifier_x, classifier_xm):\n", - " \n", - " n = len(t)\n", - " train_test_list = [[np.arange(n), np.arange(n)]]\n", - " \n", - " p_x, p_xm = [np.zeros(n) for h in range(2)]\n", - " # compute propensity scores\n", - " if len(x.shape) == 1:\n", - " x = x.reshape(-1, 1)\n", - " if len(m.shape) == 1:\n", - " m = m.reshape(-1, 1)\n", - " \n", - " train_test_list = get_train_test_lists(crossfit, n)\n", - " \n", - " for train_index, test_index in train_test_list:\n", - " x_clf = classifier_x.fit(x[train_index, :], t[train_index])\n", - " xm_clf = classifier_xm.fit(np.hstack((x, m))[train_index, :], t[train_index])\n", - " p_x[test_index] = x_clf.predict_proba(x[test_index, :])[:, 1]\n", - " p_xm[test_index] = xm_clf.predict_proba(\n", - " np.hstack((x, m))[test_index, :])[:, 1]\n", - " \n", - " return p_x, p_xm\n", - "\n", - "def SNIPW(y, t, m, x, trim, p_x, p_xm, clip):\n", - " \"\"\"\n", - " IPW estimator presented in\n", - " HUBER, Martin. Identifying causal mechanisms (primarily) based on inverse\n", - " probability weighting. Journal of Applied Econometrics, 2014,\n", - " vol. 29, no 6, p. 920-943.\n", - "\n", - " results has 6 values\n", - " - total effect\n", - " - direct effect treated (\\theta(1))\n", - " - direct effect non treated (\\theta(0))\n", - " - indirect effect treated (\\delta(1))\n", - " - indirect effect untreated (\\delta(0))\n", - " - number of used observations (non trimmed)\n", - "\n", - " y array-like, shape (n_samples)\n", - " outcome value for each unit, continuous\n", - "\n", - " t array-like, shape (n_samples)\n", - " treatment value for each unit, binary\n", - "\n", - " m array-like, shape (n_samples, n_features_mediator)\n", - " mediator value for each unit, can be continuous or binary, and\n", - " multi-dimensional\n", - "\n", - " x array-like, shape (n_samples, n_features_covariates)\n", - " covariates (potential confounders) values\n", - "\n", - "\n", - " trim float\n", - " Trimming rule for discarding observations with extreme propensity\n", - " scores. In the absence of post-treatment confounders (w=NULL),\n", - " observations with Pr(D=1|M,X)(1-trim) are\n", - " dropped. In the presence of post-treatment confounders\n", - " (w is defined), observations with Pr(D=1|M,W,X)(1-trim) are dropped.\n", - "\n", - " logit boolean\n", - " whether logit or pobit regression is used for propensity score\n", - " legacy from the R package, here only logit is implemented\n", - "\n", - " regularization boolean, default True\n", - " whether to use regularized models (logistic or\n", - " linear regression). If True, cross-validation is used\n", - " to chose among 8 potential log-spaced values between\n", - " 1e-5 and 1e5\n", - "\n", - " forest boolean, default False\n", - " whether to use a random forest model to estimate the propensity\n", - " scores instead of logistic regression\n", - "\n", - " crossfit integer, default 0\n", - " number of folds for cross-fitting\n", - "\n", - " clip float\n", - " limit to clip for numerical stability (min=clip, max=1-clip)\n", - " \"\"\"\n", - " \n", - " t = t.squeeze()\n", - " \n", - " # trimming. Following causal weight code, not sure I understand\n", - " # why we trim only on p_xm and not on p_x\n", - " ind = ((p_xm > trim) & (p_xm < (1 - trim)))\n", - " y, t, p_x, p_xm = y[ind], t[ind], p_x[ind], p_xm[ind]\n", - "\n", - " # note on the names, ytmt' = Y(t, M(t')), the treatment needs to be\n", - " # binary but not the mediator\n", - " p_x = np.clip(p_x, clip, 1 - clip)\n", - " p_xm = np.clip(p_xm, clip, 1 - clip)\n", - "\n", - " y1m1 = np.sum(y * t / p_x) / np.sum(t / p_x)\n", - " y1m0 = np.sum(y * t * (1 - p_xm) / (p_xm * (1 - p_x))) /\\\n", - " np.sum(t * (1 - p_xm) / (p_xm * (1 - p_x)))\n", - " y0m0 = np.sum(y * (1 - t) / (1 - p_x)) /\\\n", - " np.sum((1 - t) / (1 - p_x))\n", - " y0m1 = np.sum(y * (1 - t) * p_xm / ((1 - p_xm) * p_x)) /\\\n", - " np.sum((1 - t) * p_xm / ((1 - p_xm) * p_x))\n", - "\n", - " return(y1m1 - y0m0,\n", - " y1m1 - y0m1,\n", - " y1m0 - y0m0,\n", - " y1m1 - y1m0,\n", - " y0m1 - y0m0,\n", - " np.sum(ind))\n", - "\n", - "def IPW(y, t, m, x, trim, p_x, p_xm, clip):\n", - " \"\"\"\n", - " IPW estimator presented in\n", - " HUBER, Martin. Identifying causal mechanisms (primarily) based on inverse\n", - " probability weighting. Journal of Applied Econometrics, 2014,\n", - " vol. 29, no 6, p. 920-943.\n", - "\n", - " results has 6 values\n", - " - total effect\n", - " - direct effect treated (\\theta(1))\n", - " - direct effect non treated (\\theta(0))\n", - " - indirect effect treated (\\delta(1))\n", - " - indirect effect untreated (\\delta(0))\n", - " - number of used observations (non trimmed)\n", - "\n", - " y array-like, shape (n_samples)\n", - " outcome value for each unit, continuous\n", - "\n", - " t array-like, shape (n_samples)\n", - " treatment value for each unit, binary\n", - "\n", - " m array-like, shape (n_samples, n_features_mediator)\n", - " mediator value for each unit, can be continuous or binary, and\n", - " multi-dimensional\n", - "\n", - " x array-like, shape (n_samples, n_features_covariates)\n", - " covariates (potential confounders) values\n", - "\n", - "\n", - " trim float\n", - " Trimming rule for discarding observations with extreme propensity\n", - " scores. In the absence of post-treatment confounders (w=NULL),\n", - " observations with Pr(D=1|M,X)(1-trim) are\n", - " dropped. In the presence of post-treatment confounders\n", - " (w is defined), observations with Pr(D=1|M,W,X)(1-trim) are dropped.\n", - "\n", - " logit boolean\n", - " whether logit or pobit regression is used for propensity score\n", - " legacy from the R package, here only logit is implemented\n", - "\n", - " regularization boolean, default True\n", - " whether to use regularized models (logistic or\n", - " linear regression). If True, cross-validation is used\n", - " to chose among 8 potential log-spaced values between\n", - " 1e-5 and 1e5\n", - "\n", - " forest boolean, default False\n", - " whether to use a random forest model to estimate the propensity\n", - " scores instead of logistic regression\n", - "\n", - " crossfit integer, default 0\n", - " number of folds for cross-fitting\n", - "\n", - " clip float\n", - " limit to clip for numerical stability (min=clip, max=1-clip)\n", - " \"\"\"\n", - " \n", - " t = t.squeeze()\n", - " \n", - " # trimming. Following causal weight code, not sure I understand\n", - " # why we trim only on p_xm and not on p_x\n", - " # trimming. Following causal weight code, not sure I understand\n", - " # why we trim only on p_xm and not on p_x\n", - " ind = ((p_xm > trim) & (p_xm < (1 - trim)))\n", - " y, t, p_x, p_xm = y[ind], t[ind], p_x[ind], p_xm[ind]\n", - "\n", - " # note on the names, ytmt' = Y(t, M(t')), the treatment needs to be\n", - " # binary but not the mediator\n", - " p_x = np.clip(p_x, clip, 1 - clip)\n", - " p_xm = np.clip(p_xm, clip, 1 - clip)\n", - "\n", - " y1m1 = np.mean(y * t / p_x)\n", - " y1m0 = np.mean(y * t * (1 - p_xm) / (p_xm * (1 - p_x))) \n", - " y0m0 = np.mean(y * (1 - t) / (1 - p_x))\n", - " y0m1 = np.mean(y * (1 - t) * p_xm / ((1 - p_xm) * p_x)) \n", - "\n", - " return(y1m1 - y0m0,\n", - " y1m1 - y0m1,\n", - " y1m0 - y0m0,\n", - " y1m1 - y1m0,\n", - " y0m1 - y0m0,\n", - " np.sum(ind))\n" - ] - }, - { - "cell_type": "code", - "execution_count": 164, - "id": "cf795077", - "metadata": {}, - "outputs": [], - "source": [ - "# y = Y\n", - "# t = T\n", - "# m = M\n", - "# x = X\n", - "# trim=0\n", - "# logit=True\n", - "# regularization=False\n", - "# forest=False\n", - "# crossfit=0\n", - "# clip=0.0\n", - "# calibration=False\n", - "# classifier_x, classifier_xm = get_classifier(regularization, forest, calibration)" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "60063b02", - "metadata": {}, - "outputs": [], - "source": [ - "# p_x, p_xm = estimate_probabilities(t, m, x, crossfit, classifier_x, classifier_xm)\n", - "# effects_IPW = IPW(y, t, m, x, trim, p_x, p_xm)\n", - "# effects_SNIPW = SNIPW(y, t, m, x, trim, p_x, p_xm)" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "d6e0cf37", - "metadata": {}, - "outputs": [], - "source": [ - "# tau_hat, theta_1_hat, theta_0_hat, delta_1_hat, delta_0_hat, n_non_trimmed = effects_IPW" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "69e45369", - "metadata": {}, - "outputs": [], - "source": [ - "# print(\"IPW\")\n", - "# print(\"Direct effects\")\n", - "# print(\"True theta1:{}, estimated theta1: {}\".format(theta_1, round(theta_1_hat,3)))\n", - "# print(\"True theta0:{}, estimated theta0: {}\".format(theta_0, round(theta_0_hat,3)))\n", - "# print(\"\\\\\")\n", - "# print(\"Indirect effects\")\n", - "# print(\"True delta1:{}, estimated delta1: {}\".format(delta_1, round(delta_1_hat,3)))\n", - "# print(\"True delta0:{}, estimated delta0: {}\".format(delta_0, round(delta_0_hat,3)))\n", - "# print(\"\\\\\")\n", - "# print(\"Total effect\")\n", - "# print(\"True tau:{}, estimated tau: {}\".format(tau, round(tau_hat,3)))" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "c5ad6863", - "metadata": {}, - "outputs": [], - "source": [ - "# tau_hat, theta_1_hat, theta_0_hat, delta_1_hat, delta_0_hat, n_non_trimmed = effects_SNIPW\n", - "# print(\"SNIPW\")\n", - "# print(\"Direct effects\")\n", - "# print(\"True theta1:{}, estimated theta1: {}\".format(theta_1, round(theta_1_hat,3)))\n", - "# print(\"True theta0:{}, estimated theta0: {}\".format(theta_0, round(theta_0_hat,3)))\n", - "# print(\"\\\\\")\n", - "# print(\"Indirect effects\")\n", - "# print(\"True delta1:{}, estimated delta1: {}\".format(delta_1, round(delta_1_hat,3)))\n", - "# print(\"True delta0:{}, estimated delta0: {}\".format(delta_0, round(delta_0_hat,3)))\n", - "# print(\"\\\\\")\n", - "# print(\"Total effect\")\n", - "# print(\"True tau:{}, estimated tau: {}\".format(tau, round(tau_hat,3)))" - ] - }, - { - "cell_type": "markdown", - "id": "7370ccd3", - "metadata": {}, - "source": [ - "### Ordinary least squares" - ] - }, - { - "cell_type": "code", - "execution_count": 165, - "id": "32dbc702", - "metadata": {}, - "outputs": [], - "source": [ - "def ols_mediation(y, t, m, x, interaction=False, regularization=True):\n", - " \"\"\"\n", - " found an R implementation https://cran.r-project.org/package=regmedint\n", - "\n", - " implements very simple model of mediation\n", - " Y ~ X + T + M\n", - " M ~ X + T\n", - " estimation method is product of coefficients\n", - "\n", - " y array-like, shape (n_samples)\n", - " outcome value for each unit, continuous\n", - "\n", - " t array-like, shape (n_samples)\n", - " treatment value for each unit, binary\n", - "\n", - " m array-like, shape (n_samples)\n", - " mediator value for each unit, can be continuous or binary, and\n", - " is necessary in 1D\n", - "\n", - " x array-like, shape (n_samples, n_features_covariates)\n", - " covariates (potential confounders) values\n", - "\n", - " interaction boolean, default=False\n", - " whether to include interaction terms in the model\n", - " not implemented here, just for compatibility of signature\n", - " function\n", - "\n", - " regularization boolean, default True\n", - " whether to use regularized models (logistic or\n", - " linear regression). If True, cross-validation is used\n", - " to chose among 8 potential log-spaced values between\n", - " 1e-5 and 1e5\n", - "\n", - " \"\"\"\n", - " if regularization:\n", - " alphas = ALPHAS\n", - " else:\n", - " alphas = [0.0]\n", - " if len(x.shape) == 1:\n", - " x = x.reshape(-1, 1)\n", - " if len(m.shape) == 1:\n", - " m = m.reshape(-1, 1)\n", - " if len(t.shape) == 1:\n", - " t = t.reshape(-1, 1)\n", - " coef_t_m = np.zeros(m.shape[1])\n", - " for i in range(m.shape[1]):\n", - " m_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS)\\\n", - " .fit(np.hstack((x, t)), m[:, i])\n", - " coef_t_m[i] = m_reg.coef_[-1]\n", - " y_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS)\\\n", - " .fit(np.hstack((x, t, m)), y.ravel())\n", - "\n", - " # return total, direct and indirect effect\n", - " direct_effect = y_reg.coef_[x.shape[1]]\n", - " indirect_effect = sum(y_reg.coef_[x.shape[1] + 1:] * coef_t_m)\n", - " return [direct_effect + indirect_effect,\n", - " direct_effect,\n", - " direct_effect,\n", - " indirect_effect,\n", - " indirect_effect,\n", - " None]\n" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "0db06a94", - "metadata": {}, - "outputs": [], - "source": [ - "# effects_linear = ols_mediation(y, t, m, x)\n", - "\n", - "# tau_hat, theta_1_hat, theta_0_hat, delta_1_hat, delta_0_hat, n_non_trimmed = effects_linear\n", - "# print(\"Linear coefficients\")\n", - "# print(\"Direct effects\")\n", - "# print(\"True theta1:{}, estimated theta1: {}\".format(theta_1, round(theta_1_hat,3)))\n", - "# print(\"True theta0:{}, estimated theta0: {}\".format(theta_0, round(theta_0_hat,3)))\n", - "# print(\"\\\\\")\n", - "# print(\"Indirect effects\")\n", - "# print(\"True delta1:{}, estimated delta1: {}\".format(delta_1, round(delta_1_hat,3)))\n", - "# print(\"True delta0:{}, estimated delta0: {}\".format(delta_0, round(delta_0_hat,3)))\n", - "# print(\"\\\\\")\n", - "# print(\"Total effect\")\n", - "# print(\"True tau:{}, estimated tau: {}\".format(tau, round(tau_hat,3)))" - ] - }, - { - "cell_type": "markdown", - "id": "c13945ae", - "metadata": {}, - "source": [ - "### G computation" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "0ffc9cc2", - "metadata": {}, - "outputs": [], - "source": [ - "def get_interactions(interaction, *args):\n", - " \"\"\"\n", - " this function provides interaction terms between different groups of\n", - " variables (confounders, treatment, mediators)\n", - " Inputs\n", - " --------\n", - " interaction boolean\n", - " whether to compute interaction terms\n", - "\n", - " *args flexible, one or several arrays\n", - " blocks of variables between which interactions should be\n", - " computed\n", - " Returns\n", - " --------\n", - " Examples\n", - " --------\n", - " >>> x = np.arange(6).reshape(3, 2)\n", - " >>> t = np.ones((3, 1))\n", - " >>> m = 2 * np.ones((3, 1))\n", - " >>> get_interactions(False, x, t, m)\n", - " array([[0., 1., 1., 2.],\n", - " [2., 3., 1., 2.],\n", - " [4., 5., 1., 2.]])\n", - " >>> get_interactions(True, x, t, m)\n", - " array([[ 0., 1., 1., 2., 0., 1., 0., 2., 2.],\n", - " [ 2., 3., 1., 2., 2., 3., 4., 6., 2.],\n", - " [ 4., 5., 1., 2., 4., 5., 8., 10., 2.]])\n", - " \"\"\"\n", - " variables = list(args)\n", - " for index, var in enumerate(variables):\n", - " if len(var.shape) == 1:\n", - " variables[index] = var.reshape(-1,1)\n", - " pre_inter_variables = np.hstack(variables)\n", - " if not interaction:\n", - " return pre_inter_variables\n", - " new_cols = list()\n", - " for i, var in enumerate(variables[:]):\n", - " for j, var2 in enumerate(variables[i+1:]):\n", - " for ii in range(var.shape[1]):\n", - " for jj in range(var2.shape[1]):\n", - " new_cols.append((var[:, ii] * var2[:, jj]).reshape(-1, 1))\n", - " new_vars = np.hstack(new_cols)\n", - " result = np.hstack((pre_inter_variables, new_vars))\n", - " return result\n", - "\n", - "def g_computation(y, t, m, x, interaction=False, forest=False,\n", - " crossfit=0, calibration=True, regularization=True,\n", - " calib_method='sigmoid'):\n", - " \"\"\"\n", - " m is binary !!!\n", - "\n", - " implementation of the g formula for mediation\n", - "\n", - " y array-like, shape (n_samples)\n", - " outcome value for each unit, continuous\n", - "\n", - " t array-like, shape (n_samples)\n", - " treatment value for each unit, binary\n", - "\n", - " m array-like, shape (n_samples)\n", - " mediator value for each unit, here m is necessary binary and uni-\n", - " dimensional\n", - "\n", - " x array-like, shape (n_samples, n_features_covariates)\n", - " covariates (potential confounders) values\n", - "\n", - " interaction boolean, default=False\n", - " whether to include interaction terms in the model\n", - " interactions are terms XT, TM, MX\n", - "\n", - " forest boolean, default False\n", - " whether to use a random forest model to estimate the propensity\n", - " scores instead of logistic regression, and outcome model instead\n", - " of linear regression\n", - "\n", - " crossfit integer, default 0\n", - " number of folds for cross-fitting\n", - "\n", - " regularization boolean, default True\n", - " whether to use regularized models (logistic or\n", - " linear regression). If True, cross-validation is used\n", - " to chose among 8 potential log-spaced values between\n", - " 1e-5 and 1e5\n", - " \"\"\"\n", - " if regularization:\n", - " alphas = ALPHAS\n", - " cs = ALPHAS\n", - " else:\n", - " alphas = [0.0]\n", - " cs = [np.inf]\n", - " n = len(y)\n", - " if len(x.shape) == 1:\n", - " x = x.reshape(-1, 1)\n", - " if len(m.shape) == 1:\n", - " mr = m.reshape(-1, 1)\n", - " else:\n", - " mr = np.copy(m)\n", - " if len(t.shape) == 1:\n", - " t = t.reshape(-1, 1)\n", - " t0 = np.zeros((n, 1))\n", - " t1 = np.ones((n, 1))\n", - " m0 = np.zeros((n, 1))\n", - " m1 = np.ones((n, 1))\n", - "\n", - " if crossfit < 2:\n", - " train_test_list = [[np.arange(n), np.arange(n)]]\n", - " else:\n", - " kf = KFold(n_splits=crossfit)\n", - " train_test_list = list()\n", - " for train_index, test_index in kf.split(x):\n", - " train_test_list.append([train_index, test_index])\n", - " mu_11x, mu_10x, mu_01x, mu_00x, f_00x, f_01x, f_10x, f_11x = \\\n", - " [np.zeros(n) for h in range(8)]\n", - "\n", - " for train_index, test_index in train_test_list:\n", - " if not forest:\n", - " y_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS)\\\n", - " .fit(get_interactions(interaction, x, t, mr)[train_index, :], y[train_index])\n", - " pre_m_prob = LogisticRegressionCV(Cs=cs, cv=CV_FOLDS)\\\n", - " .fit(get_interactions(interaction, t, x)[train_index, :], m.ravel()[train_index])\n", - " else:\n", - " y_reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10)\\\n", - " .fit(get_interactions(interaction, x, t, mr)[train_index, :], y[train_index])\n", - " pre_m_prob = RandomForestClassifier(n_estimators=100, min_samples_leaf=10)\\\n", - " .fit(get_interactions(interaction, t, x)[train_index, :], m.ravel()[train_index])\n", - " if calibration:\n", - " m_prob = CalibratedClassifierCV(pre_m_prob, method=calib_method)\\\n", - " .fit(get_interactions(\n", - " interaction, t, x)[train_index, :], m.ravel()[train_index])\n", - " else:\n", - " m_prob = pre_m_prob\n", - " mu_11x[test_index] = y_reg.predict(get_interactions(interaction, x, t1, m1)[test_index, :])\n", - " mu_10x[test_index] = y_reg.predict(get_interactions(interaction, x, t1, m0)[test_index, :])\n", - " mu_01x[test_index] = y_reg.predict(get_interactions(interaction, x, t0, m1)[test_index, :])\n", - " mu_00x[test_index] = y_reg.predict(get_interactions(interaction, x, t0, m0)[test_index, :])\n", - " f_00x[test_index] = m_prob.predict_proba(get_interactions(interaction, t0, x)[test_index, :])[:, 0]\n", - " f_01x[test_index] = m_prob.predict_proba(get_interactions(interaction, t0, x)[test_index, :])[:, 1]\n", - " f_10x[test_index] = m_prob.predict_proba(get_interactions(interaction, t1, x)[test_index, :])[:, 0]\n", - " f_11x[test_index] = m_prob.predict_proba(get_interactions(interaction, t1, x)[test_index, :])[:, 1]\n", - "\n", - " direct_effect_i1 = mu_11x - mu_01x\n", - " direct_effect_i0 = mu_10x - mu_00x\n", - " direct_effect_treated = (direct_effect_i1 * f_11x + direct_effect_i0 * f_10x).sum() / n\n", - " direct_effect_control = (direct_effect_i1 * f_01x + direct_effect_i0 * f_00x).sum() / n\n", - " indirect_effect_i1 = f_11x - f_01x\n", - " indirect_effect_i0 = f_10x - f_00x\n", - " indirect_effect_treated = (indirect_effect_i1 * mu_11x + indirect_effect_i0 * mu_10x).sum() / n\n", - " indirect_effect_control = (indirect_effect_i1 * mu_01x + indirect_effect_i0 * mu_00x).sum() / n\n", - " total_effect = direct_effect_control + indirect_effect_treated\n", - "\n", - " return [total_effect,\n", - " direct_effect_treated,\n", - " direct_effect_control,\n", - " indirect_effect_treated,\n", - " indirect_effect_control,\n", - " None]" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "1d3605ff", - "metadata": {}, - "outputs": [], - "source": [ - "# effects_g_computation = g_computation(y, t, m, x)\n", - "\n", - "# tau_hat, theta_1_hat, theta_0_hat, delta_1_hat, delta_0_hat, n_non_trimmed = effects_linear\n", - "# print(\"Linear coefficients\")\n", - "# print(\"Direct effects\")\n", - "# print(\"True theta1:{}, estimated theta1: {}\".format(theta_1, round(theta_1_hat,3)))\n", - "# print(\"True theta0:{}, estimated theta0: {}\".format(theta_0, round(theta_0_hat,3)))\n", - "# print(\"\\\\\")\n", - "# print(\"Indirect effects\")\n", - "# print(\"True delta1:{}, estimated delta1: {}\".format(delta_1, round(delta_1_hat,3)))\n", - "# print(\"True delta0:{}, estimated delta0: {}\".format(delta_0, round(delta_0_hat,3)))\n", - "# print(\"\\\\\")\n", - "# print(\"Total effect\")\n", - "# print(\"True tau:{}, estimated tau: {}\".format(tau, round(tau_hat,3)))" - ] - }, - { - "cell_type": "markdown", - "id": "d3d47477", - "metadata": {}, - "source": [ - "### Multiply robust estimator" - ] - }, - { - "cell_type": "code", - "execution_count": 166, - "id": "d8c15b96", - "metadata": {}, - "outputs": [], - "source": [ - "def get_regressions(regularization=False, interaction=False, forest=False, calibration=True, calib_method='sigmoid'):\n", - " if regularization:\n", - " alphas, cs = ALPHAS, ALPHAS\n", - " else:\n", - " alphas, cs = [0.0], [np.inf]\n", - " \n", - " # mu_tm, f_mtx, and p_x model fitting\n", - " if not forest:\n", - " y_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS)\n", - " pre_m_prob = LogisticRegressionCV(Cs=cs, cv=CV_FOLDS)\n", - " pre_p_x_clf = LogisticRegressionCV(Cs=cs, cv=CV_FOLDS)\n", - " else:\n", - " y_reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10)\n", - " pre_m_prob = RandomForestClassifier(n_estimators=100, min_samples_leaf=10)\n", - " pre_p_x_clf = RandomForestClassifier(n_estimators=100, min_samples_leaf=10)\n", - " if calibration:\n", - " m_prob = CalibratedClassifierCV(pre_m_prob, method=calib_method)\n", - " p_x_clf = CalibratedClassifierCV(pre_p_x_clf, method=calib_method)\n", - " else:\n", - " m_prob = pre_m_prob\n", - " p_x_clf = pre_p_x_clf\n", - " \n", - " return y_reg, m_prob, p_x_clf\n", - " \n", - "def get_train_test_lists(crossfit, n): \n", - " if crossfit < 2:\n", - " train_test_list = [[np.arange(n), np.arange(n)]]\n", - " else:\n", - " kf = KFold(n_splits=crossfit)\n", - " train_test_list = list(kf.split(x))\n", - " \n", - " return train_test_list\n", - "\n", - "def estimate_probabilities(t, m, x, crossfit, classifier_x, classifier_xm):\n", - " \n", - " n = len(t)\n", - " train_test_list = [[np.arange(n), np.arange(n)]]\n", - " \n", - " p_x, p_xm = [np.zeros(n) for h in range(2)]\n", - " # compute propensity scores\n", - " if len(x.shape) == 1:\n", - " x = x.reshape(-1, 1)\n", - " if len(m.shape) == 1:\n", - " m = m.reshape(-1, 1)\n", - " \n", - " train_test_list = get_train_test_lists(crossfit, n)\n", - " \n", - " for train_index, test_index in train_test_list:\n", - " x_clf = classifier_x.fit(x[train_index, :], t[train_index])\n", - " xm_clf = classifier_xm.fit(np.hstack((x, m))[train_index, :], t[train_index])\n", - " p_x[test_index] = x_clf.predict_proba(x[test_index, :])[:, 1]\n", - " p_xm[test_index] = xm_clf.predict_proba(\n", - " np.hstack((x, m))[test_index, :])[:, 1]\n", - " \n", - " return p_x, p_xm\n", - "\n", - "def get_interactions(interaction, *args):\n", - " \"\"\"\n", - " this function provides interaction terms between different groups of\n", - " variables (confounders, treatment, mediators)\n", - " Inputs\n", - " --------\n", - " interaction boolean\n", - " whether to compute interaction terms\n", - "\n", - " *args flexible, one or several arrays\n", - " blocks of variables between which interactions should be\n", - " computed\n", - " Returns\n", - " --------\n", - " Examples\n", - " --------\n", - " >>> x = np.arange(6).reshape(3, 2)\n", - " >>> t = np.ones((3, 1))\n", - " >>> m = 2 * np.ones((3, 1))\n", - " >>> get_interactions(False, x, t, m)\n", - " array([[0., 1., 1., 2.],\n", - " [2., 3., 1., 2.],\n", - " [4., 5., 1., 2.]])\n", - " >>> get_interactions(True, x, t, m)\n", - " array([[ 0., 1., 1., 2., 0., 1., 0., 2., 2.],\n", - " [ 2., 3., 1., 2., 2., 3., 4., 6., 2.],\n", - " [ 4., 5., 1., 2., 4., 5., 8., 10., 2.]])\n", - " \"\"\"\n", - " variables = list(args)\n", - " for index, var in enumerate(variables):\n", - " if len(var.shape) == 1:\n", - " variables[index] = var.reshape(-1,1)\n", - " pre_inter_variables = np.hstack(variables)\n", - " if not interaction:\n", - " return pre_inter_variables\n", - " new_cols = list()\n", - " for i, var in enumerate(variables[:]):\n", - " for j, var2 in enumerate(variables[i+1:]):\n", - " for ii in range(var.shape[1]):\n", - " for jj in range(var2.shape[1]):\n", - " new_cols.append((var[:, ii] * var2[:, jj]).reshape(-1, 1))\n", - " new_vars = np.hstack(new_cols)\n", - " result = np.hstack((pre_inter_variables, new_vars))\n", - " return result\n", - "\n", - "def multiply_robust_efficient(\n", - " y,\n", - " t,\n", - " m,\n", - " x,\n", - " interaction=False,\n", - " forest=False,\n", - " crossfit=0,\n", - " trim=0.01,\n", - " regularization=True,\n", - " calibration=True,\n", - " calib_method=\"sigmoid\",\n", - "):\n", - " \"\"\"\n", - " Presented in Eric J. Tchetgen Tchetgen. Ilya Shpitser.\n", - " \"Semiparametric theory for causal mediation analysis: Efficiency bounds,\n", - " multiple robustness and sensitivity analysis.\"\n", - " Ann. Statist. 40 (3) 1816 - 1845, June 2012.\n", - " https://doi.org/10.1214/12-AOS990\n", - "\n", - " Parameters\n", - " ----------\n", - " y : array-like, shape (n_samples)\n", - " Outcome value for each unit, continuous\n", - "\n", - " t : array-like, shape (n_samples)\n", - " Treatment value for each unit, binary\n", - "\n", - " m : array-like, shape (n_samples)\n", - " Mediator value for each unit, binary and unidimensional\n", - "\n", - " x : array-like, shape (n_samples, n_features_covariates)\n", - " Covariates value for each unit, continuous\n", - "\n", - " interaction : boolean, default=False\n", - " Whether to include interaction terms in the model\n", - " interactions are terms XT, TM, MX\n", - "\n", - " forest : boolean, default=False\n", - " Whether to use a random forest model to estimate the propensity\n", - " scores instead of logistic regression, and outcome model instead\n", - " of linear regression\n", - "\n", - " crossfit : integer, default=0\n", - " Number of folds for cross-fitting. If crossfit<2, no cross-fitting is applied\n", - "\n", - " trim : float, default=0.01\n", - " Limit to trim p_x and f_mtx for numerical stability (min=trim, max=1-trim)\n", - "\n", - " regularization : boolean, default=True\n", - " Whether to use regularized models (logistic or linear regression).\n", - " If True, cross-validation is used to chose among 8 potential\n", - " log-spaced values between 1e-5 and 1e5\n", - "\n", - " calibration : boolean, default=True\n", - " Whether to add a calibration step so that the classifier used to estimate\n", - " the treatment propensity score and the density of the (binary) mediator.\n", - " Calibration ensures the output of the [predict_proba](https://scikit-learn.org/stable/glossary.html#term-predict_proba)\n", - " method can be directly interpreted as a confidence level.\n", - "\n", - " calib_method : str, default=\"sigmoid\"\n", - " Which calibration method to use.\n", - " Implemented calibration methods are \"sigmoid\" and \"isotonic\".\n", - "\n", - "\n", - " Returns\n", - " -------\n", - " total : float\n", - " Average total effect.\n", - " direct1 : float\n", - " Direct effect on the exposed.\n", - " direct0 : float\n", - " Direct effect on the unexposed,\n", - " indirect1 : float\n", - " Indirect effect on the exposed.\n", - " indirect0 : float\n", - " Indirect effect on the unexposed.\n", - " n_discarded : int\n", - " Number of discarded samples due to trimming.\n", - "\n", - "\n", - " Raises\n", - " ------\n", - " ValueError\n", - " - If t or y are multidimensional.\n", - " - If x, t, m, or y don't have the same length.\n", - " - If m is not binary.\n", - " \"\"\"\n", - " # Format checking\n", - " if len(y) != len(y.ravel()):\n", - " raise ValueError(\"Multidimensional y is not supported\")\n", - " if len(t) != len(t.ravel()):\n", - " raise ValueError(\"Multidimensional t is not supported\")\n", - " if len(m) != len(m.ravel()):\n", - " raise ValueError(\"Multidimensional m is not supported\")\n", - "\n", - " n = len(y)\n", - " if len(x.shape) == 1:\n", - " x.reshape(n, 1)\n", - " if len(m.shape) == 1:\n", - " m.reshape(n, 1)\n", - "\n", - " dim_m = m.shape[1]\n", - " if n * dim_m != sum(m.ravel() == 1) + sum(m.ravel() == 0):\n", - " raise ValueError(\"m is not binary\")\n", - "\n", - " y = y.ravel()\n", - " t = t.ravel()\n", - " m = m.ravel()\n", - " if n != len(x) or n != len(m) or n != len(t):\n", - " raise ValueError(\"Inputs don't have the same number of observations\")\n", - "\n", - " # Initialisation\n", - " (\n", - " p_x, # P(T=1|X)\n", - " f_00x, # f(M=0|T=0,X)\n", - " f_01x, # f(M=0|T=1,X)\n", - " f_10x, # f(M=1|T=0,X)\n", - " f_11x, # f(M=1|T=1,X)\n", - " f_m0x, # f(M|T=0,X)\n", - " f_m1x, # f(M|T=1,X)\n", - " mu_t1, # E[Y|T=1,M,X]\n", - " mu_t0, # E[Y|T=0,M,X]\n", - " mu_t1_m1, # E[Y|T=1,M=1,X]\n", - " mu_t1_m0, # E[Y|T=1,M=0,X]\n", - " mu_t0_m1, # E[Y|T=0,M=1,X]\n", - " mu_t0_m0, # E[Y|T=0,M=0,X]\n", - " E_mu_t0_t0, # E[E[Y|T=0,M,X]|T=0,X]\n", - " E_mu_t0_t1, # E[E[Y|T=0,M,X]|T=1,X]\n", - " E_mu_t1_t0, # E[E[Y|T=1,M,X]|T=0,X]\n", - " E_mu_t1_t1, # E[E[Y|T=1,M,X]|T=1,X]\n", - " ) = [np.zeros(n) for _ in range(17)]\n", - " t0, m0 = np.zeros((n, 1)), np.zeros((n, 1))\n", - " t1, m1 = np.ones((n, 1)), np.ones((n, 1))\n", - " n_discarded = 0\n", - "\n", - " if regularization:\n", - " alphas, cs = ALPHAS, ALPHAS\n", - " else:\n", - " alphas, cs = [0.0], [np.inf]\n", - "\n", - " train_test_list = get_train_test_lists(crossfit, n)\n", - "\n", - " # Cross-fitting loop\n", - " for train_index, test_index in train_test_list:\n", - " # Index declaration\n", - " test_ind = np.arange(len(test_index))\n", - " ind_t0 = t[test_index] == 0\n", - "\n", - " y_reg, m_prob, p_x_clf = get_regressions(regularization, interaction, forest, calibration)\n", - " y_reg.fit(\n", - " get_interactions(interaction, x, t, m)[train_index, :], y[train_index]\n", - " )\n", - " m_prob.fit(\n", - " get_interactions(interaction, t, x)[train_index, :], m[train_index]\n", - " )\n", - " p_x_clf.fit(\n", - " x[train_index, :], t[train_index]\n", - " )\n", - "\n", - " # predict P(T=1|X)\n", - " p_x[test_index] = p_x_clf.predict_proba(x[test_index, :])[:, 1]\n", - "\n", - " # predict f(M=m|T=t,X)\n", - " res = m_prob.predict_proba(get_interactions(interaction, t0, x)[test_index, :])\n", - " f_00x[test_index] = res[:, 0]\n", - " f_01x[test_index] = res[:, 1]\n", - " res = m_prob.predict_proba(get_interactions(interaction, t1, x)[test_index, :])\n", - " f_10x[test_index] = res[:, 0]\n", - " f_11x[test_index] = res[:, 1]\n", - "\n", - " # predict f(M|T=t,X)\n", - " f_m0x[test_index] = m_prob.predict_proba(\n", - " get_interactions(interaction, t0, x)[test_index, :]\n", - " )[test_ind, m[test_index]]\n", - " f_m1x[test_index] = m_prob.predict_proba(\n", - " get_interactions(interaction, t1, x)[test_index, :]\n", - " )[test_ind, m[test_index]]\n", - "\n", - " # predict E[Y|T=t,M,X]\n", - " mu_t1[test_index] = y_reg.predict(\n", - " get_interactions(interaction, x, t1, m)[test_index, :]\n", - " )\n", - " mu_t0[test_index] = y_reg.predict(\n", - " get_interactions(interaction, x, t0, m)[test_index, :]\n", - " )\n", - "\n", - " # predict E[Y|T=t,M=m,X]\n", - " mu_t0_m0[test_index] = y_reg.predict(\n", - " get_interactions(interaction, x, t0, m0)[test_index, :]\n", - " )\n", - " mu_t0_m1[test_index] = y_reg.predict(\n", - " get_interactions(interaction, x, t0, m1)[test_index, :]\n", - " )\n", - " mu_t1_m1[test_index] = y_reg.predict(\n", - " get_interactions(interaction, x, t1, m1)[test_index, :]\n", - " )\n", - " mu_t1_m0[test_index] = y_reg.predict(\n", - " get_interactions(interaction, x, t1, m0)[test_index, :]\n", - " )\n", - "\n", - " # E[E[Y|T=1,M=m,X]|T=t,X] model fitting\n", - " reg_y_t1m1_t0 = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit(\n", - " x[test_index, :][ind_t0, :], mu_t1_m1[test_index][ind_t0]\n", - " )\n", - " reg_y_t1m0_t0 = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit(\n", - " x[test_index, :][ind_t0, :], mu_t1_m0[test_index][ind_t0]\n", - " )\n", - " reg_y_t1m1_t1 = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit(\n", - " x[test_index, :][~ind_t0, :], mu_t1_m1[test_index][~ind_t0]\n", - " )\n", - " reg_y_t1m0_t1 = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit(\n", - " x[test_index, :][~ind_t0, :], mu_t1_m0[test_index][~ind_t0]\n", - " )\n", - "\n", - " # predict E[E[Y|T=1,M=m,X]|T=t,X]\n", - " E_mu_t1_t0[test_index] = (\n", - " reg_y_t1m0_t0.predict(x[test_index, :]) * f_00x[test_index]\n", - " + reg_y_t1m1_t0.predict(x[test_index, :]) * f_01x[test_index]\n", - " )\n", - " E_mu_t1_t1[test_index] = (\n", - " reg_y_t1m0_t1.predict(x[test_index, :]) * f_10x[test_index]\n", - " + reg_y_t1m1_t1.predict(x[test_index, :]) * f_11x[test_index]\n", - " )\n", - "\n", - " # E[E[Y|T=0,M=m,X]|T=t,X] model fitting\n", - " reg_y_t0m1_t0 = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit(\n", - " x[test_index, :][ind_t0, :], mu_t0_m1[test_index][ind_t0]\n", - " )\n", - " reg_y_t0m0_t0 = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit(\n", - " x[test_index, :][ind_t0, :], mu_t0_m0[test_index][ind_t0]\n", - " )\n", - " reg_y_t0m1_t1 = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit(\n", - " x[test_index, :][~ind_t0, :], mu_t0_m1[test_index][~ind_t0]\n", - " )\n", - " reg_y_t0m0_t1 = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit(\n", - " x[test_index, :][~ind_t0, :], mu_t0_m0[test_index][~ind_t0]\n", - " )\n", - "\n", - " # predict E[E[Y|T=0,M=m,X]|T=t,X]\n", - " E_mu_t0_t0[test_index] = (\n", - " reg_y_t0m0_t0.predict(x[test_index, :]) * f_00x[test_index]\n", - " + reg_y_t0m1_t0.predict(x[test_index, :]) * f_01x[test_index]\n", - " )\n", - " E_mu_t0_t1[test_index] = (\n", - " reg_y_t0m0_t1.predict(x[test_index, :]) * f_10x[test_index]\n", - " + reg_y_t0m1_t1.predict(x[test_index, :]) * f_11x[test_index]\n", - " )\n", - "\n", - " # trimming\n", - " p_x_trim = p_x != np.clip(p_x, trim, 1 - trim)\n", - " f_m0x_trim = f_m0x != np.clip(f_m0x, trim, 1 - trim)\n", - " f_m1x_trim = f_m1x != np.clip(f_m1x, trim, 1 - trim)\n", - " trimmed = p_x_trim + f_m0x_trim + f_m1x_trim\n", - "\n", - " var_name = [\"t\", \"y\", \"p_x\", \"f_m0x\", \"f_m1x\", \"mu_t1\", \"mu_t0\"]\n", - " var_name += [\"E_mu_t1_t1\", \"E_mu_t0_t0\", \"E_mu_t1_t0\", \"E_mu_t0_t1\"]\n", - "\n", - " for var in var_name:\n", - " exec(f\"{var} = {var}[~trimmed]\")\n", - " n_discarded += np.sum(trimmed)\n", - "\n", - " # ytmt computing\n", - " y1m1 = t / p_x * (y - E_mu_t1_t1) + E_mu_t1_t1\n", - " y0m0 = (1 - t) / (1 - p_x) * (y - E_mu_t0_t0) + E_mu_t0_t0\n", - " y1m0 = (\n", - " (t / p_x) * (f_m0x / f_m1x) * (y - mu_t1)\n", - " + (1 - t) / (1 - p_x) * (mu_t1 - E_mu_t1_t0)\n", - " + E_mu_t1_t0\n", - " )\n", - " y0m1 = (\n", - " (1 - t) / (1 - p_x) * (f_m1x / f_m0x) * (y - mu_t0)\n", - " + t / p_x * (mu_t0 - E_mu_t0_t1)\n", - " + E_mu_t0_t1\n", - " )\n", - "\n", - " # effects computing\n", - " total = np.mean(y1m1 - y0m0)\n", - " direct1 = np.mean(y1m1 - y0m1)\n", - " direct0 = np.mean(y1m0 - y0m0)\n", - " indirect1 = np.mean(y1m1 - y1m0)\n", - " indirect0 = np.mean(y0m1 - y0m0)\n", - "\n", - " return total, direct1, direct0, indirect1, indirect0, n_discarded\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "id": "2dabfd33", - "metadata": {}, - "outputs": [], - "source": [ - "# effects_MR = multiply_robust_efficient(y, t, m, x)\n", - "\n", - "# tau_hat, theta_1_hat, theta_0_hat, delta_1_hat, delta_0_hat, n_non_trimmed = effects_linear\n", - "# print(\"Multiply robust coefficients\")\n", - "# print(\"Direct effects\")\n", - "# print(\"True theta1:{}, estimated theta1: {}\".format(theta_1, round(theta_1_hat,3)))\n", - "# print(\"True theta0:{}, estimated theta0: {}\".format(theta_0, round(theta_0_hat,3)))\n", - "# print(\"\\\\\")\n", - "# print(\"Indirect effects\")\n", - "# print(\"True delta1:{}, estimated delta1: {}\".format(delta_1, round(delta_1_hat,3)))\n", - "# print(\"True delta0:{}, estimated delta0: {}\".format(delta_0, round(delta_0_hat,3)))\n", - "# print(\"\\\\\")\n", - "# print(\"Total effect\")\n", - "# print(\"True tau:{}, estimated tau: {}\".format(tau, round(tau_hat,3)))" - ] - }, - { - "cell_type": "code", - "execution_count": 289, - "id": "859c9b16", - "metadata": {}, - "outputs": [], - "source": [ - "params={\n", - " 'trim':0,\n", - " 'logit':True,\n", - " 'regularization':False,\n", - " 'forest':False,\n", - " 'crossfit':0,\n", - " 'clip':0.01,\n", - " 'calibration':False,\n", - "}\n", - "\n", - "dataset_name='blobs_overlap'\n", - "n_samples=10000\n", - "mediator_binary=False\n", - "\n", - "list_causal_effects = ['total effect $\\tau$', 'direct effect treated $\\theta(1)$','direct effect non treated $\\theta(0)$', 'indirect effect treated $\\delta(1)$', 'indirect effect untreated $\\delta(0)$', 'n']\n", - "\n", - "def run_experiment(dataset_name, n_samples, mediator_binary, params, overlap_coefficient):\n", - " \n", - " causal_data, causal_effects = generate_causal_data(dataset_name, n_samples, mediator_binary, overlap_coefficient)\n", - " x, t, m, y = causal_data\n", - " classifier_x, classifier_xm = get_classifier(params['regularization'], params['forest'], params['calibration'])\n", - " p_x, p_xm = estimate_probabilities(t, m, x, params['crossfit'], classifier_x, classifier_xm)\n", - " effects_IPW = IPW(y, t, m, x, params['trim'], p_x, p_xm, params['clip'])\n", - " effects_SNIPW = SNIPW(y, t, m, x, params['trim'], p_x, p_xm, params['clip'])\n", - " effects_linear = ols_mediation(y, t, m, x)\n", - " effects_g_computation = g_computation(y, t, m, x)\n", - " effects_MR = multiply_robust_efficient(y, t, m, x)\n", - " data = {'causal_effects': list_causal_effects}\n", - " data['Truth'] = causal_effects\n", - " data['IPW'] = effects_IPW\n", - " data['SNIPW'] = effects_SNIPW\n", - " data['linear'] = effects_linear\n", - " data['G-computation'] = effects_g_computation\n", - " data['MR'] = effects_MR\n", - " df = pd.DataFrame(data)\n", - " df = df[:-1]\n", - " df.set_index('causal_effects', inplace=True)\n", - " return df\n", - "\n", - "# results_df = run_experiment(dataset_name, n_samples, True, params)" - ] - }, - { - "cell_type": "code", - "execution_count": 311, - "id": "a1929ae8", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", - " y = column_or_1d(y, warn=True)\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", - " y = column_or_1d(y, warn=True)\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=2):\n", - "ABNORMAL_TERMINATION_IN_LNSRCH.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", - " y = column_or_1d(y, warn=True)\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", - " y = column_or_1d(y, warn=True)\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", - " y = column_or_1d(y, warn=True)\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", - " y = column_or_1d(y, warn=True)\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", - " y = column_or_1d(y, warn=True)\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", - " y = column_or_1d(y, warn=True)\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", - " y = column_or_1d(y, warn=True)\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", - " y = column_or_1d(y, warn=True)\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=2):\n", - "ABNORMAL_TERMINATION_IN_LNSRCH.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", - " y = column_or_1d(y, warn=True)\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", - " y = column_or_1d(y, warn=True)\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=2):\n", - "ABNORMAL_TERMINATION_IN_LNSRCH.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", - " y = column_or_1d(y, warn=True)\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", - " y = column_or_1d(y, warn=True)\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", - " y = column_or_1d(y, warn=True)\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", - " y = column_or_1d(y, warn=True)\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", - " y = column_or_1d(y, warn=True)\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", - " y = column_or_1d(y, warn=True)\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=2):\n", - "ABNORMAL_TERMINATION_IN_LNSRCH.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", - " y = column_or_1d(y, warn=True)\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", - " y = column_or_1d(y, warn=True)\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=2):\n", - "ABNORMAL_TERMINATION_IN_LNSRCH.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=2):\n", - "ABNORMAL_TERMINATION_IN_LNSRCH.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", - " y = column_or_1d(y, warn=True)\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", - " y = column_or_1d(y, warn=True)\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=2):\n", - "ABNORMAL_TERMINATION_IN_LNSRCH.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n" - ] - } - ], - "source": [ - "list_overlap_coefficients = list(np.arange(0, 1.1, 0.1))\n", - "\n", - "direct_effect_treated_dic ={\n", - " 'Truth': [],\n", - " 'IPW': [],\n", - " 'SNIPW': [],\n", - " 'linear': [],\n", - " 'G-computation': [],\n", - " 'MR': []\n", - "}\n", - "direct_effect_treated_df = pd.DataFrame(direct_effect_treated_dic)\n", - "\n", - "direct_effect_non_treated_df = direct_effect_treated_df.copy()\n", - "indirect_effect_treated_df = direct_effect_treated_df.copy()\n", - "indirect_effect_non_treated_df = direct_effect_treated_df.copy()\n", - "total_effect_df = direct_effect_treated_df.copy()\n", - "n_samples = 100000\n", - "\n", - "for coefficient in list_overlap_coefficients:\n", - " results_df = run_experiment(dataset_name, n_samples, True, params, coefficient)\n", - " total_effect_df.loc[len(total_effect_df.index)] = results_df.iloc[0].values\n", - " direct_effect_treated_df.loc[len(direct_effect_treated_df.index)] = results_df.iloc[1].values\n", - " direct_effect_non_treated_df.loc[len(direct_effect_non_treated_df.index)] = results_df.iloc[2].values\n", - " indirect_effect_treated_df.loc[len(indirect_effect_treated_df.index)] = results_df.iloc[3].values\n", - " indirect_effect_non_treated_df.loc[len(indirect_effect_non_treated_df.index)] = results_df.iloc[4].values" - ] - }, - { - "cell_type": "code", - "execution_count": 309, - "id": "c03cac85-b10c-41a5-8c0f-8dd19d538aeb", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
TruthIPWSNIPWlinearG-computationMR
00.3574020.3524600.3524600.3493570.3025150.352481
10.3579080.3582670.3582960.3578860.2564030.357535
20.3588980.3332630.3328750.3301530.2900080.333733
30.3597490.3543990.3543850.3508640.3189230.355388
40.3603300.3439090.3437900.3407820.2362880.344092
50.3607100.3600250.3598610.3568760.2694090.359386
60.3609610.4220340.4220310.4177720.3555090.422454
70.3611330.3358430.3359500.3328040.2802510.336579
80.3612540.4359420.4358860.4355830.3765360.436722
90.3613420.3608320.3608300.3572710.3055340.361261
100.3614080.3666850.3667480.3637640.2876680.365552
\n", - "
" - ], - "text/plain": [ - " Truth IPW SNIPW linear G-computation MR\n", - "0 0.357402 0.352460 0.352460 0.349357 0.302515 0.352481\n", - "1 0.357908 0.358267 0.358296 0.357886 0.256403 0.357535\n", - "2 0.358898 0.333263 0.332875 0.330153 0.290008 0.333733\n", - "3 0.359749 0.354399 0.354385 0.350864 0.318923 0.355388\n", - "4 0.360330 0.343909 0.343790 0.340782 0.236288 0.344092\n", - "5 0.360710 0.360025 0.359861 0.356876 0.269409 0.359386\n", - "6 0.360961 0.422034 0.422031 0.417772 0.355509 0.422454\n", - "7 0.361133 0.335843 0.335950 0.332804 0.280251 0.336579\n", - "8 0.361254 0.435942 0.435886 0.435583 0.376536 0.436722\n", - "9 0.361342 0.360832 0.360830 0.357271 0.305534 0.361261\n", - "10 0.361408 0.366685 0.366748 0.363764 0.287668 0.365552" - ] - }, - "execution_count": 309, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "total_effect_df" - ] - }, - { - "cell_type": "code", - "execution_count": 314, - "id": "1b8f5869-e7c9-48a7-b2b6-70b5a890f313", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Text(0.5, 1.0, 'Undirect effect non treated')" - ] - }, - "execution_count": 314, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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okUMHDgQb29vfH19GTVqFLt27arR/x9//MEtt9xC69atMZlMREREcOutt5KXl+du88wzz/DYY48BEBMTc0JuAFzv+auvQ1BQEOPGjePo0aMnnM97771HbGwsZrOZPn36sGbNmtOev2j8ZOa8ELWkqipjxoxh1apV3HbbbXTv3p0lS5bw2GOPkZaWxuuvvw7A/Pnzuf322+nTpw933nknALGxsQBs2rSJ9evXM27cOFq0aEFqaiqzZ89myJAh7N69+6xngNWmv169etG6dWu++uorJkyYUGP/BQsWEBgYSGJiIuBaiKZv377uFz2hoaEsWrSI2267jeLi4hMWQp0+fToGg4FHH30Ui8WCwWBg9+7dfP/991x33XXExMSQlZXFf//7XwYPHszu3buJjIwEXB90XHLJJWRkZPDvf/+biIgIPv/8c1atWnXCea5cuZKRI0cSHx/P1KlT0Wg07jfZa9asoU+fPqe8Rk6nkzFjxrB27VruvPNOOnTowM6dO3n99dfZv38/33//PaGhocyfP5/nn3+e0tJSZsyYAUCHDh2YP38+Dz/8MC1atOCRRx4BIDQ0tFb9Vps2bRrPPPMM/fv359lnn8VgMLBx40ZWrlzJ8OHDmTVrFg888AA+Pj48+eSTAGcsnSSEEOKfGT9+PP/3f//H0qVLueOOO07bduXKlXz11Vfcf//9hISEEB0dXesx0+FwMHr0aFasWMG4ceP497//TUlJCcuWLePPP/9k6NChzJ49m3vuuYerrrqKq6++GqDGV/v/rry8nMGDB5OWlsZdd91Fy5YtWb9+PZMnTyYjI4NZs2adcgzr0aOHu87tsGHDuPnmm8+q32q33XYb8+bNY+TIkdx+++3Y7XbWrFnDhg0b6NWr12lfD/1dhw4dePbZZ5kyZQp33nknAwcOBKB///7uNnl5eYwcOZJx48Zx0003ER4eflZj8ezZs+nUqRNjxoxBp9Px448/cu+99+J0OrnvvvsATjse1/baqKrKFVdcwdq1a7n77rvp0KED33333QmvwYQQQvxFxuTzZ0w+3osvvohGo+HRRx+lqKiIl19+mRtvvJGNGze621SXLOrduzczZswgKyuLN954g3Xr1rFt27Ya3whwOBwkJiaSkJDAzJkzWb58Oa+++iqxsbHcc889p4yjNu+X7733XkJDQ5kyZQplZWWAKzczYcIE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+44777yTRx99FL1ez3PPPcddd93FJZdcwtixY0lJSeGjjz6SmvNNnSqEOKn77rtP/ft/kZKSEvXhhx9WIyMjVb1er7Zt21Z95ZVXVKfTWaPd3r171UGDBqlms1kF1AkTJqiqqqoFBQXqxIkT1ZCQENXHx0dNTExU9+7dq7Zq1crdRlVVddWqVSqgrlq16rQx1ra/asnJySqgAuratWtP2mdWVpZ63333qVFRUaper1cjIiLUSy+9VH3vvfdOiO/rr78+Yf/Kykr1kUceUZs1a6aazWb1oosuUpOSktTBgwergwcPrtH20KFD6qhRo1Sz2ayGhoaqjzzyiPrNN9+ogLphw4Yabbdt26ZeffXVanBwsGo0GtVWrVqp119/vbpixYrTXiNVVVWr1aq+9NJLaqdOnVSj0agGBgaq8fHx6rRp09SioiJ3u8GDB6udOnU6Yf9WrVqpo0aNOud+VVVV586dq/bo0cPdbvDgweqyZcvcz2dmZqqjRo1SfX19VeCEayWEEOLsfPTRR+4xD1ANBoMaERGhDhs2TH3jjTfU4uLiE/aZOnXqCWM/oN53330nPUZtxkxVVdXy8nL1ySefVGNiYtztrr32WvXgwYPuNuvXr1fj4+NVg8GgAurUqVNPe34lJSXq5MmT1TZt2qgGg0ENCQlR+/fvr86cOVO1Wq3udqcaw051XrXt1263q6+88ooaFxenGgwGNTQ0VB05cqS6ZcsWd5tTvR46lR9++EHt2LGjqtPpVED96KOPVFU99fisqrUfixcuXKh27dpVNZlManR0tPrSSy+pc+fOVQE1JSXF3e5043Ftr01eXp46fvx41c/PT/X391fHjx+vbtu2rcY5CSFEUyJjssuFMiaf6v1+SkrKSceyBQsWuN/rBgUFqTfeeKN67NixGm0mTJigent7n3Csk/2eT+ZU43P1v61Nmzad8lwSExNVf39/1WQyqbGxseott9yibt682d3m2LFj6lVXXaUGBASo/v7+6nXXXaemp6ef9Hc/ffp0tXnz5qpGoznhNcQ333yjDhgwQPX29la9vb3VuLg49b777lP37dtXo493331XjYmJUY1Go9qrVy/1t99+O2m+RDQdiqqe40oOQghRD2bNmsXDDz/MsWPHaN68uafDEUIIIYQQQgghhBCiXkhyXgjhMRUVFTVWVa+srKRHjx44HA7279/v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vP/++9x0000A7Nu3j6lTp7Jp0yYOHDjA0qVLufPOO+nRowetW7euxDMkUjWorxcpm+bRbchzKYIiqBVavPZXUtK5vwAWEalsyu0iF9agdfH6aMlpbjRs3wk3T08sWVbqpruz3NOVE5vedXKEF0eD806QmV5S1kYz50WqMsMwsGZnO+VmGMZFxfz3yyFNJhPvvPMON910E15eXjRq1IilS5faPeb333/n2muvxcfHh+DgYO644w5SU1Nt9y9btowrr7ySWrVqUbt2ba677jr27dtnu//AgQOYTCY+/PBDYmNj8fDwYNGiRRcVvzhXSSmZp59+mrZt2xIfH8+yZctsi8QeOnTIbiHXpKQk2rVrR7t27UhOTmbGjBm0a9eOu+++29bm9OnTjBkzhqZNm3LnnXdy5ZVXsnz5clxd/6zzu2TJEjp16sSwYcNo3rw506ZN47nnnuO+++4Dimf1f//99/Tt25emTZvyyCOPMHjwYL788stKOjNSk6mvL6a+XmqyNlH9SQkoniDlElwIwClLHbJT0p0ZlohUEOX2YsrtUtNEX9seDCtZrrXJ3H+cmI5XANA5JYhCk4mPts+Hi/w/6ExaENYJSmbOq6yNSNVm5OSwq30Hpzx3k982YSqnmRPPPPMM06dP56WXXmLWrFkMGzaMgwcPEhgYyKlTp+jduzd33303r776Kjk5OTz++OMMGTKEH374AYCsrCzGjx9P69atyczM5Omnn+amm24iPj7erhTJE088wcsvv0y7du3w8FD/Vl2NHTuWsWPHlnpfXFyc3e+RkZEX/AAyZMgQhgwZct42ISEhzJs375z3169fn9WrV593HyIXS329+nqp+ZqEd+NkQB71T3iRlLQNr4I6ZLsGkvjtJloM7+Ps8ESknCm3K7dLzeRVrza1ik5wyiWY/d9toelVsez4aRXBx70xNYaPLLmMTlyNW1RPZ4daJhqcd4KSmfO+Aer0RKTijRgxgltvvRWA559/nv/7v/9jw4YN9O/fn9dff5127drx/PPP29q/++671K9fn927d9O4cWMGDx5st793332XoKAgduzYQcuWLW3bx40bx80331w5ByUiInbU14ucm6vFFe/aJgCOHThCk8Bc9mfDwS3HaOHk2EREzkW5XeRsoSEmTqXC4V2naPvAtXj4+pGbcYbmab5sr5PBt+tncKMG5+V8DMMg42RJWRvVnBepykyenjT5bZPTnru8/LUmt7e3N35+fqSkpACwZcsWVq1ahY+Pz1mP27dvH40bN2bPnj08/fTT/PLLL6SmptoW6Tx06JDdm7qOHTuWW8wiIpVFfb36erk8RNWvT9H6M5BTRFATL/ZvhmOny+//oIhUHcrtyu1Sc0V2bciOL7NIyauFCRNNrujOlhXf0i2zCdvr/MqizD3ccDoJk3+os0N1mAbnK1l+TiEFeUUA+GjmvEiVZjKZyu2SRGf6a21vKD6ukjdmmZmZXH/99bz44otnPa5evXoAXH/99URERPD2228TGhqK1WqlZcuW5Ofn27X39vauoCMQEak46uvV18vloXWDbqzy/x91T3ngEu6GaVMROa4BpG7ZR5020c4OT0TKkXK7crvUXPWvbovli5UUuHhz9MdtNO0Wy5YV32I6kIVXuIkEdzd+W/sSHa591dmhOkyD85UsM7243ryHtyuu7hYnRyMil7v27dvz6aefEhkZiYvL2Snh5MmT7Nq1i7fffpurrroKgJ9//rmywxQRkUugvl4E2sQM5MOAj6h7yoPk/VsIMBqSRgj7v9+mwXkRqXaU2+Vy5eLhTpAljWOEkvjTHq6aNBif2nXIPJnK9Xkt+NDldxYdXk6HwnxwcXN2uA4xX7iJlKeMNJW0EZGqY8yYMaSlpXHrrbeyceNG9u3bx/Llyxk5ciRFRUUEBARQu3Zt5s6dy969e/nhhx8YP368s8MWEZEyUF8vAiG1GpITUDxb9GDCVsLCigezjuzNdGZYIiIXRbldLmfhMcVXeyQdycdkNtOka/EXUNEZDQFY6WYmacsCp8VXVhqcr2SZfwzO+waqpI2IOF9oaChr1qyhqKiIvn370qpVK8aNG0etWrUwm82YzWaWLFnCpk2baNmyJQ8//DAvvfSSs8MWEZEyUF8vUlwOol7d4g/zWSezCO0UBkBKQSBFeQXODE1EpMyU2+VyFnV1KwDSTEHkpZ2hWfdYAFJ+38UVlmCsJhNLtr7jzBDLRGVtKllGWnFZG9WbF5HyEhcXZ/v5wIEDdvcZhnFW+1OnTtn93qhRIz777LNz7r9Pnz7s2LHjnPuNjIws9XlERKT8qK8XuXQtQ1tw0Hs3/lmuEGTBpTCbQhcvDq2Mp+GATs4OT0QuM8rtIhendpsoPAu2kuNai/3LNtH01p4E1AslPTmJ/m79WJ/zPp8ap7nvyK94hVf9BY81c76SZaarrI2IiIiIiEhlax3Rk+MBxZOlkvckUNftFAAH1u13YlQiIiJSFmazmWDfbAAObU7CZDLRpFvx7HnT/izCTW6csVj4at00Z4bpMA3OV7IMlbURERERERGpdC0a9iO1VvHnsQNbfyG8sR8ASclWZ4YlIiIiZdSgdTAAyWnFi7427d4DgINbN3NLvQEALD69HSM73TkBloEG5ytZ5h9lbTQ4LyIiIiIiUnm83H3wCCweiD9x+CiRvZoBcMoSRPbxNGeGJiIiImUQfW17MKxkudYmfechaofVJygyCmtREc2K2uNlwD5XF9atne7sUC+oSgzOz549m8jISDw8POjSpQsbNmw4Z9u3336bq666ioCAAAICAujTp0+p7RMSErjhhhvw9/fH29ubTp06cejQoYo8jAuyWg0yT5XUnFdZGxERERERkcrUuG4IOW5FGEUGBZ6FeBecBJOZ/d9scnZoFaIsn7W3b9/O4MGDiYyMxGQyMXPmzLPaZGRkMG7cOCIiIvD09KRbt25s3LjRrk1mZiZjx44lPDwcT09PmjdvzptvvmnXpmfPnphMJrvbfffdVy7HLCIiNZ9XvdrUKjoBwP7vtgDQtFvx7PkDv2xgUO02ACw68DVYq/YVck4fnP/www8ZP348kydP5rfffqNNmzb069ePlJSUUtvHxcVx6623smrVKtatW0f9+vXp27cvR48etbXZt28fV155JU2bNiUuLo6tW7cyadIkPDycO1s9+3Q+htXAZDbh5a/BeRERERERkcrUOqQjJ/6oO390VwIhAfkAHNp63JlhVYiyftbOzs4mKiqKadOmERISUmqbu+++mxUrVrBgwQK2bdtG37596dOnj93n8fHjx7Ns2TIWLlxIQkIC48aNY+zYsSxdutRuX6NHjyY5Odl2mz696s9uFBGRqiM0xATA4V2ngD8H5w8n/M5NzcZiMgx+dDU4uP0jZ4XoEKcPzr/yyiuMHj2akSNH2r5R9/Ly4t133y21/aJFi3jggQdo27YtTZs25Z133sFqtbJy5Upbm6eeeooBAwYwffp02rVrR3R0NDfccAN169atrMMqlW0x2FrumM0mp8YiIiIiIiJyuWkdfa1tUdgj2+OJaFcPgGNnPJ0ZVoUo62ftTp068dJLL3HLLbfg7n72ZLKcnBw+/fRTpk+fTo8ePYiJiWHKlCnExMQwZ84cW7u1a9cyfPhwevbsSWRkJPfccw9t2rQ5a9a+l5cXISEhtpufn995jycvL48zZ87Y3URE5PIV2bUhACl5ARQVFOIXVJfQxs3AMMjadYyr3IvHgT+In3O+3TidUwfn8/Pz2bRpE3369LFtM5vN9OnTh3Xr1jm0j+zsbAoKCggMDATAarXy9ddf07hxY/r160fdunXp0qULX3zxxTn3UVlJvmQxWJ9AzZoXERERERGpbA3rdSDjj0Vhj+zaTsP+HTBZC8lxDSB1yz4nR1d+yuOz9t8VFhZSVFR01hXpnp6e/Pzzz7bfu3XrxtKlSzl69CiGYbBq1Sp2795N37597R63aNEi6tSpQ8uWLZk4cSLZ2dnnff4XXngBf39/261+/foXdRwiIlIz1L+6LZaiXApcvEj6cRvw58KwO9esZlib+wH4ojCVzJQEp8V5IU4dnE9NTaWoqIjg4GC77cHBwRw7dsyhfTz++OOEhoba3nSkpKSQmZnJtGnT6N+/P9999x033XQTN998M6tXry51H5WV5G2D8wFaDFZERERERKSymU1mwgM8KDRbyc/OIzsvkwAjFYD9329zcnTlpzw+a/+dr68vXbt2ZerUqSQlJVFUVMTChQtZt24dycnJtnazZs2iefPmhIeH4+bmRv/+/Zk9ezY9evSwtbnttttYuHAhq1atYuLEiSxYsIDbb7/9vM8/ceJETp8+bbsdPnz4oo5DRERqBhcPd4IsxQu6J/68F4DGV1yJyWTm2L49NA3oRhSuZJnNfLHmP84M9bycXtbmUkybNo0lS5bw+eef2769t/5R5P/GG2/k4Ycfpm3btjzxxBNcd911Zy1CU6KyknxmevHlk76BGpwXERERERFxhpa1Y0j1L641f3TXdsLCXQA4vDfTmWFVCwsWLMAwDMLCwnB3d+f//u//uPXWWzGb/xxamDVrFuvXr2fp0qVs2rSJl19+mTFjxvD999/b2txzzz3069ePVq1aMWzYMN5//30+//xz9u0799UL7u7u+Pn52d1EROTyFh7jDUDSkeK87l0rgAatiheD3b32J4ZFDgRgcVo8RXlZzgnyApw6OF+nTh0sFgvHj9svvnP8+PFzLkBTYsaMGUybNo3vvvuO1q1b2+3TxcWF5s2b27Vv1qwZhw4dKnVflZXkM/+YOe+rsjYiIlVOXFwcJpOJU6dOOTsUERGpIOrrBaBN2JWkBBZPnEramUDDKxsBcKIgkMLcPGeGVm4u5bP2+URHR7N69WoyMzM5fPgwGzZsoKCggKioKKC4Lv2TTz7JK6+8wvXXX0/r1q0ZO3YsQ4cOZcaMGefcb5cuXQDYu3fvRccmIpcn5fbLW9TVrQBIMwWRl1ZcprxkYdida39kYJcJRJs9uT6yPwVVdPlPpw7Ou7m50aFDB7vFXEsWd+3ates5Hzd9+nSmTp3KsmXL6Nix41n77NSpE7t27bLbvnv3biIiIsr3AMroz5rzmjkvIuXv2LFjPPTQQ8TExODh4UFwcDDdu3dnzpw5F6zhWV1FRkYyc+bMMj+uZ8+ejBs3zm5bt27dSE5Oxt/fv3yCExGpAOrrHae+Xs6lVaPrSPljUdjDOzYT2qMVroXZFLl4cPiHLU6Ornxc7GdtR3l7e1OvXj3S09NZvnw5N954IwAFBQUUFBTYzaQHsFgstqvcSxMfHw9AvXr1Ljk2kepGud1xyu3yd7XbROFZkI5hdmH/sk0AxHTuisXFhZNHDpF9/CSf3/4L91/9Mh5u3k6OtnQuzg5g/PjxDB8+nI4dO9K5c2dmzpxJVlYWI0eOBODOO+8kLCyMF154AYAXX3yRp59+msWLFxMZGWmrl+fj44OPjw8AEyZMYOjQofTo0YNevXqxbNkyvvzyS+Li4pxyjCUy04rfAKrmvIiUt/3799O9e3dq1arF888/T6tWrXB3d2fbtm3MnTuXsLAwbrjhBmeHWaW5ubld0kwyEZGKpr7+0qmvF4AA33q4/lHW5nRKKnk5WQS5p5NU5MWBtftpOKCzkyMsH2X9rJ2fn8+OHTtsPx89epT4+Hh8fHyIiYkBYPny5RiGQZMmTdi7dy8TJkygadOmtn36+fkRGxvLhAkT8PT0JCIigtWrV/P+++/zyiuvALBv3z4WL17MgAEDqF27Nlu3buXhhx+mR48edlfFi1wOlNsvnXL75c1sNhPil0NiTgAHf0ui2W3g4e1Dw3Yd2btxPTvXrOaqiIbODvP8jCpg1qxZRoMGDQw3Nzejc+fOxvr16233xcbGGsOHD7f9HhERYQBn3SZPnmy3z//+979GTEyM4eHhYbRp08b44osvHI7n9OnTBmCcPn36Ug/NJj+v0Hj93pXG6/euNHKz8sttvyJSfnJycowdO3YYOTk5hmEYhtVqNfJzC51ys1qtZYq9X79+Rnh4uJGZmVnq/efb3+HDh41bbrnFCAgIMLy8vIwOHTrY9cNvvPGGERUVZbi6uhqNGzc23n//fbvHA8abb75pDBw40PD09DSaNm1qrF271tizZ48RGxtreHl5GV27djX27t1re8zkyZONNm3aGG+++aYRHh5ueHp6Gv/85z+NU6dO2drExsYaDz30kN1z3XjjjbacEBsbe1YuMAzDSE1NNW655RYjNDTU8PT0NFq2bGksXrzYto/hw4ef9bjExERj1apVBmCkp6fb2n7yySdG8+bNDTc3NyMiIsKYMWOGXTwRERHGc889Z4wcOdLw8fEx6tevb7z11lvnPNd/f439VUXkHvmTzq+UUF+vvt6Zfb1UHY9/cI3x1KhrjBlDBhq7N6w1Ns78n/H6vSuNhXctvvCDHVQVck9ZPmsnJiaW+lk7NjbW1ubDDz80oqKiDDc3NyMkJMQYM2aM3f9pwzCM5ORkY8SIEUZoaKjh4eFhNGnSxHj55ZdtfdShQ4eMHj16GIGBgYa7u7sRExNjTJgwocznqSqcX3G+0vpc5fZiyu3K7ZeLrf/9znj93pXGvFEf2bbtXPujMWPIQGPumFFl/n95PhWRe5w+cx5g7NixjB07ttT7/j7b/cCBAw7tc9SoUYwaNeoSIys/JfXmXT0suHlWidMuIhdQmG9l7kOrnfLc97wWi6u7xaG2J0+e5LvvvuP555/H27v0y7RMptKLq2VmZhIbG0tYWBhLly4lJCSE3377zXbZ8eeff85DDz3EzJkz6dOnD1999RUjR44kPDycXr162fYzdepUXnnlFV555RUef/xxbrvtNqKiopg4cSINGjRg1KhRjB07lm+//db2mL179/LRRx/x5ZdfcubMGe666y4eeOABFi1a5NBxf/bZZ7Rp04Z77rmH0aNH27bn5ubSoUMHHn/8cfz8/Pj666+54447iI6OpnPnzrz22mvs3r2bli1b8uyzzwIQFBR0Vn7ZtGkTQ4YMYcqUKQwdOpS1a9fywAMPULt2bUaMGGFr9/LLLzN16lSefPJJPvnkE+6//35iY2Np0qSJQ8chIs6lvl59vfr6y1PrOq2IC/iVgEw3knYl0Lrv1fySsI9TliCyk0/iVa+2s0MsF2X5rB0ZGYlhGOfd35AhQxgyZMh524SEhDBv3rxz3l+/fn1Wr3ZOvyuXB+V25Xbl9stL9LXt+fGXzWS51iZ95yECmjYgqn0nXD08OXPiOMl7dhLauJmzwzwnjRJXkpKSNr6BHufsXEVELsbevXttlxf/VZ06dcjNLf5icMyYMbz44otnPXbx4sWcOHGCjRs3EhgYCGC7bBmKF98eMWIEDzzwAFB8efT69euZMWOG3Zu6kSNH2j6oPf7443Tt2pVJkybRr18/AB566CHb5c4lcnNzef/99wkLCwNg1qxZDBw4kJdfftmhyxIDAwOxWCz4+vratQ8LC+PRRx+1/f6vf/2L5cuX89FHH9G5c2f8/f1xc3PDy8vrvM/zyiuvcPXVVzNp0iQAGjduzI4dO3jppZfs3tQNGDDAdn4ef/xxXn31VVatWqU3dSJSrtTXq6+X8tU6sg8fBq6hyWFfju7cTuzto/Au2ECWa232ffsbrUZd4+wQRaSGU25Xbpfy4VWvNrWKTnDKJZj9322hQ9MGuLp7ENOxCwk/x7FzzY8anBfISP9jMdgAdydHIiKOcnEzc89rsU577ku1YcMGrFYrw4YNIy8vj/vuu4+FCxfa7s/MzCQ+Pp527drZ3tD9XUJCAvfcc4/dtu7du/Paa6/ZbftrfdDg4GAAWrVqZbctNzeXM2fO4OfnB0CDBg1sb+gAunbtitVqZdeuXZdUM7CoqIjnn3+ejz76iKNHj5Kfn09eXh5eXl5l2k9CQoJtcbMS3bt3Z+bMmRQVFWGxFM+I+euxm0wmQkJCSElJuej4RaRyqa9XX6++/vLUJPJq0mtNBODY/j0U5OcREpDPvkw4tPU4rS7weBGpupTblduV2y8/oSEmTqXC4V2n6PDHtqbdY0n4OY5d636i5513Y7Y4dlVLZdPgfCUpKWvjE6jFYEWqC5PJ5PAlic4UExODyWRi165ddtujoqIA8PT0BODZZ5+1m4nw1/sulaurq+3nkquDSttWcpmlI8xm81mXVhcUFFzwcS+99BKvvfYaM2fOpFWrVnh7ezNu3Djy8/Mdfu6y+OtxQvGxluU4RcS51Nc7Tn39n9TXV3+uLm5EeLmS7V6IV54Lx/ftIaJ9KPt+NDie4YXVasVsvvRBNhGpfMrtjlNu/5Nye/UW2S2KHUszSckLoKigEIurCxGt2+Lh40v26VMc3r6NiNZtnR1mqfRuo5JkpP9R1iZAg/MiUr5q167NNddcw+uvv05WVtY529WtW5eYmBjbDYpnC8THx5OWllbqY5o1a8aaNWvstq1Zs4bmzZtfctyHDh0iKSnJ9vv69esxm822ywiDgoJITk623V9UVMTvv/9utw83NzeKiorOiu/GG2/k9ttvp02bNkRFRbF79+4LPu7vznXsjRs3ts22EBGpLOrr1ddL+WvlF0FKQPHntKM7dxDVvwMmayE5rrU4uWW/k6MTkZpOuV25XcpP/d5tsBTmUuDiRdKP2wCwuLjSuEt3AHaurbprnWhwvpKUzJz3DVRZGxEpf2+88QaFhYV07NiRDz/8kISEBHbt2sXChQvZuXPnOd+E3HrrrYSEhDBo0CDWrFnD/v37+fTTT1m3bh0AEyZMYP78+cyZM4c9e/bwyiuv8Nlnn501c+NieHh4MHz4cLZs2cJPP/3Egw8+yJAhQ2yXQvbu3Zuvv/6ar7/+mp07d3L//fdz6tQpu31ERkby448/cvToUVJTUwFo1KgRK1asYO3atSQkJHDvvfdy/Pjxsx73yy+/cODAAVJTU0udIfHII4+wcuVKpk6dyu7du3nvvfd4/fXXy+XYRUQuhvp69fVSvlqHdOb4H4PzSbsTcA/0o0VoOl1b5eAdVjMWhBWRqk25XbldyoeLhztBLsVfViX+vMe2vWn3HgDs+WUthQ5cweEMGpyvJBklZW00c15EKkB0dDSbN2+mT58+TJw4kTZt2tCxY0dmzZrFo48+ytSpU0t9nJubG9999x1169ZlwIABtGrVimnTptneBA4aNIjXXnuNGTNm0KJFC9566y3mzZtHz549LznmmJgYbr75ZgYMGEDfvn1p3bo1b7zxhu3+UaNGMXz4cO68805iY2OJioqyW7wIii/xPHDgANHR0QQFBQHw73//m/bt29OvXz969uxpe9P6V48++igWi4XmzZsTFBTEoUOHzoqvffv2fPTRRyxZsoSWLVvy9NNP8+yzz9otIiQiUpnU16uvl/LVptF1f5k5vx3DaiV2ylDajxmIV90AJ0cnIpcD5Xbldik/4THeABw9UmjbFtasBVfcPJR//Ps/WFyqZnV3k/H3QlDCmTNn8Pf35/Tp07YFLy6FYRi89eBqigqs3D61K/5B5VMbTETKV25uLomJiTRs2BAPD32RVpGmTJnCF198QXx8vLNDqVTne42Vd+4Rezq/UkJ9feVRX6/XWFVnGAZXv9uavivr41pkZviM2dSpH1Fu+1fuqVg6vwLqcyubcrteZ1XZic17+eitQ5ishdw17QrcA8s/N1RE7tHM+UqQm1lAUYEVTOBTS2VtREREREREnM1kMtHKPYATtf4obbMrwckRiYiIyMWq3SYKz4J0DLML+5dtcnY4DtPgfCUoKWnj5eeGxVWnXEREREREpCpoFdDErrSNiIiIVE9ms5kQvxwADv6WdIHWVYdGiitBZlrxmz3VmxcRKTZlypTL7lJIEZHLjfp6qQ7aNIj9c3BeM+dFRM5LuV2qugatgwE4lu7m5Egcp8H5SpCRXjxz3jdQJW1ERERERESqihYxAznpn4sVg9Mpx8hMT3N2SCIiInKRogZ0AMNKlmtt0hMOOjsch2hwvhJk/lHWxidQM+dFRERERESqCi/PACJcLKT7FQCQtGuHkyMSERGRi+UVHEitohMA7Ptui5OjcYwG5ytBxh9lbXxV1kZERERERKRKae0VSkpA8YSqozs1OC8iIlKdhYaYADiy+7STI3GMBucrQWZ6ycx5lbURERERERGpSlrXbau68yIiIjVEZLcoAFLyAigqKHRyNBemwflKUFLWxldlbURERERERKqU1g37cvyPwfmUA/soyM11ckQiIiJyser3boOlMJcCFy+Sftzm7HAuSIPzFayo0ErWmXwAfFTWRkREREREpEpp2OAqzO6FZHoUYlitJO/d5eyQRERE5CK5eLgT5Fq8wHviz3ucHM2FaXC+gmWdygMDLC5mPH1dnR2OiIiIiIiI/IXZbKGV2fsvpW1Ud15ERKQ6qx/jA8DRIyprc9nL+KOkjU+AOyaTycnRiEhNNGLECEwmE/fdd99Z940ZMwaTycSIESPs2ppMJlxdXWnYsCGPPfYYubp8W0SkSlNfL1KxWvlHaVFYEalUyu0iFadh75YApJvqkJN6xsnRnJ8G5ytYZnrx7Asf1ZsXkQpUv359lixZQk5Ojm1bbm4uixcvpkGDBnZt+/fvT3JyMvv37+fVV1/lrbfeYvLkyZUdsoiIlJH6epGK06beFRwPLP7slrxnJ1ZrkZMjEpHLgXK7SMWo3SYKz4J0DLMLB5b/6uxwzsvF2QHUdBm2xWDdnRyJiJSVYRgU5uU55bld3Mt2tU379u3Zt28fn332GcOGDQPgs88+o0GDBjRs2NCurbu7OyEhIUDxm8E+ffqwYsUKXnzxxfI7ABGRakJ9vYgAtGp8PacS3iHfxQo5OZw8fIigiIYXfqCIVDnK7SJiNpsJ8cshMSeAg5uTaTbM2RGdmwbnK1hmSVkbzZwXqXYK8/L4v+H/cMpzP/jeJ7h6lK3fGDVqFPPmzbO9qXv33XcZOXIkcXFx53zM77//ztq1a4mIiLiUcEVEqi319SICEBAQRbgVVrU/wRNt/kmdBpHODklELpJyu4gANGgdTOIvcCzdzdmhnJfK2lSwjLTib2t9AzQ4LyIV6/bbb+fnn3/m4MGDHDx4kDVr1nD77bef1e6rr77Cx8cHDw8PWrVqRUpKChMmTHBCxCIiUlbq60UqTmv3OiTXyWVXZrzWCxORSqPcLlIxogZ0AMNKlmtt0hMOOjucc9LM+QqWmV4yc15lbUSqGxd3dx587xOnPXdZBQUFMXDgQObPn49hGAwcOJA6deqc1a5Xr17MmTOHrKwsXn31VVxcXBg8eHB5hC0iUu2orxeREq1rt+Dr46vZdnqfs0MRkUug3C4iAF7BgdQqOsEpl2D2fbeFjs2q5pUmGpyvYJm2mvOaOS9S3ZhMpjJfkuhso0aNYuzYsQDMnj271Dbe3t7ExMQAxZdMtmnThv/+97/cddddlRaniEhVob5eREq0btATjq9mqzUTw2rFZNaF5iLVkXK7iJQIDTFxKhUO7z5NR2cHcw56t1GB8nIKyc8tAsBHZW1EpBL079+f/Px8CgoK6Nev3wXbm81mnnzySf7973+Tk5NTCRGKiMilUl8vUjGaRF+Lm2Fw2mzm0OGfnR2OiFxGlNtFKkZktygATuQFUFRQ6ORoSqfB+QpkcTEx4IHW9BzWBFd3i7PDEZHLgMViISEhgR07dmCxONbv/POf/8RisZxzhoaIiFQt6utFKoaruzdPhvfnzeb3UjeopbPDEZHLiHK7SMWo37sNrcNOcu1t4VV2PRkNzlcgF1cLDVvXocVVYc4ORUQuI35+fvj5+Tnc3sXFhbFjxzJ9+nSysrIqMDIRESkv6utFKsbgPjPo3mksnl6Bzg5FRC4zyu0i5c/Fw52rJv2T+r3bYnapmhOnTYZhGM4Ooqo5c+YM/v7+nD59ukwdo4hUb7m5uSQmJtKwYUM8qlmNQqkezvcaU+6pWDq/UkJ9vVQ0vcakhHJPxdL5FVCfK5VDrzMpURG5RzPnRUREREREREREREQqmQbnRUREREREREREREQqmQbnRUREREREREREREQqmQbnRURExGb27NlERkbi4eFBly5d2LBhwznbbt++ncGDBxMZGYnJZGLmzJlntcnIyGDcuHFERETg6elJt27d2Lhxo12bzMxMxo4dS3h4OJ6enjRv3pw333zTrk1ubi5jxoyhdu3a+Pj4MHjwYI4fP14uxywiIiIiIiLiDBqcFxH5G62TLRXFarU6O4Tz+vDDDxk/fjyTJ0/mt99+o02bNvTr14+UlJRS22dnZxMVFcW0adMICQkptc3dd9/NihUrWLBgAdu2baNv37706dOHo0eP2tqMHz+eZcuWsXDhQhISEhg3bhxjx45l6dKltjYPP/wwX375JR9//DGrV68mKSmJm2++uXxPgFxW1NdLRanqfb2ISE2kvlcqkl5fUpFMhj6ZnEWrvotcnoqKitizZw9eXl4EBQVhMpmcHZLUEIZhkJ+fz4kTJygqKqJRo0aYzfbfj1eF3NOlSxc6derE66+/DhS/Ca1fvz7/+te/eOKJJ8772MjISMaNG8e4ceNs23JycvD19eV///sfAwcOtG3v0KED1157Lf/5z38AaNmyJUOHDmXSpEmltjl9+jRBQUEsXryYf/zjHwDs3LmTZs2asW7dOq644ooLHltVOL9SNaivl4riSF8vlxflnoql8ytQ/H51z549WCwWgoKCcHNzU26XcqPcLn9XEbnHpVz2IiJSA1gsFsLDwzly5AgHDhxwdjhSA3l5edGgQYMq+YYuPz+fTZs2MXHiRNs2s9lMnz59WLdu3UXts7CwkKKiIjw8POy2e3p68vPPP9t+79atG0uXLmXUqFGEhoYSFxfH7t27efXVVwHYtGkTBQUF9OnTx/aYpk2b0qBBg3MOzufl5ZGXl2f7/cyZMxd1DFLzqK+XilaV+3oRkZrGbDbTsGFDkpOTSUpKcnY4UkMpt0tF0uC8iMhf+Pj40KhRIwoKCpwditQwFosFFxeXKjuTJzU1laKiIoKDg+22BwcHs3Pnzovap6+vL127dmXq1Kk0a9aM4OBgPvjgA9atW0dMTIyt3axZs7jnnnsIDw/HxcUFs9nM22+/TY8ePQA4duwYbm5u1KpV66zYjh07Vupzv/DCCzzzzDMXFbfUfOrrpaJU9b5eRKQmcnNzo0GDBraJISLlSbldKpoG50VE/sZisWCxWJwdhkiNsGDBAkaNGkVYWBgWi4X27dtz6623smnTJlubWbNmsX79epYuXUpERAQ//vgjY8aMITQ01G62fFlMnDiR8ePH234/c+YM9evXv+TjkZpDfb2IiEjNYTKZcHV1xdXV1dmhiIiUiQbnRUREhDp16mCxWDh+/Ljd9uPHj59zsVdHREdHs3r1arKysjhz5gz16tVj6NChREVFAcV16Z988kk+//xzW1361q1bEx8fz4wZM+jTpw8hISHk5+dz6tQpu9nz54vN3d0dd3f3i45bREREREREpKKpWJKIiIjg5uZGhw4dWLlypW2b1Wpl5cqVdO3a9ZL37+3tTb169UhPT2f58uXceOONABQUFFBQUHBW/UaLxYLVagWKF4d1dXW1i23Xrl0cOnSoXGITERERERERcQbNnBcREREAxo8fz/Dhw+nYsSOdO3dm5syZZGVlMXLkSADuvPNOwsLCeOGFF4DiRWR37Nhh+/no0aPEx8fj4+Njqym/fPlyDMOgSZMm7N27lwkTJtC0aVPbPv38/IiNjWXChAl4enoSERHB6tWref/993nllVcA8Pf356677mL8+PEEBgbi5+fHv/71L7p27VrqYrAiIiIiIiIi1YEG50thGAZQXJ9WRESkMpTknJIc5AxDhw7lxIkTPP300xw7doy2bduybNky2yKxhw4dspvhnpSURLt27Wy/z5gxgxkzZhAbG0tcXBwAp0+fZuLEiRw5coTAwEAGDx7Mc889Z1cPdMmSJUycOJFhw4aRlpZGREQEzz33HPfdd5+tzauvvorZbGbw4MHk5eXRr18/3njjDYePTbldREQqW1XI7TWZcruIiFS2isjtJkPvFM5y5MgRLRonIiJOcfjwYcLDw50dRo2j3C4iIs6i3F4xlNtFRMRZyjO3a3C+FFarlaSkJHx9fTGZTJe0rzNnzlC/fn0OHz6Mn59fOUVYM+lclY3Ol+N0rspG58tx5XmuDMMgIyOD0NDQs+qvy6VTbncOnauy0flynM5V2eh8OU65vfpQbncOnSvH6VyVjc6X43Suyqaq53aVtSmF2Wwu95kNfn5++g/jIJ2rstH5cpzOVdnofDmuvM6Vv79/OUQjpVFudy6dq7LR+XKczlXZ6Hw5Trm96lNudy6dK8fpXJWNzpfjdK7Kpqrmdn19LyIiIiIiIiIiIiJSyTQ4LyIiIiIiIiIiIiJSyTQ4X8Hc3d2ZPHky7u7uzg6lytO5KhudL8fpXJWNzpfjdK4uT/q7O07nqmx0vhync1U2Ol+O07m6POnv7jidK8fpXJWNzpfjdK7KpqqfLy0IKyIiIiIiIiIiIiJSyTRzXkRERERERERERESkkmlwXkRERERERERERESkkmlwXkRERERERERERESkkmlwXkRERERERERERESkkmlwXkRERERERERERESkkmlwvhzMnj2byMhIPDw86NKlCxs2bDhv+48//pimTZvi4eFBq1at+OabbyopUucry7l6++23ueqqqwgICCAgIIA+ffpc8NzWNGV9bZVYsmQJJpOJQYMGVWyAVUhZz9WpU6cYM2YM9erVw93dncaNG+v/4nnMnDmTJk2a4OnpSf369Xn44YfJzc2tpGid58cff+T6668nNDQUk8nEF198ccHHxMXF0b59e9zd3YmJiWH+/PkVHqeUP+V2xym3l41yu+OU2x2nvO445fbLk/J62Si3O055vWyU2x2n3O6YGpHXDbkkS5YsMdzc3Ix3333X2L59uzF69GijVq1axvHjx0ttv2bNGsNisRjTp083duzYYfz73/82XF1djW3btlVy5JWvrOfqtttuM2bPnm1s3rzZSEhIMEaMGGH4+/sbR44cqeTInaOs56tEYmKiERYWZlx11VXGjTfeWDnBOllZz1VeXp7RsWNHY8CAAcbPP/9sJCYmGnFxcUZ8fHwlR+4cZT1fixYtMtzd3Y1FixYZiYmJxvLly4169eoZDz/8cCVHXvm++eYb46mnnjI+++wzAzA+//zz87bfv3+/4eXlZYwfP97YsWOHMWvWLMNisRjLli2rnIClXCi3O065vWyU2x2n3O445fWyUW6//Civl41yu+OU18tGud1xyu2Oqwl5XYPzl6hz587GmDFjbL8XFRUZoaGhxgsvvFBq+yFDhhgDBw6029alSxfj3nvvrdA4q4Kynqu/KywsNHx9fY333nuvokKsUi7mfBUWFhrdunUz3nnnHWP48OGXTaIv67maM2eOERUVZeTn51dWiFVKWc/XmDFjjN69e9ttGz9+vNG9e/cKjbOqcSTRP/bYY0aLFi3stg0dOtTo169fBUYm5U253XHK7WWj3O445XbHKa9fPOX2y4PyetkotztOeb1slNsdp9x+caprXldZm0uQn5/Ppk2b6NOnj22b2WymT58+rFu3rtTHrFu3zq49QL9+/c7Zvqa4mHP1d9nZ2RQUFBAYGFhRYVYZF3u+nn32WerWrctdd91VGWFWCRdzrpYuXUrXrl0ZM2YMwcHBtGzZkueff56ioqLKCttpLuZ8devWjU2bNtkuo9u/fz/ffPMNAwYMqJSYq5PLtY+vSZTbHafcXjbK7Y5Tbnec8nrFu1z7+JpCeb1slNsdp7xeNsrtjlNur1hVsY93cdoz1wCpqakUFRURHBxstz04OJidO3eW+phjx46V2v7YsWMVFmdVcDHn6u8ef/xxQkNDz/pPVBNdzPn6+eef+e9//0t8fHwlRFh1XMy52r9/Pz/88APDhg3jm2++Ye/evTzwwAMUFBQwefLkygjbaS7mfN12222kpqZy5ZVXYhgGhYWF3HfffTz55JOVEXK1cq4+/syZM+Tk5ODp6emkyMRRyu2OU24vG+V2xym3O055veIpt1dvyutlo9zuOOX1slFud5xye8WqinldM+elWpg2bRpLlizh888/x8PDw9nhVDkZGRnccccdvP3229SpU8fZ4VR5VquVunXrMnfuXDp06MDQoUN56qmnePPNN50dWpUUFxfH888/zxtvvMFvv/3GZ599xtdff83UqVOdHZqIVGPK7een3F42yu2OU14XkYqi3H5uyutlp9zuOOX26k0z5y9BnTp1sFgsHD9+3G778ePHCQkJKfUxISEhZWpfU1zMuSoxY8YMpk2bxvfff0/r1q0rMswqo6zna9++fRw4cIDrr7/ets1qtQLg4uLCrl27iI6OrtigneRiXlv16tXD1dUVi8Vi29asWTOOHTtGfn4+bm5uFRqzM13M+Zo0aRJ33HEHd999NwCtWrUiKyuLe+65h6eeegqzWd/zljhXH+/n56eZddWEcrvjlNvLRrndccrtjlNer3jK7dWb8nrZKLc7Tnm9bJTbHafcXrGqYl7XX+cSuLm50aFDB1auXGnbZrVaWblyJV27di31MV27drVrD7BixYpztq8pLuZcAUyfPp2pU6eybNkyOnbsWBmhVgllPV9NmzZl27ZtxMfH22433HADvXr1Ij4+nvr161dm+JXqYl5b3bt3Z+/evbY3QwC7d++mXr16NTbBl7iY85WdnX1WMi95g2QYRsUFWw1drn18TaLc7jjl9rJR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nToxdepUhg4dyrp163j99dd54403AGjcuDHDhg3jzjvv5OWXX6Zdu3acOHGClStX0rp1awYOHOjg2T7b5MmTufrqq4mOjuaWW26hsLCQb775hscff/ystuV1niMjI/nll184cOAAPj4+BAYGMmXKFDp06ECLFi3Iy8vjq6++OuebJhERqdqU25XbldtFRGoW5XblduV2qao0c16kHEybNo3Bgwdzxx130L59e/bu3cvy5csJCAiwazds2DC2bNnCTTfdZHdZl8lk4ptvvqFHjx6MHDmSxo0bc8stt3Dw4EGCg4MdjiMoKIj58+fz8ccf07x5c6ZNm3bOy7OmTZvGQw89RIcOHTh27Bhffvklbm5u59z3p59+SqdOnbj11ltp3rw5jz32mO1b6Pbt2/PRRx+xZMkSWrZsydNPP82zzz5rt9r8vHnzuPPOO3nkkUdo0qQJgwYNYuPGjTRo0MDh4ytNz549+fjjj1m6dClt27ald+/ebNiwodS25XWeH330USwWC82bN7ddgujm5sbEiRNp3bo1PXr0wGKxsGTJkks6NhERcR7lduV25XYRkZpFuV25XbldqiKTYRiGs4MQkcoTFxdHr169SE9Pt6vXJiIiItWTcruIiEjNotwucvnQzHkRERERERERERERkUqmwXkRERERERERERERkUqmsjYiIiIiIiIiIiIiIpVMM+dFRERERERERERERCqZBudFRERERERERERERCqZBudFRERERERERERERCqZBudFRERERERERERERCqZBudFRERERERERERERCqZBudFRERERERERERERCqZBudFRERERERERERERCqZBudFRERERERERERERCqZBudFylnPnj3p2bOn7fcDBw5gMpmYP3++02KqCAsWLKBp06a4urpSq1Yt2/aXXnqJqKgoLBYLbdu2dVp8l4u/v95ERORPysnKyZez+fPnYzKZOHDggLNDEREREZFz0OC81GhTpkzBZDKRmppa6v0tW7as0QObixcvZubMmeW+3507dzJixAiio6N5++23mTt3LgDfffcdjz32GN27d2fevHk8//zz5f7c33zzDVOmTHG4/RtvvOH0QZi1a9cyZcoUTp065dQ4REScSTlZObmqqQr5OTs7mylTphAXF+e0GERERETEeVycHYBITRcREUFOTg6urq6V/tyLFy/m999/Z9y4ceW637i4OKxWK6+99hoxMTG27T/88ANms5n//ve/uLm5letzlvjmm2+YPXu2w4MBb7zxBnXq1GHEiBEVEo8j1q5dyzPPPMOIESPsZjSKiEjlUk4uX2XNyVVNVcjP2dnZPPPMMwA1+sspERERESmdZs6LVDCTyYSHhwcWi+W87bKysiopokuXkpICcNYH2ZSUFDw9PStsEKCiVae/gYiIlJ1yslwsq9VKbm6us8MQERERkRpGg/MifxEXF4fJZOKjjz7iueeeIzw8HA8PD66++mr27t17Vvu5c+cSHR2Np6cnnTt35qeffjqrTWn1bUeMGIGPjw/79u1jwIAB+Pr6MmzYMKD4w9/MmTNp0aIFHh4eBAcHc++995Kenn7Wvr/99ltiY2Px9fXFz8+PTp06sXjxYqB49tXXX3/NwYMHMZlMmEwmIiMjL3gOFi5cSIcOHfD09CQwMJBbbrmFw4cP2+6PjIxk8uTJAAQFBWEymWylCubNm0dWVpbt+f56zBfab4lffvmFAQMGEBAQgLe3N61bt+a1116znbfZs2cD2J7DZDKd81giIyPZvn07q1evtrUtmZVWUod19erVPPDAA9StW5fw8HC7c3vVVVfh7e2Nr68vAwcOZPv27Xb737p1KyNGjCAqKgoPDw9CQkIYNWoUJ0+etLWZMmUKEyZMAKBhw4a2OP5a/9XRc+PI601EpKZQTq5ZObkk3uuuu46ff/6Zzp074+HhQVRUFO+///5Zbffv388///lPAgMD8fLy4oorruDrr7+2a1PW18hfXSg/m0wmxo4dy6JFi2jRogXu7u4sW7YMgKNHjzJq1CiCg4Nxd3enRYsWvPvuu3b7z8/P5+mnn6ZDhw74+/vj7e3NVVddxapVq2xtDhw4QFBQEADPPPOMLYa/Xomwc+dO/vGPfxAYGIiHhwcdO3Zk6dKlZx3P9u3b6d27N56enoSHh/Of//wHq9V63nMgIiIiIs6nsjYipZg2bRpms5lHH32U06dPM336dIYNG8Yvv/xia/Pf//6Xe++9l27dujFu3Dj279/PDTfcQGBgIPXr17/gcxQWFtKvXz+uvPJKZsyYgZeXFwD33nsv8+fPZ+TIkTz44IMkJiby+uuvs3nzZtasWWO7FH/+/PmMGjWKFi1aMHHiRGrVqsXmzZtZtmwZt912G0899RSnT5/myJEjvPrqqwD4+PicN6bnnnuOSZMmMWTIEO6++25OnDjBrFmz6NGjB5s3b6ZWrVrMnDmT999/n88//5w5c+bg4+ND69atiYmJYe7cuWzYsIF33nkHgG7dujm8X4AVK1Zw3XXXUa9ePR566CFCQkJISEjgq6++4qGHHuLee+8lKSmJFStWsGDBggue45kzZ/Kvf/0LHx8fnnrqKQCCg4Pt2jzwwAMEBQXx9NNP22ZKLliwgOHDh9OvXz9efPFFsrOzmTNnDldeeSWbN2+2DaisWLGC/fv3M3LkSEJCQti+fTtz585l+/btrF+/HpPJxM0338zu3bv54IMPePXVV6lTpw6A7cO4o+fmUl9vIiLVlXJyzcjJJfbu3cs//vEP7rrrLoYPH867777LiBEj6NChAy1atADg+PHjdOvWjezsbB588EFq167Ne++9xw033MAnn3zCTTfdZLdPR14jf3eh/AzFpYE++ugjxo4dS506dYiMjOT48eNcccUVtsH7oKAgvv32W+666y7OnDljK1t05swZ3nnnHW699VZGjx5NRkYG//3vf+nXrx8bNmygbdu2BAUFMWfOHO6//35uuukmbr75ZgBat24NFA+4d+/enbCwMJ544gm8vb356KOPGDRoEJ9++qntPBw7doxevXpRWFhoazd37lw8PT0d/ruIiIiIiJMYIjXY5MmTDcA4ceJEqfe3aNHCiI2Ntf2+atUqAzCaNWtm5OXl2ba/9tprBmBs27bNMAzDyM/PN+rWrWu0bdvWrt3cuXMNwG6fiYmJBmDMmzfPtm348OEGYDzxxBN28fz0008GYCxatMhu+7Jly+y2nzp1yvD19TW6dOli5OTk2LW1Wq22nwcOHGhERESc+wT9xYEDBwyLxWI899xzdtu3bdtmuLi42G0/13kdPny44e3tfVH7LSwsNBo2bGhEREQY6enp5zymMWPGGGXpuv7+Ny4xb948AzCuvPJKo7Cw0LY9IyPDqFWrljF69Gi79seOHTP8/f3ttmdnZ5+13w8++MAAjB9//NG27aWXXjIAIzEx0a6to+emLK83EZGqSjlZOTkiIuKsHJmSkmK4u7sbjzzyiG3buHHjDMD46aefbNsyMjKMhg0bGpGRkUZRUZFhGI6/Rs7lXPnZMAwDMMxms7F9+3a77XfddZdRr149IzU11W77LbfcYvj7+9veGxQWFtrFZBiGkZ6ebgQHBxujRo2ybTtx4oQBGJMnTz4rhquvvtpo1aqVkZuba9tmtVqNbt26GY0aNbJtKzlfv/zyi21bSkqK4e/vf87jExEREZGqQWVtREoxcuRIuxqtV111FVB8iTXAr7/+SkpKCvfdd59duxEjRuDv7+/w89x///12v3/88cf4+/tzzTXXkJqaart16NABHx8f26XQK1asICMjgyeeeAIPDw+7fVzokvJz+eyzz7BarQwZMsTuuUNCQmjUqJHdZdgVsd/NmzeTmJjIuHHjzqqbe7HH5IjRo0fb1R5esWIFp06d4tZbb7WL12Kx0KVLF7vz8NcZabm5uaSmpnLFFVcA8Ntvv13wuR09N+X1ehMRqY6Uk2tWTm7evLntbwjFM9WbNGli+3tC8UKznTt35sorr7Rt8/Hx4Z577uHAgQPs2LHDbp8Xeo1crNjYWJo3b2773TAMPv30U66//noMw7A7h/369eP06dO2/G+xWGwxWa1W0tLSKCwspGPHjg69R0hLS+OHH35gyJAhZGRk2J7n5MmT9OvXjz179nD06FGg+HxdccUVdO7c2fb4oKAgW3kmEREREam6VNZGLnulfchs0KCB3e8BAQEAthqzBw8eBKBRo0Z27VxdXYmKinLoeV1cXOxqnAPs2bOH06dPU7du3VIfU7Lo2759+wBo2bKlQ8/liD179mAYxlnHVKLk0v2K2m9FHJMjGjZsaPf7nj17AOjdu3ep7f38/Gw/p6Wl8cwzz7BkyRLb36bE6dOnL/jcjp6b8ni9iYhUB8rJfz53Tc3Jf/97QvHf9K91/A8ePEiXLl3OatesWTPb/X+N7UKvkYv19/cIJ06c4NSpU8ydO5e5c+eW+pi/vh947733ePnll9m5cycFBQXn3G9p9u7di2EYTJo0iUmTJp3zucLCws55vpo0aXLB5xERERER59LgvNRoJTPYcnJySr0/Ozv7rFlugN1M6r8yDKPcYnN3d8dstr94xWq1UrduXRYtWlTqY/5aB7W8Wa1WTCYT3377banHf6HauJW93/Ly93qsJYunLViwgJCQkLPau7j82W0OGTKEtWvXMmHCBNq2bYuPjw9Wq5X+/fs7tAhbVT83IiLlSTnZcTU5J1fE37OiXiPneo9w++23M3z48FIfU1IvfuHChYwYMYJBgwYxYcIE6tati8Vi4YUXXrB9+XE+Jc/16KOP0q9fv1LbxMTEOHwsIiIiIlI1aXBearSIiAgAdu3addaCcNnZ2Rw+fJi+ffte9H737NljN8O6oKCAxMRE2rRpc1HxRkdH8/3339O9e/fzLuIVHR0NwO+//37eD2ZlufQ8OjoawzBo2LAhjRs3djzoctrvX4+pT58+52xX1svpy9q+JI66deueN4709HRWrlzJM888w9NPP23bXjLz3pEYHD03FfV6ExGpTMrJysmOioiIYNeuXWdt37lzp+3+8lDW+IOCgvD19aWoqOi85wXgk08+ISoqis8++8zueSZPnuxQDCVXfbi6ul7wuSIiIkp9/1HaORQRERGRqkU156VGu/rqq3Fzc2POnDlnzWSeO3cuhYWFXHvttWXeb8eOHQkKCuLNN98kPz/ftn3+/PmcOnXqouMdMmQIRUVFTJ069az7CgsLbfvu27cvvr6+vPDCC+Tm5tq1++ssMW9vb4fKqwDcfPPNWCwWnnnmmbNmmhmGwcmTJ8t4NGXbb/v27WnYsCEzZ8486xz+/ZgAh8+zt7d3mf4m/fr1w8/Pj+eff97uEvQSJ06cAP6cpff3Y5o5c2apMZQWs6PnpqJebyIilUk5WTnZUQMGDGDDhg2sW7fOti0rK4u5c+cSGRlpVwf+UpQ1fovFwuDBg/n000/5/fffz7q/5D1CSVuwP1+//PKL3TEBeHl5lRpD3bp16dmzJ2+99RbJycnnfa4BAwawfv16NmzYYHf/ua76EBEREZGqQzPnpUarW7cuTz/9NP/+97/p0aMHN9xwA15eXqxdu5YPPviAvn37cv3115d5v66urvznP//h3nvvpXfv3gwdOpTExETmzZt3STXAY2Njuffee3nhhReIj4+nb9++uLq6smfPHj7++GNee+01/vGPf+Dn58err77K3XffTadOnbjtttsICAhgy5YtZGdn89577wHQoUMHPvzwQ8aPH0+nTp3w8fE55/FGR0fzn//8h4kTJ3LgwAEGDRqEr68viYmJfP7559xzzz08+uijZT4mR/drNpuZM2cO119/PW3btmXkyJHUq1ePnTt3sn37dpYvX247JoAHH3yQfv36YbFYuOWWW875/B06dGDOnDn85z//ISYmhrp1656znjwU15SfM2cOd9xxB+3bt+eWW24hKCiIQ4cO8fXXX9O9e3def/11/Pz86NGjB9OnT6egoICwsDC+++47EhMTS40B4KmnnuKWW27B1dWV66+/3uFzU1GvNxGRyqScrJzsqCeeeIIPPviAa6+9lgcffJDAwEDee+89EhMT+fTTT88qQXSxzpWfSwbtSzNt2jRWrVpFly5dGD16NM2bNyctLY3ffvuN77//nrS0NACuu+46PvvsM2666SYGDhxIYmIib775Js2bNyczM9O2P09PT5o3b86HH35I48aNCQwMpGXLlrRs2ZLZs2dz5ZVX0qpVK0aPHk1UVBTHjx9n3bp1HDlyhC1btgDw2GOPsWDBAvr3789DDz2Et7c3c+fOJSIigq1bt5bLuRIRERGRCmKIXAYWLlxoXHHFFYa3t7fh7u5uNG3a1HjmmWeM3Nxcu3arVq0yAOPjjz+2256YmGgAxrx58+y2v/HGG0bDhg0Nd3d3o2PHjsaPP/5oxMbGGrGxsed97PDhww1vb+9zxjt37lyjQ4cOhqenp+Hr62u0atXKeOyxx4ykpCS7dkuXLjW6detmeHp6Gn5+fkbnzp2NDz74wHZ/Zmamcdtttxm1atUyACMiIuKC5+rTTz81rrzySsPb29vw9vY2mjZtaowZM8bYtWuXrc3kyZMNwDhx4oTdY893XI7s1zAM4+effzauueYaw9fX1/D29jZat25tzJo1y3Z/YWGh8a9//csICgoyTCaTcaFu7NixY8bAgQMNX19fA7D9bebNm2cAxsaNG0t93KpVq4x+/foZ/v7+hoeHhxEdHW2MGDHC+PXXX21tjhw5Ytx0001GrVq1DH9/f+Of//ynkZSUZADG5MmT7fY3depUIywszDCbzQZgJCYmlvncOPJ6ExGp6pSTL9+cHBERYQwcOPCs7aXlsn379hn/+Mc/jFq1av0/e/cdHld1rQ38PedMb5JGXbJsuffesE0vNpDQQyDUmMBN+OxQHBIgCXAJLYRyCQmEQCjpgdA7GINtcMe9SW6yZKt3afrMOef7YzQjyVVlmmbe3/PokXQ0ZWkQ3rPXXntt1WAwqLNmzVI//PDDbrfp7d/IsRxvfAagLlq06Jj3qa2tVRctWqQWFRWpWq1WzcvLU8855xz1xRdfDN9GURT10UcfVYcMGaLq9Xp16tSp6ocffqjeeOONR/23X716tTp9+nRVp9Md9R5i//796g033KDm5eWpWq1WLSwsVL/73e+qb775ZrfH2LZtm3rGGWeoBoNBLSwsVB966CH15ZdfPuo9BxERERElFkFVI3iaFhERERERERERERERnRR7zhMRERERERERERERxRiT80REREREREREREREMcbkPBERERERERERERFRjDE5T0RERERERER9tnLlSlx00UUoKCiAIAh49913T3qf5cuXY9q0adDr9RgxYgRee+21qMdJRESUaJicJyIiIiIiIqI+czqdmDx5Mp577rke3b6srAzf+c53cNZZZ2HLli244447cPPNN+Ozzz6LcqRERESJRVBVVY13EEREREREREQ08AmCgHfeeQeXXnrpcW9z991346OPPsKOHTvC166++mq0tLTg008/jUGUREREiUET7wASkaIoqKqqgtVqhSAI8Q6HiIhSgKqqaG9vR0FBAUSRG9sijWM7ERHFGsf241uzZg3OPffcbtcWLFiAO+6447j38Xq98Hq94e8VRUFTUxMyMzM5thMRUUxEY2xncv4YqqqqUFRUFO8wiIgoBR06dAiDBg2KdxhJh2M7ERHFC8f2o9XU1CA3N7fbtdzcXLS1tcHtdsNoNB51n8ceewwPPvhgrEIkIiI6rkiO7UzOH4PVagUQfKFtNlucoyEiolTQ1taGoqKi8BhEkcWxnYiIYo1je2Tde++9WLJkSfj71tZWDB48mGM7ERHFTDTGdibnjyG0Jc5ms3GQJyKimOK27Ojg2E5ERPHCsf1oeXl5qK2t7XattrYWNpvtmFXzAKDX66HX64+6zrGdiIhiLZJjOxvfEREREREREVHMzJkzB8uWLet2benSpZgzZ06cIiIiIooPJueJiIiIiIiIqM8cDge2bNmCLVu2AADKysqwZcsWVFRUAAi2pLnhhhvCt//JT36CAwcO4Be/+AVKSkrw/PPP44033sCdd94Zj/CJiIjihsl5IiIiIiIiIuqzb7/9FlOnTsXUqVMBAEuWLMHUqQLGO74AAPh4SURBVFNx//33AwCqq6vDiXoAGDp0KD766CMsXboUkydPxlNPPYW//OUvWLBgQVziJyIiihf2nCciIiIiIiKiPjvzzDOhqupxf/7aa68d8z6bN2+OYlRERESJj5XzREREREREREREREQxxuQ8EREREREREREREVGMMTlPRERERERERERERBRjTM4TEREREREREREREcUYk/NERERERERERERERDHG5DwRERERERERERER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p/H5558bn9doNEhLS0Pv3r2NF+9/lZ6ejieffNJk28CBA7FixQqTbT179jT+bKgt3qNHD5NtlZWVKCkpgY+PDwCgTZs2xot3AOjfvz/0ej1OnTrVqPqwOp0Ob731Fr788ktcunQJWq0WVVVVUKvVFh0nPT0dDz74oMm2gQMHYvny5dDpdJDLa0c/3vzeBUFAcHAw8vPzGxw/OQ+uJUPkfJjbmduZ24mIiMiRsHPeTjSFtZ3zXn68gCdyFoIgmD39XEodOnSAIAg4deqUyfZ27doBADw8PAAA8+fPNxl1dvNzjeXufqNcl2GafX3bDFPqzSGTySCKosm26urqO+737rvvYsWKFVi+fDl69OgBT09PPPfcc9BqtWa/tiVufp9A7Xu15H2S89IYb7wztxM5C+Z28zG338DcTkRERLbS+OEbZBbN9bq0vIAnImtr3rw5hg8fjlWrVqGsrOyW7QIDA9GhQwfjA6gdGZaWloZr167Vu0/Xrl2xd+9ek2179+5FREREo+POzs7G5cuXjb//9ttvkMlkxinjAQEByMnJMT6v0+lw/Phxk2MoFArodLo68T344IP429/+hl69eqFdu3Y4ffr0Hff7q1u9906dOhlH1lHTZpgV58WyNkRkZcztzO1ERETUNLBz3k5KC3kBT0S28/7776OmpgYxMTHYvHkz0tPTcerUKXz++ec4efLkLS84H330UQQHByMhIQF79+7F+fPn8c0332D//v0AgBdffBHr16/H6tWrcebMGSxduhRbtmypM0qvIVQqFSZNmoSjR4/il19+wbPPPotHHnnEOO192LBh+O677/Ddd9/h5MmTmDZtGoqKikyOER4ejp9//hmXLl1CQUEBAKBjx47YtWsX9u3bh/T0dDz11FPIy8urs9+BAweQmZmJgoKCekfDPf/880hOTsaCBQtw+vRp/Pvf/8aqVaus8t7JNbCsDRHZEnM7czsRERG5PnbO24lh6jsv4InIFtq3b48jR44gLi4Os2bNQq9evRATE4OVK1fihRdewIIFC+rdT6FQ4Mcff0RgYCBGjhyJHj16YNGiRcYL/oSEBKxYsQKLFy9Gt27d8MEHH+CTTz7BkCFDGh1zhw4d8H//938YOXIk7r33XvTs2RPvv/++8fnHH38ckyZNwsSJExEbG4t27dqZLFQH1E7nz8zMRPv27REQEAAAmD17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t4uBgYHiP//5T6negl1Zer7mzZsnent7i1988YV4/vx58ccffxTbt28vPvLII1K9BbspLS0Vjxw5Ih45ckQEIC5dulQ8cuSImJWVJYqiKL7yyiviY489Zmx//vx5Ua1Wiy+++KKYnp4uvvfee6JcLhd37twp1VugBmBuNx9zu2WY283H3G4+5nXLMLc7D+Zj62G+th7mcuthrrcefhewDqm+I7Bz3gpWrlwptmnTRlQoFGLfvn3F3377zfhcbGysOGnSJJP2X375pdipUydRoVCI3bp1E7/77js7RywdS85VWFiYCKDOY968efYPXCKW/m3drKklfUvP1b59+8R+/fqJSqVSbNeunfjmm2+KNTU1do5aOpacr+rqavH1118X27dvL6pUKjE0NFR85plnxMLCQvsHbme7d++u93PIcH4mTZokxsbG1tknMjJSVCgUYrt27cRPPvnE7nFT4zG3m4+53TLM7eZjbjcf87r5mNudC/Ox9TBfWw9zufUw11sPvws0nlTfEQRR5HwFIiIiIiIiIiIiIiJ7Ys15IiIiIiIiIiIiIiI7Y+c8EREREREREREREZGdsXOeiIiIiIiIiIiIiMjO2DlPRERERERERERERGRn7JwnIiIiIiIiIiIiIrIzds4TEREREREREREREdkZO+eJiIiIiIiIiIiIiOyMnfNERERERERERERERHbGznkiJzdkyBA899xzUodhFVu3bkWHDh0gl8uN7+mv29avX49mzZqZfczw8HAsX77cJvESERHZAnP77TG3ExEREZGrcJM6ACIig6eeegqJiYl49tln4e3tXe82Nzc3jBw50uxjHjp0CJ6enlaNc8iQIYiMjGTHABER0R0wtxMRERER3Ro754mclFarhUKhkDoMq9FoNMjPz0d8fDxCQkJuuQ0APDw8zD5uQECA1WMlIiKyBeZ28zC3ExEREZGrYFkbIiuoqqrCs88+i8DAQKhUKgwaNAiHDh0CAOj1erRu3RqrV6822efIkSOQyWTIysoCABQVFeGJJ55AQEAAfHx8MGzYMBw9etTY/vXXX0dkZCQ++ugjtG3bFiqVqt5YPvvsM8TExMDb2xvBwcEYP3488vPzjc+npKRAEAR899136NmzJ1QqFe666y4cP378tu+xqKgITz31FIKCgqBSqdC9e3ds377d+Pw333yDbt26QalUIjw8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4MFITExEp06dMG7cOGRlZSEoKMjsOAICArB+/Xp89dVXiIiIwKJFi2459XrRokWYOXMmoqOjkZubi//+979QKBS3PPY333yDPn364NFHH0VERAReeukl4wizqKgofPnll9i0aRO6d++OuXPnYv78+Zg8ebJx/08++QQTJ07E888/j86dOyMhIQGHDh1CmzZtzH5/9RkyZAi++uorbNu2DZGRkRg2bBgOHjxYb1trnecXXngBcrkcERERxvICCoUCs2bNQs+ePTF48GDI5XJs2rSpUe+NiIikw9zO3M7cTkRERES2JoiiKEodBBHZT0pKCoYOHYrCwkKTWqxERETknJjbiYiIiIicE0fOExERERERERERERHZGTvniYiIiIiIiIiIiIjsjGVtiIiIiIiIiIiIiIjsjCPniYiIiIiIiIiIiIjsjJ3zRERERERERERERER2xs55IiIiIiIiIiIiIiI7Y+c8EREREREREREREZGdsXOeiIiIiIiIiIiIiMjO2DlPRERERERERERERGRn7JwnIiIiIiIiIiIiIrIzds4TEREREREREREREdnZ/wdBGqV3ldDsfwAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "fig, axs = plt.subplots(2, 3, figsize=(15, 9), layout='constrained')\n", - "\n", - "\n", - "axs[0][0].plot(list_overlap_coefficients, total_effect_df['Truth'], label='Truth')\n", - "axs[0][0].plot(list_overlap_coefficients, total_effect_df['IPW'], label='IPW')\n", - "axs[0][0].plot(list_overlap_coefficients, total_effect_df['SNIPW'], label='SNIPW')\n", - "axs[0][0].plot(list_overlap_coefficients, total_effect_df['linear'], label='linear')\n", - "axs[0][0].plot(list_overlap_coefficients, total_effect_df['G-computation'], label='G-computation')\n", - "axs[0][0].plot(list_overlap_coefficients, total_effect_df['MR'], label='MR')\n", - "axs[0][0].set_xlabel('overlap coefficients')\n", - "axs[0][0].set_ylabel('Total average effect')\n", - "axs[0][0].legend()\n", - "axs[0][0].set_title('Total average effect')\n", - "\n", - "axs[0][1].plot(list_overlap_coefficients, direct_effect_treated_df['Truth'], label='Truth')\n", - "axs[0][1].plot(list_overlap_coefficients, direct_effect_treated_df['IPW'], label='IPW')\n", - "axs[0][1].plot(list_overlap_coefficients, direct_effect_treated_df['SNIPW'], label='SNIPW')\n", - "axs[0][1].plot(list_overlap_coefficients, direct_effect_treated_df['linear'], label='linear')\n", - "axs[0][1].plot(list_overlap_coefficients, direct_effect_treated_df['G-computation'], label='G-computation')\n", - "axs[0][1].plot(list_overlap_coefficients, direct_effect_treated_df['MR'], label='MR')\n", - "axs[0][1].set_xlabel('overlap coefficients')\n", - "axs[0][1].set_ylabel('Direct effect treated')\n", - "axs[0][1].legend()\n", - "axs[0][1].set_title('Direct effect treated')\n", - "\n", - "axs[0][2].plot(list_overlap_coefficients, direct_effect_non_treated_df['Truth'], label='Truth')\n", - "axs[0][2].plot(list_overlap_coefficients, direct_effect_non_treated_df['IPW'], label='IPW')\n", - "axs[0][2].plot(list_overlap_coefficients, direct_effect_non_treated_df['SNIPW'], label='SNIPW')\n", - "axs[0][2].plot(list_overlap_coefficients, direct_effect_non_treated_df['linear'], label='linear')\n", - "axs[0][2].plot(list_overlap_coefficients, direct_effect_non_treated_df['G-computation'], label='G-computation')\n", - "axs[0][2].plot(list_overlap_coefficients, direct_effect_non_treated_df['MR'], label='MR')\n", - "axs[0][2].set_xlabel('overlap coefficients')\n", - "axs[0][2].set_ylabel('Direct effect non treated')\n", - "axs[0][2].legend()\n", - "axs[0][2].set_title('Direct effect non treated')\n", - "\n", - "\n", - "axs[1][0].plot(list_overlap_coefficients, indirect_effect_treated_df['Truth'], label='Truth')\n", - "axs[1][0].plot(list_overlap_coefficients, indirect_effect_treated_df['IPW'], label='IPW')\n", - "axs[1][0].plot(list_overlap_coefficients, indirect_effect_treated_df['SNIPW'], label='SNIPW')\n", - "axs[1][0].plot(list_overlap_coefficients, indirect_effect_treated_df['linear'], label='linear')\n", - "axs[1][0].plot(list_overlap_coefficients, indirect_effect_treated_df['G-computation'], label='G-computation')\n", - "axs[1][0].plot(list_overlap_coefficients, indirect_effect_treated_df['MR'], label='MR')\n", - "axs[1][0].set_xlabel('overlap coefficients')\n", - "axs[1][0].set_ylabel('Undirect effect treated')\n", - "axs[1][0].legend()\n", - "axs[1][0].set_title('Undirect effect treated')\n", - "\n", - "axs[1][1].plot(list_overlap_coefficients, indirect_effect_non_treated_df['Truth'], label='Truth')\n", - "axs[1][1].plot(list_overlap_coefficients, indirect_effect_non_treated_df['IPW'], label='IPW')\n", - "axs[1][1].plot(list_overlap_coefficients, indirect_effect_non_treated_df['SNIPW'], label='SNIPW')\n", - "axs[1][1].plot(list_overlap_coefficients, indirect_effect_non_treated_df['linear'], label='linear')\n", - "axs[1][1].plot(list_overlap_coefficients, indirect_effect_non_treated_df['G-computation'], label='G-computation')\n", - "axs[1][1].plot(list_overlap_coefficients, indirect_effect_non_treated_df['MR'], label='MR')\n", - "axs[1][1].set_xlabel('overlap coefficients')\n", - "axs[1][1].set_ylabel('Undirect effect non treated')\n", - "axs[1][1].legend()\n", - "axs[1][1].set_title('Undirect effect non treated')" - ] - }, - { - "cell_type": "code", - "execution_count": 265, - "id": "c490ff5b-d8c7-449a-b03f-1cb4d27bf386", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
TruthIPWSNIPWlinearG-computationMR
causal_effects
total effect $\\tau$0.3615310.3510760.3510720.3507340.3001380.350750
direct effect treated $\\theta(1)$0.2000000.1960000.1959050.1958930.1958930.195904
direct effect non treated $\\theta(0)$0.2000000.1959630.1958300.1958930.1958930.195913
indirect effect treated $\\delta(1)$0.1615310.1551130.1552420.1548410.1042460.154838
indirect effect untreated $\\delta(0)$0.1615310.1550760.1551660.1548410.1042460.154846
\n", - "
" - ], - "text/plain": [ - " Truth IPW SNIPW linear \\\n", - "causal_effects \n", - "total effect $\\tau$ 0.361531 0.351076 0.351072 0.350734 \n", - "direct effect treated $\\theta(1)$ 0.200000 0.196000 0.195905 0.195893 \n", - "direct effect non treated $\\theta(0)$ 0.200000 0.195963 0.195830 0.195893 \n", - "indirect effect treated $\\delta(1)$ 0.161531 0.155113 0.155242 0.154841 \n", - "indirect effect untreated $\\delta(0)$ 0.161531 0.155076 0.155166 0.154841 \n", - "\n", - " G-computation MR \n", - "causal_effects \n", - "total effect $\\tau$ 0.300138 0.350750 \n", - "direct effect treated $\\theta(1)$ 0.195893 0.195904 \n", - "direct effect non treated $\\theta(0)$ 0.195893 0.195913 \n", - "indirect effect treated $\\delta(1)$ 0.104246 0.154838 \n", - "indirect effect untreated $\\delta(0)$ 0.104246 0.154846 " - ] - }, - "execution_count": 265, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "direct_effect_treated_dic ={\n", - " 'Truth': [],\n", - " 'IPW': [],\n", - " 'SNIPW': [],\n", - " 'linear': [],\n", - " 'G-computation': [],\n", - " 'MR': []\n", - "}\n", - "\n", - "direct_effect_df = pd.DataFrame(direct_effect_treated_dic)\n", - "results_df" - ] - }, - { - "cell_type": "code", - "execution_count": 284, - "id": "d931d30d-f042-451f-8fcd-28ce76e05ef8", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([0.2 , 0.19599953, 0.1959052 , 0.19589261, 0.19589261,\n", - " 0.19590424])" - ] - }, - "execution_count": 284, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "results_df.iloc[1].values" - ] - }, - { - "cell_type": "code", - "execution_count": 285, - "id": "7b01bd07-0957-45b7-99f6-96e44ca1b08f", - "metadata": {}, - "outputs": [], - "source": [ - "direct_effect_df.loc[len(direct_effect_df.index)] = results_df.iloc[1].values" - ] - }, - { - "cell_type": "code", - "execution_count": 286, - "id": "a9af9306-23d8-475a-a569-5e7674d34b7d", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
TruthIPWSNIPWlinearG-computationMR
00.20.1960.1959050.1958930.1958930.195904
\n", - "
" - ], - "text/plain": [ - " Truth IPW SNIPW linear G-computation MR\n", - "0 0.2 0.196 0.195905 0.195893 0.195893 0.195904" - ] - }, - "execution_count": 286, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "direct_effect_df" - ] - }, - { - "cell_type": "code", - "execution_count": 280, - "id": "04456141-479d-454e-a03e-e3103e7d5acc", - "metadata": {}, - "outputs": [ - { - "ename": "IndexError", - "evalue": "iloc cannot enlarge its target object", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[280], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mdirect_effect_df\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43miloc\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m]\u001b[49m \u001b[38;5;241m=\u001b[39m results_df\u001b[38;5;241m.\u001b[39miloc[\u001b[38;5;241m1\u001b[39m]\n", - "File \u001b[0;32m~/miniconda3/envs/mind/lib/python3.9/site-packages/pandas/core/indexing.py:882\u001b[0m, in \u001b[0;36m_LocationIndexer.__setitem__\u001b[0;34m(self, key, value)\u001b[0m\n\u001b[1;32m 880\u001b[0m key \u001b[38;5;241m=\u001b[39m com\u001b[38;5;241m.\u001b[39mapply_if_callable(key, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mobj)\n\u001b[1;32m 881\u001b[0m indexer \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_get_setitem_indexer(key)\n\u001b[0;32m--> 882\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_has_valid_setitem_indexer\u001b[49m\u001b[43m(\u001b[49m\u001b[43mkey\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 884\u001b[0m iloc \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mname \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124miloc\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mobj\u001b[38;5;241m.\u001b[39miloc\n\u001b[1;32m 885\u001b[0m iloc\u001b[38;5;241m.\u001b[39m_setitem_with_indexer(indexer, value, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mname)\n", - "File \u001b[0;32m~/miniconda3/envs/mind/lib/python3.9/site-packages/pandas/core/indexing.py:1608\u001b[0m, in \u001b[0;36m_iLocIndexer._has_valid_setitem_indexer\u001b[0;34m(self, indexer)\u001b[0m\n\u001b[1;32m 1606\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m is_integer(i):\n\u001b[1;32m 1607\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m i \u001b[38;5;241m>\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;28mlen\u001b[39m(ax):\n\u001b[0;32m-> 1608\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mIndexError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124miloc cannot enlarge its target object\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 1609\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(i, \u001b[38;5;28mdict\u001b[39m):\n\u001b[1;32m 1610\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mIndexError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124miloc cannot enlarge its target object\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", - "\u001b[0;31mIndexError\u001b[0m: iloc cannot enlarge its target object" - ] - } - ], - "source": [ - "direct_effect_df.iloc[0] = results_df.iloc[1]" - ] - }, - { - "cell_type": "code", - "execution_count": 317, - "id": "49e3480f", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", - " y = column_or_1d(y, warn=True)\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", - " y = column_or_1d(y, warn=True)\n" - ] - } - ], - "source": [ - "n_samples = 10000\n", - "causal_data, causal_effects = generate_causal_data(dataset_name, n_samples, False)\n", - "x, t, m, y = causal_data\n", - "classifier_x, classifier_xm = get_classifier(params['regularization'], params['forest'], params['calibration'])\n", - "p_x, p_xm = estimate_probabilities(t, m, x, params['crossfit'], classifier_x, classifier_xm)" - ] - }, - { - "cell_type": "code", - "execution_count": 318, - "id": "024d4e12", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[1.2988589 ],\n", - " [1.35519484],\n", - " [0.43082362],\n", - " ...,\n", - " [1.50852977],\n", - " [0.61602638],\n", - " [0.39563278]])" - ] - }, - "execution_count": 318, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m" - ] - }, - { - "cell_type": "code", - "execution_count": 319, - "id": "d4a0427a-37cd-4194-91da-d6348ed1bc62", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", - " y = column_or_1d(y, warn=True)\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/utils/validation.py:1183: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", - " y = column_or_1d(y, warn=True)\n" - ] - } - ], - "source": [ - "x_clf = LogisticRegressionCV(Cs=cs, cv=CV_FOLDS)\n", - "xm_clf = LogisticRegressionCV(Cs=cs, cv=CV_FOLDS)\n", - "# x_clf = RandomForestClassifier(n_estimators=100, min_samples_leaf=10)\n", - "# xm_clf = RandomForestClassifier(n_estimators=100, min_samples_leaf=10)\n", - "# calib_method = 'sigmoid'\n", - "# x_clf = CalibratedClassifierCV(x_clf, method=calib_method)\n", - "# xm_clf = CalibratedClassifierCV(xm_clf, method=calib_method)\n", - " \n", - "n = len(t)\n", - "train_test_list = [[np.arange(n), np.arange(n)]]\n", - "\n", - "p_x, p_xm = [np.zeros(n) for h in range(2)]\n", - "# compute propensity scores\n", - "if len(x.shape) == 1:\n", - " x = x.reshape(-1, 1)\n", - "if len(m.shape) == 1:\n", - " m = m.reshape(-1, 1)\n", - "\n", - "train_test_list = get_train_test_lists(crossfit, n)\n", - "\n", - "for train_index, test_index in train_test_list:\n", - " x_clf = x_clf.fit(x[train_index, :], t[train_index])\n", - " xm_clf = xm_clf.fit(np.hstack((x, m))[train_index, :], t[train_index])\n", - " p_x[test_index] = x_clf.predict_proba(x[test_index, :])[:, 1]\n", - " p_xm[test_index] = xm_clf.predict_proba(\n", - " np.hstack((x, m))[test_index, :])[:, 1]\n", - " " - ] - }, - { - "cell_type": "code", - "execution_count": 231, - "id": "a77836ed-b11f-4a99-b670-d50a13fc55c6", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([0.55134251, 0.54009824, 0.44951737, ..., 0.47679434, 0.54150298,\n", - " 0.44453564])" - ] - }, - "execution_count": 231, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "p_xm" - ] - }, - { - "cell_type": "code", - "execution_count": 232, - "id": "af950b01-7d74-4f3d-9eb0-892da36255db", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(array([[-0.14573364, 1.14127987],\n", - " [ 0.1143222 , 0.41886898],\n", - " [ 0.41700926, 0.1057243 ],\n", - " ...,\n", - " [-0.97086447, -1.2636025 ],\n", - " [-0.1728669 , 0.58630943],\n", - " [ 0.27764468, 0.1388676 ]]),\n", - " array([[1.29800425],\n", - " [1.2368184 ],\n", - " [0.55538922],\n", - " ...,\n", - " [0.83712826],\n", - " [1.24495826],\n", - " [0.51778423]]))" - ] - }, - "execution_count": 232, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x, m" - ] - }, - { - "cell_type": "code", - "execution_count": 219, - "id": "cd147283-d205-46d6-a9d8-a2b09d30dd27", - "metadata": {}, - "outputs": [], - "source": [ - "# effects_SNIPW = SNIPW(y, t, m, x, params['trim'], p_x, p_xm, params['clip'])\n", - "# effects_IPW = IPW(y, t, m, x, params['trim'], p_x, p_xm, params['clip'])\n", - "# effects_linear = ols_mediation(y, t, m, x)\n", - "# data = {'causal_effects': list_causal_effects}\n", - "# data['Truth'] = causal_effects\n", - "# data['IPW'] = effects_IPW\n", - "# data['SNIPW'] = effects_SNIPW\n", - "# data['linear'] = effects_linear\n", - "# # data['G-computation'] = effects_g_computation\n", - "# # data['MR'] = effects_MR\n", - "# df = pd.DataFrame(data)\n", - "# df = df[:-1]\n", - "# df.set_index('causal_effects', inplace=True)\n", - "# df" - ] - }, - { - "cell_type": "code", - "execution_count": 220, - "id": "af23121c-d339-4c03-832d-134f132facb0", - "metadata": {}, - "outputs": [], - "source": [ - "# effects_SNIPW" - ] - }, - { - "cell_type": "code", - "execution_count": 320, - "id": "288ce26d", - "metadata": {}, - "outputs": [], - "source": [ - "# p_x = np.ones_like(p_x)*0.5\n", - "# p_xm = np.ones_like(p_x)*0.5\n", - "\n", - "t = t.squeeze()\n", - "m = m.squeeze()\n", - "\n", - "trim, clip = params['trim'], params['clip']\n", - "ind = ((p_xm > trim) & (p_xm < (1 - trim)))\n", - "y, t, p_x, p_xm = y[ind], t[ind], p_x[ind], p_xm[ind]\n", - "\n", - "# note on the names, ytmt' = Y(t, M(t')), the treatment needs to be\n", - "# binary but not the mediator\n", - "# p_x = np.clip(p_x, clip, 1 - clip)\n", - "# p_xm = np.clip(p_xm, clip, 1 - clip)" - ] - }, - { - "cell_type": "code", - "execution_count": 321, - "id": "30c07386-25ab-4a7d-8e3d-73fe7beccc6e", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([0.87468474, 0.86611361, 0.10836141, ..., 0.85700136, 0.24415944,\n", - " 0.09631354])" - ] - }, - "execution_count": 321, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "p_xm" - ] - }, - { - "cell_type": "code", - "execution_count": 322, - "id": "f1d1d9e9-cfca-460e-8b34-e2c173440f4a", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(array([1, 1, 0, ..., 1, 0, 0]),\n", - " array([1.2988589 , 1.35519484, 0.43082362, ..., 1.50852977, 0.61602638,\n", - " 0.39563278]))" - ] - }, - "execution_count": 322, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "t, m" - ] - }, - { - "cell_type": "code", - "execution_count": 323, - "id": "cf21bee8-16b9-4340-a1a2-0957480e57be", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(array([0.49911269, 0.49910858, 0.49911134, ..., 0.49905853, 0.4991041 ,\n", - " 0.49910848]),\n", - " array([0.87468474, 0.86611361, 0.10836141, ..., 0.85700136, 0.24415944,\n", - " 0.09631354]))" - ] - }, - "execution_count": 323, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "p_x, p_xm" - ] - }, - { - "cell_type": "code", - "execution_count": 249, - "id": "adf32072-9df7-421c-ab14-6ea6568f1017", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(1.459935393087433,\n", - " 1.4510845752122383,\n", - " 0.45031871376382127,\n", - " 0.4592350721494876)" - ] - }, - "execution_count": 249, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "y1m1, y1m0, y0m0, y0m1" - ] - }, - { - "cell_type": "code", - "execution_count": 251, - "id": "aba4768d-6dd8-4409-b00a-052650e28df6", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1.0096386399749133" - ] - }, - "execution_count": 251, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.mean(y[t==1]) - np.mean(y[t==0])" - ] - }, - { - "cell_type": "code", - "execution_count": 242, - "id": "bdec14fd-17f1-4798-9183-3c9afc691ee1", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(array([0.52450131, 0.52802596, 0.42351199, ..., 0.41328875, 0.75890838,\n", - " 0.31698331]),\n", - " array([0.44951737, 0.44707598, 0.43042701, ..., 0.44875362, 0.47679434,\n", - " 0.44453564]),\n", - " array([[0.55538922],\n", - " [0.50750763],\n", - " [0.36399668],\n", - " ...,\n", - " [0.53309387],\n", - " [0.83712826],\n", - " [0.51778423]]))" - ] - }, - "execution_count": 242, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "y[t == 0], p_xm[t==0], m[t==0]" - ] - }, - { - "cell_type": "code", - "execution_count": 229, - "id": "56cf00d5", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(array([0.49992031, 0.49999308, 0.50004991, ..., 0.49993754, 0.49994602,\n", - " 0.50002961]),\n", - " array([0.55134251, 0.54009824, 0.44951737, ..., 0.47679434, 0.54150298,\n", - " 0.44453564]))" - ] - }, - "execution_count": 229, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "p_x, p_xm" - ] - }, - { - "cell_type": "code", - "execution_count": 324, - "id": "77e2e82a", - "metadata": {}, - "outputs": [], - "source": [ - "y1m1 = np.sum(y * t / p_x) / np.sum(t / p_x)\n", - "y1m0 = np.sum(y * t * (1 - p_xm) / (p_xm * (1 - p_x))) / np.sum(t * (1 - p_xm) / (p_xm * (1 - p_x)))\n", - "y0m0 = np.sum(y * (1 - t) / (1 - p_x)) / np.sum((1 - t) / (1 - p_x))\n", - "y0m1 = np.sum(y * (1 - t) * p_xm / ((1 - p_xm) * p_x)) / np.sum((1 - t) * p_xm / ((1 - p_xm) * p_x))" - ] - }, - { - "cell_type": "code", - "execution_count": 325, - "id": "5222f22d", - "metadata": {}, - "outputs": [], - "source": [ - "total = y1m1 - y0m0\n", - "direct1 = y1m1 - y0m1\n", - "direct0 = y1m0 - y0m0\n", - "indirect1 = y1m1 - y1m0\n", - "indirect0 = y0m1 - y0m0" - ] - }, - { - "cell_type": "code", - "execution_count": 326, - "id": "85639584", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(1.0135569515076976,\n", - " 0.9705545005708663,\n", - " 0.9718376688842252,\n", - " 0.041719282623472465,\n", - " 0.04300245093683125)" - ] - }, - "execution_count": 326, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "total, direct1, direct0, indirect1, indirect0" - ] - }, - { - "cell_type": "code", - "execution_count": 327, - "id": "fc1d458c-cc45-46f6-8ec5-d928edf9d24c", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[1.01, 0.2, 0.2, array([0.81]), array([0.81]), 0]" - ] - }, - "execution_count": 327, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "causal_effects" - ] - }, - { - "cell_type": "code", - "execution_count": 328, - "id": "b7ba814d-7537-404e-aaa9-cd08db28324f", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[1.0137213660591147,\n", - " 0.20538623501610792,\n", - " 0.20538623501610792,\n", - " 0.8083351310430068,\n", - " 0.8083351310430068,\n", - " None]" - ] - }, - "execution_count": 328, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "effects_linear = ols_mediation(y, t, m, x)\n", - "effects_linear" - ] - }, - { - "cell_type": "code", - "execution_count": 213, - "id": "b2406285", - "metadata": {}, - "outputs": [], - "source": [ - "buckets = np.array([0., 0.2, 0.4, 0.6, 0.8, 1, 2])\n", - "inds_bucketized = np.digitize(m, buckets)\n", - "m_bucketized = buckets[inds_bucketized]" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "id": "3b8f735b", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([0, 0, 0, ..., 0, 0, 1])" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "t" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "id": "ae29514c", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(0.7604472500700034, 0.9298412249266818)" - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "y1m0, y1m1" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "id": "6bec18fc", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(0.9298412249266818, 0.561811808050858)" - ] - }, - "execution_count": 33, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "y1m1, y0m0" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "id": "4c714f42", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0.7304799154421578" - ] - }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "y0m1" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "id": "f9a6ae12", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([0.50738952, 0.50589069, 0.5043246 , ..., 0.51055525, 0.5073326 ,\n", - " 0.5050081 ])" - ] - }, - "execution_count": 35, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "p_x" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "id": "9fbc7b80", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([0.3441798 , 0.57279379, 0.56999283, ..., 0.34006814, 0.34241638,\n", - " 0.33865712])" - ] - }, - "execution_count": 36, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "p_xm" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "id": "03dd5fc9", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([-0.01977597, 0.83585177, 1.01397798, ..., 0.05477241,\n", - " -0.0568483 , 0.21183378])" - ] - }, - "execution_count": 37, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "y" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "id": "f41cd741", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([1.06728555, 0.97410996, 1.02338864, ..., 0.20753601, 1.15600895,\n", - " 0.21183378])" - ] - }, - "execution_count": 38, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "y[t==1]" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "id": "1d41ed95", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([False, False, False, ..., False, False, True])" - ] - }, - "execution_count": 39, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "t.squeeze()==[1]" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "id": "f8173cc4", - "metadata": {}, - "outputs": [], - "source": [ - "n = y.shape[0]" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "id": "1c5246e4", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0.4708003280218567" - ] - }, - "execution_count": 41, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "y[t.squeeze()==[1]].sum()/n" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "id": "1ac06044", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0.2774302058941099" - ] - }, - "execution_count": 42, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "y[t.squeeze()==[0]].sum()/n" - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "id": "dd96e9b3", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([0.3441798 , 0.57279379, 0.56999283, ..., 0.34006814, 0.34241638,\n", - " 0.33865712])" - ] - }, - "execution_count": 43, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "p_xm" - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "id": "8a42f190", - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "import pandas as pd\n", - "from itertools import combinations\n", - "\n", - "import seaborn as sns\n", - "# sns.set_context('talk')\n", - "# sns.set_style('whitegrid')" - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "id": "3653e203", - "metadata": {}, - "outputs": [], - "source": [ - "p_t = 0.5*np.ones_like(p_x)\n", - "th_p_t_mx = 0.5*np.ones_like(p_x)" - ] - }, - { - "cell_type": "code", - "execution_count": 46, - "id": "e1559733", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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hKtq3rFjh7p3766//vrLo8spDBw4UM2bN3eoWz0/P1+tWrXSsmXL1KFDB/cVBwAAUBv5UGAmEZoBcIPCwlMDshOi0wyHDx/TrbeurbHnLVlyaY09a+/evUpKStKWLVt0wQUX2I+/9NJLslgsbn9+TYZzK1eu1OWXX27/vn79+urYsaOeeeYZtWvXzn583LhxevDBBxUVFaWBAwdq4cKFFd7XmZ/T3Llz9e6772rz5s3Kzs5WRkaGYmNjKxwzZswYLV68WL/++muJMO+GG25QZmamVq5cqdDQUI0ePVqPP/64vv76a4frAgAAQDl8LDCTmJ4JwA1s65lZnTo9k90zUXvExMRUGuL4qh07dig1NVWfffaZMjIydM011yjzn90/Dhw4oE8++USDBg2SZA0PU1NT7S9Jmj9/fqljjsrJydE111yjsWPHVnnMU089pcjISI0aNcp+bN68efruu+80f/58BQRY/1h05513as2aNdq+fbtTtQEAAOA0PhiYSYRmANygODTLkWGYVDw9M9RTJQEVslgsmj59ulq0aKHw8HC1a9dOH374of18RkaG7rzzTjVo0EDh4eFq1aqV5s+fL0lKSkqSJLVv316GYahHjx6SrB1gN998s/0ePXr00MMPP6wRI0bojDPOUHx8vObOnauTJ09q0KBBioqK0plnnqnPP//cPsZkMmnw4MFKSkpSeHi4zj77bL300kv285MmTdLChQv18ccfyzAMGYahlStXSpIOHjyofv366YwzzlC9evV00003ae/evSXuPWrUKMXGxqpevXoaM2ZMlTu+4uLilJCQoIsvvlgvvPCC0tLStH79eknS4sWL1a5dOzVp0kSSNTxMSEiwvyQpNja21DFHjRgxQk888YQ6depU5TGhoaFauHChFi5cqC+++EIpKSkaOXKkpk+frjPPPNN+Xb169dSlSxe99957TtUGAACAU/hoYCYRmgFwg+LQLPufr7n/fKXTDN5p/Pjxmj9/vmbPnq3ff/9dI0eO1F133aVVq1ZJkp588klt27ZNn3/+ubZv367Zs2erfv36kqSffvpJkvT1118rNTVVS5cuLfc5CxcuVP369fXTTz/p4Ycf1gMPPKDbb79dXbp00ebNm9WrVy/dfffdysnJkSSZzWY1adJEixcv1rZt2zRhwgSNHTtWixcvliSNHj1affv21TXXXGPv2urSpYtycnJ0+eWXKzIyUqtXr9batWsVGRmpa665RgUFBZKkF154QfPmzdObb76ptWvX6tixY1q2bJnDP7vwcOuv68LCQknS6tWr1bFjR4fvM3XqVEVGRlb4WrNmjcP3PV2HDh2UnJysIUOG6O6779ZFF12kBx54oNR1F198sUueBwAAUKv5cGAmsaYZADf4Z5aWDOPEP0fy//lKpxm8z8mTJzVjxgx9++236ty5sySpRYsWWrt2rV5//XV1795dKSkpat++vT0Mat68uX18gwYNJFm7kyrrmmrXrp3Gjx8vSUpOTtYzzzyj+vXra+jQoZKkCRMmaPbs2frll1/UqVMnBQcHa/LkyfbxSUlJWrdunRYvXqy+ffsqMjJS4eHhys/PL/Hst99+WwEBAXrjjTdkGIYk65TI2NhYrVy5Uj179tTMmTOVnJysW2+9VZI0Z84cffnllw797I4eParJkycrKipKF198sSTrGm/OLKA/bNgw9e3bt8JrGjdu7PB9y2ILSX/88Uf9+eef9p/R6c86tTMPAAAADvLxwEwiNAPgBsWdZrY3tumZdJrB+2zbtk15eXm6+uqrSxwvKChQ+/btJUkPPPCAbr31Vm3evFk9e/bUzTffrC5dujj8rPPPP9/+PjAwUPXq1dN5551nPxYfHy9JSk9Ptx+bM2eO3njjDe3bt0+5ubkqKCgoseFAWTZt2qSdO3eW2rkyLy9Pu3btUmZmplJTU+0hoSQFBQWpY8eOVZqiaZt6efLkSbVq1UoffPCB4uLiJEm5ubkKC3N804+6deuqbt26Do9zxooVK5SamqqAgABt2LBBTZs2LXVNeHi4veMPAAAADvKDwEwiNAPgBsWhma3TjN0z4b3MZrMk6bPPPivVyRQaau2O7N27t/bt26fPPvtMX3/9ta688ko9+OCDev755x16VnBwcInvDcMocczW8WSrafHixRo5cqReeOEFde7cWVFRUXruuef0448/VvqZOnTooHfeeafUOVtnXHWsWbNG0dHRatCggaKjo0ucq1+/vjIyMhy+59SpUzV16tQKr/n888/VrVs3h+99qoyMDA0dOlRjx45VcHCwhg8fru7du9un29ocO3bMJT8rAACAWsdPAjOJ0AyAGxRPz7StaUZoBu917rnnKjQ0VCkpKerevXu51zVo0EADBw7UwIED1a1bNz322GN6/vnnFRISIsm6sL6rrVmzRl26dNHw4cPtx3bt2lXimpCQkFLPvvDCC7Vo0SLFxcWVCrVsGjZsqPXr1+uyyy6TJBUVFWnTpk268MILK60rKSmp3J1B27dvr23btlV6j9PV1PTMhx9+WHFxcRo/frwMw9BHH32khx56SO+//36J63777Td7pyEAAACqyI8CM4nQDIAblL8RQLCKiqQgfuepdeLj62rJkktr9HlVFRUVpdGjR2vkyJEym8269NJLlZWVpXXr1ikyMlL33HOPJkyYoA4dOqhNmzbKz8/X//3f/6l169aSrDtJhoeH64svvlCTJk0UFhammJgYl3yOli1b6q233tKXX36ppKQk/e9//9OGDRvsO3ZK1vXVvvzyS+3YsUP16tVTTEyM7rzzTj333HO66aabNGXKFDVp0kQpKSlaunSpHnvsMTVp0kSPPvqonnnmGbVq1UqtW7fWjBkzdPz48WrX3KtXLw0ZMkQmk0mBgYFVHufo9My0tDSlpaVp586dkqRff/1VUVFRatq0abn3WbZsmT744ANt2LDB3uG3YMECdejQQUuWLLGv7yZZA8unnnqqyvUAAADUen4WmEmEZgDcwBaaFXea5dvP5eZKpy2zhFrg668/8XQJFXrqqacUFxenadOmaffu3YqNjdWFF16osWPHSrJ2cyUnJ2vv3r0KDw9Xt27d7J1JQUFBevnllzVlyhRNmDBB3bp108qVK11S17Bhw7R161b169dPhmHojjvu0PDhw/X555/brxk6dKhWrlypjh076sSJE/ruu+/Uo0cPrV69Wo8//rj69Omj7OxsNW7cWFdeeaW98+zf//63UlNTNXDgQAUEBOjee+/VLbfcokxbq6iTrr32WgUHB+vrr79Wr169qnWvisyZM6fEJgm2jrn58+dr4MCBpa4/cuSIhg0bpokTJ5ZYW65t27aaOHFiiWmaP/zwgzIzM3Xbbbe5rX4AAAC/4oeBmSQZlqqs+OvDsrKyFBMTo8zMzHKnqABwrUcekV55RQoMfElBQc8qPz9f0lFJUnq6xDJBvq2i31fz8vK0Z88eJSUlObUYPPzDrFmz9PHHHzu8G6erDRw4UM2bN9ekSZMcGnf77berffv29tC0pvDrB0B5+DsNAK/mg4FZVX9fpdMMgMvl5trfSZIMwyKLJU9S2CnnAPir++67TxkZGcrOzi61g6e3y8/PV7t27TRy5EhPlwIAAOD9fDAwcwShGQCXy8mxvcs75WiBpDDl55e+HoB/CQoK0rhx4zxdhlNCQ0M1fvx4T5cBAADg/fw8MJMIzQC4gS00M4xT28oKJYnQDECNufnmm8vd5RMAAADVUAsCM4nQDIAbFE/BPLXTzJqWFRTUdDUAaqubb77Z0yUAAAD4n1oSmElSgKcLAOB/bJ1mZvOJU45a0zI6zQAAAADAR9WiwEwiNAPgBrZOM7P5pP2YYRCaAQAAAIDPqmWBmURoBsANijcCOHVNM0IzAAAAAPBJtTAwkwjNALhB2WuaEZoBAAAAgM+ppYGZRGgGwA2KO81yTjlqDc3YCAAAAAAAfEQtDswkQjMAbkCnGU53dqsWiogIq7HX2a1aePoja+DAgT63e6Orat6xY4cSEhKUnZ1d/aKqYeDAgZo0aZJHa5CkX3/9VU2aNNHJkycrvxgAAMBb1PLATJKCPF0AAP9T1ppmhpEvi4XQrLbaf/CQctY/UWPPi+j0TI09a+/evUpKStKWLVt0wQUX2I+/9NJLslgsbn/+wIEDdfz4cX300Uduf9bKlSt1+eWX27+vX7++OnbsqGeeeUbt2rWzHx83bpwefPBBRUVFaeDAgVq4cGGF93Xm5zR37ly9++672rx5s7Kzs5WRkaHY2NgKx4wZM0aLFy/Wr7/+qqioKPvxG264QZmZmVq5cqUCAir/90Tb/+aBgYHat2+fGjdubD+XmpqqxMREmUwm7dmzR82bN9d5552niy++WC+++KLGjx/v8GcFAACocQRmkug0A+BihYVSUZHtOzYCQO0VExNTaYjjq3bs2KHU1FR99tlnysjI0DXXXKPMzExJ0oEDB/TJJ59o0KBBkqzhYWpqqv0lSfPnzy91zFE5OTm65pprNHbs2CqPeeqppxQZGalRo0bZj82bN0/fffed5s+fX6XA7FSNGjXSW2+9VeLYwoULS4RoNoMGDdLs2bNlMpkcegYAAECNIzCzIzQD4FK5uSW+O+V9oSRCM3gni8Wi6dOnq0WLFgoPD1e7du304Ycf2s9nZGTozjvvVIMGDRQeHq5WrVpp/vz5kqSkpCRJUvv27WUYhnr06CGp9FTHHj166OGHH9aIESN0xhlnKD4+XnPnztXJkyc1aNAgRUVF6cwzz9Tnn39uH2MymTR48GAlJSUpPDxcZ599tl566SX7+UmTJmnhwoX6+OOPZRiGDMPQypUrJUkHDx5Uv379dMYZZ6hevXq66aabtHfv3hL3HjVqlGJjY1WvXj2NGTOmyh1fcXFxSkhI0MUXX6wXXnhBaWlpWr9+vSRp8eLFateunZo0aSLJGh4mJCTYX5IUGxtb6pijRowYoSeeeEKdOnWq8pjQ0FAtXLhQCxcu1BdffKGUlBSNHDlS06dP15lnnulwDffcc4/9/wc2CxYs0D333FPq2l69euno0aNatWqVw88BAACoMQRmJRCaAXCpkqHZqWuaWdMyNgKANxo/frzmz5+v2bNn6/fff9fIkSN111132QOOJ598Utu2bdPnn3+u7du3a/bs2apfv74k6aeffpIkff3110pNTdXSpUvLfc7ChQtVv359/fTTT3r44Yf1wAMP6Pbbb1eXLl20efNm9erVS3fffbdy/pnjbDab1aRJEy1evFjbtm3ThAkTNHbsWC1evFiSNHr0aPXt21fXXHONvWurS5cuysnJ0eWXX67IyEitXr1aa9euVWRkpK655hoV/POL8IUXXtC8efP05ptvau3atTp27JiWLVvm8M8uPDxcklRYaA3GV69erY4dOzp8n6lTpyoyMrLC15o1axy+7+k6dOig5ORkDRkyRHfffbcuuugiPfDAA07d68Ybb1RGRobWrl0rSfaf4w033FDq2pCQELVr184lnwEAAMAtCMxKYU0zAC5lW8/MMPJOO8P0THinkydPasaMGfr222/VuXNnSVKLFi20du1avf766+revbtSUlLUvn17exjUvHlz+/gGDRpIkurVq1dp11S7du3sa1olJyfrmWeeUf369TV06FBJ0oQJEzR79mz98ssv6tSpk4KDgzV58mT7+KSkJK1bt06LFy9W3759FRkZqfDwcOXn55d49ttvv62AgAC98cYbMgxDknVKZGxsrFauXKmePXtq5syZSk5O1q233ipJmjNnjr788kuHfnZHjx7V5MmTFRUVpYsvvliSdb2vDh06OHQfSRo2bJj69u1b4TVlTXt0hi0k/fHHH/Xnn3/af0aOCg4O1l133aV58+bp0ksv1bx583TXXXcpODi4zOsbN25cotsPAADAaxCYlYnQDIBL2TrNAgLyZTYXHzcMQjN4p23btikvL09XX311ieMFBQVq3769JOmBBx7Qrbfeqs2bN6tnz566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e65Zs0a7d+/WVVddpUWLFumKK67QHXfcIUlKTExUTEyM2rVrJ0nq2rWrLrzwQr300kv68ccfNXny5FIdZqc+o6xnm0wmFRUVafLkyTrrrLN06NChMseX9+xXXnlFL7/8ss4++2z72Mcee0yFhYV6/vnnddlll1X4uQMCAjR06FBJUkJCgv3etrGVPdtsNsswDL3zzjs6efKkJOnRRx/VuHHj9Nprrym8nLVebD/zU8fHxMRIkmbMmKHbbrvNPr5Tp07q1KmTfezpnx3+iU4zH+XyrpI6zaTOC6Ubd0lnj7B26WT+Lm15TPo40dp99seLUuYfdKDVIhMmWL8GBCyTYeyt8ecbxi8yjB3KyZHmzDnlRFGOdOATafUt0kdNrFMxC45JUa2sU48v/6pWBWYAAABwj/r16yswMLBUV1l6enqpjqnTXXjhhQoMDNQll1yikSNHatKkSfaxoaGhFd4zKSlJ3bp1U2BgoK6//nr72LKeHRAQoIsuukh//PGHNm7cqIceekiJiYmSpHnz5unnn39WUFCQvv3223KfvX//flksFj300EMKCgqyj9+5c6d9bEXPPrXb6tSfWadOneznqvK5Tx3frFmzEvet6NkNGzZU48aNFRMTYx8fGRkpi8WiAwcOSJIiIiJKhWe2e5463qZ169Ylxp+urM8O/+MToZkj2/vWFiaTypwauv9g2f8iUGV1mkkdXpRuPiBd/LrUoKt1XajD30ibR0mftZY+biat7Sdtf0FKXy3lH3XNh4JX+f576bPPJKlIhjHdIzVY/xFqpqLDM/XNe18pc/3z0rc9pQ/rSqtvkg58JFlMUv0uUue3peu2S4k3s6EFAAAAXCIkJEQdOnTQihUrShxfsWKFunTpUuWxFotF+f+sfb1ixQolJSWVuudXX31V4p628Tt37rSPLevZFotFW7duVWJion799Vdt3bpVP//8s8477zy1adNGZ599trZu3apLLrmk3GevXr1a11xzjbZu3WofHxcXp9jYWPvYip596vpjp37uLVu22M85+rnXr19f4r4VPbtr1646dOiQTpw4YR+/fPlyBQQEqEmTJpKsIdfpbM8+dbzNn3/+WWL86cr67PA/Xj8907a976xZs9S1a1e9/vrr6t27t7Zt26amTZt6ujz/FRIrtbzP+sreZd1pM/ULKX2VlLNfStkvpSwuvj60nhR1thSRKIU3lMIbWV9hcVJwlBQUZf1qex/g9f/Xq5V++UUKCJDy86VBg6zHzjhjuY4f/0uSK7dStigoUIoMMyswzKy42CJFhxYp4Yw8xYTlq1HdIiWeka8W8SfVosFcnRn/T5vZ7lPuEJEoI/FW6cwhUmwbF9YGAAAAFBs1apTuvvtudezYUZ07d9bcuXOVkpKiYcOGSZKSk5N18OBBvfXWW5Kk1157TU2bNtU555yjO+64Q6NHj1ZwcLDuuecejRw5UikpKXrrrbfUt29fXX755YqOjlaXLl309ddfa8SIEfr00091zjnnSLJ2q82ZM0fXXXedtm/frrlz52rnzp1q3bq1du/eraefflqrV6/Wvn379Nprr6lt27b2useNG6f+/furUaNGCgwM1Pjx48t99jfffKO1a9eWGN+tWzctXbpUP/30kwIDAyt99syZM9W8eXO1adNGt99+ux5//HGZzWa99NJLlX7uhx56SB999JHatGmjgoICNWzYUD/99JOuueaaKn3uc889V0899ZQGDRqkyZMnq3fv3po8ebK6deumvXv3au7cuSosLNTevXv17LPPateuXdq4caN+/fVXrV27Vm3atCkx/siRI3rsscd077332rvTJk+erE6dOqlVq1bKysrSyy+/rK1bt+q1116rqf8rwgO8PrmYMWOGBg8ebF/4cObMmfryyy81e/bsMrf3zc/PL5HCZ2ZmSpKysrJcXpvFYlHWidI7ZVoscslx5+5lccNnbSA1HmJ9FZ2Ujm6Qjm2yvjK2SjkHpZyjUkbFu8eUEBDyzytIMgL/+Rp8yvfBkhEkGaf+a4BRztdT3pfZYXT6ufK6kMqYdlpqKmoVpqaWOX21KvdxclyVajztWDk15u+wdjFK0v/ussgwihQckqaC/BwZRoCsa5sFyGKxfpXFOvffthaAdT2C0t8HBlgUGiSFBVkUGiKFBUuBDjSDZeVIKccS9Mu+C7Xmz2765rcrFd34LH377T83ccOv7wvbn6+Dh1LLPFeQX+CFv/Zr7vcE2/0sTNUGAAC1QL9+/XT06FFNmTJFqampatu2rZYvX65mzZpJklJTU5WSkmK/3mw2Kzk5WXv27FFQUJAaNmyonJwczZ8/3z72sssu0/vvv6/BgwcrOztbf/75pxYtWqSDBw+WGHvmmWeqX79+Wr9+vS644AK1bdtWN910k5588kmlpaXJMAxFRERo9erVuvjii0vV/dZbb2nFihX2sRU929ZNZtO2bVutX7++xOeu6NkrV67U6NGjdfDgQYWHhyspKUnZ2dl67LHHKn32zp07S4xt06aNHnjgAX322Wd64403qvS5V6xYoYcfflgdO3ZUvXr1dMUVV2jnzp32z/7FF18oPT1d48eP159//qmwsLASn/v08X379tXTTz9t/3kcP35c9913n9LS0hQTE6P27duX+XOHfzEsXvy3noKCAkVEROiDDz7QLbfcYj/+6KOPauvWrVq1alWpMZMmTdLkyZNrskwAqJX2799fbrs6AAAAAPg6r+40c2Z73+TkZI0aNcr+vdls1rFjx1SvXr1KdzfxdllZWUpMTNT+/fsVHR3t6XJczp8/nz9/Nsm/P58/fzbJuc9nsViUnZ2tRo3YVRcAAACA//Lq0MzGke19Q0NDFRoaWuJYbGysu0rziOjoaL/8y7uNP38+f/5skn9/Pn/+bJLjn+/UnYUAAAAAwB959e6Z1dneFwAAAAAAAHCWV4dm1dneFwAAAAAAAHCW10/PrGx739okNDRUEydOLDX91F/48+fz588m+ffn8+fPJvn/5wMAAAAAZ3n17pk2s2bN0vTp0+3b3L744ou67LLLPF0WAAAAAAAA/JRPhGYAAAAAAABATfLqNc0AAAAAAAAATyA0AwAAAACgHCtXrpRhGDp+/LinS3GIYRj66KOPXHa/5s2ba+bMmdW+z5tvvqmePXtWv6Bqat68uVauXOnpMvTqq6/qxhtv9HQZKAehGQAAAAAAknr06KERI0Z4ugyHTJo0SRdccEGp46mpqerdu3eN1mEYhgzDUGBgoBITEzVkyBD9/fff9mvy8/M1YcIEPfnkk5KswZVtTFmvHj16OFXLo48+qg4dOig0NLTMn83pTCaTunTpoltvvbXE8czMTCUmJmr8+PFVfvaCBQtkGIZat25d6tzixYtlGIaaN29uPzZ06FBt2LBBa9eurfIzUHMIzQAAAAAA8DKFhYXVGp+QkFDjO6S3adNGqampSklJ0ezZs/Xpp59qwIAB9vNLlixRZGSkunXrJknasGGDUlNTlZqaqiVLlkiSduzYYT+2dOlSp+qwWCy699571a9fvypdHxgYqIULF+qLL77QO++8Yz/+8MMPq27dupowYYJDz69Tp47S09P1ww8/lDg+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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(15, 5))\n", - "# sns.kdeplot(p_t, color=\"blue\", ls='--', ax=axes[0], label='theoretical P(T=1|X)')\n", - "sns.histplot(p_x, color=\"blue\", kde=True, stat='density', ax=axes[0], label='estimated P(T=1|X)')\n", - "# sns.kdeplot(th_p_t_mx, color=\"orange\", ls='--', ax=axes[0], label='theoretical P(T=1|X, M)')\n", - "sns.histplot(p_xm, color=\"orange\", kde=True, bins=50, stat='density', ax=axes[0], label='estimated P(T=1|X, M)')\n", - "\n", - "axes[0].legend(bbox_to_anchor=[1, 0.9])\n", - "\n", - "ax = axes[1]\n", - "sns.scatterplot(x=th_p_t_mx[ind], y=p_xm, ax=ax)\n", - "ax.set_xticks(ax.get_yticks())\n", - "ax.set_aspect('equal', adjustable='box')\n", - "plt.plot([0, 1], [0, 1], 'red')\n", - "plt.ylabel('estimated P(T=1|X, M)')\n", - "plt.xlabel('theoretical P(T=1|X, M)')\n", - "plt.subplots_adjust(wspace=1.4)" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "id": "92f6704d", - "metadata": {}, - "outputs": [], - "source": [ - "interaction=False\n", - "forest=False\n", - "crossfit=0\n", - "calibration=True\n", - "regularization=True\n", - "calib_method='sigmoid'" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "id": "21010053", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[2. ],\n", - " [0.6],\n", - " [0.8],\n", - " ...,\n", - " [2. ],\n", - " [2. ],\n", - " [0.8]])" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m_bucketized" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "id": "6072f13b", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/model_selection/_split.py:737: UserWarning: The least populated class in y has only 4 members, which is less than n_splits=5.\n", - " warnings.warn(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/model_selection/_split.py:737: UserWarning: The least populated class in y has only 4 members, which is less than n_splits=5.\n", - " warnings.warn(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/model_selection/_split.py:737: UserWarning: The least populated class in y has only 4 members, which is less than n_splits=5.\n", - " warnings.warn(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/model_selection/_split.py:737: UserWarning: The least populated class in y has only 4 members, which is less than n_splits=5.\n", - " warnings.warn(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/model_selection/_split.py:737: UserWarning: The least populated class in y has only 4 members, which is less than n_splits=5.\n", - " warnings.warn(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n", - "/Users/hzenati/miniconda3/envs/mind/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n", - "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", - "\n", - "Increase the number of iterations (max_iter) or scale the data as shown in:\n", - " https://scikit-learn.org/stable/modules/preprocessing.html\n", - "Please also refer to the documentation for alternative solver options:\n", - " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", - " n_iter_i = _check_optimize_result(\n" - ] - } - ], - "source": [ - "if regularization:\n", - " alphas = ALPHAS\n", - " cs = ALPHAS\n", - "else:\n", - " alphas = [0.0]\n", - " cs = [np.inf]\n", - "m = inds_bucketized\n", - "n = len(y)\n", - "if len(x.shape) == 1:\n", - " x = x.reshape(-1, 1)\n", - "if len(m.shape) == 1:\n", - " mr = m.reshape(-1, 1)\n", - "else:\n", - " mr = np.copy(m)\n", - "if len(t.shape) == 1:\n", - " t = t.reshape(-1, 1)\n", - "\n", - "t0 = np.zeros((n, 1))\n", - "t1 = np.ones((n, 1))\n", - "m0 = np.zeros((n, 1))\n", - "m1 = np.ones((n, 1))\n", - "\n", - "if crossfit < 2:\n", - " train_test_list = [[np.arange(n), np.arange(n)]]\n", - "else:\n", - " kf = KFold(n_splits=crossfit)\n", - " train_test_list = list()\n", - " for train_index, test_index in kf.split(x):\n", - " train_test_list.append([train_index, test_index])\n", - "mu_1bx, mu_0bx, f_0bx, f_1bx = \\\n", - " [np.zeros(n) for h in range(4)]\n", - "\n", - "for train_index, test_index in train_test_list:\n", - " if not forest:\n", - " y_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS)\\\n", - " .fit(get_interactions(interaction, x, t, mr)[train_index, :], y[train_index])\n", - " pre_m_prob = LogisticRegressionCV(Cs=cs, cv=CV_FOLDS)\\\n", - " .fit(get_interactions(interaction, t, x)[train_index, :], m.ravel()[train_index])\n", - " else:\n", - " y_reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10)\\\n", - " .fit(get_interactions(interaction, x, t, mr)[train_index, :], y[train_index])\n", - " pre_m_prob = RandomForestClassifier(n_estimators=100, min_samples_leaf=10)\\\n", - " .fit(get_interactions(interaction, t, x)[train_index, :], m.ravel()[train_index])\n", - " if calibration:\n", - " m_prob = CalibratedClassifierCV(pre_m_prob, method=calib_method)\\\n", - " .fit(get_interactions(\n", - " interaction, t, x)[train_index, :], m.ravel()[train_index])\n", - " else:\n", - " m_prob = pre_m_prob\n", - "# mu_11x[test_index] = y_reg.predict(get_interactions(interaction, x, t1, m1)[test_index, :])\n", - "# mu_10x[test_index] = y_reg.predict(get_interactions(interaction, x, t1, m0)[test_index, :])\n", - "# mu_01x[test_index] = y_reg.predict(get_interactions(interaction, x, t0, m1)[test_index, :])\n", - "# mu_00x[test_index] = y_reg.predict(get_interactions(interaction, x, t0, m0)[test_index, :])\n", - "# f_00x[test_index] = m_prob.predict_proba(get_interactions(interaction, t0, x)[test_index, :])[:, 0]\n", - "# f_01x[test_index] = m_prob.predict_proba(get_interactions(interaction, t0, x)[test_index, :])[:, 1]\n", - "# f_10x[test_index] = m_prob.predict_proba(get_interactions(interaction, t1, x)[test_index, :])[:, 0]\n", - "# f_11x[test_index] = m_prob.predict_proba(get_interactions(interaction, t1, x)[test_index, :])[:, 1]\n", - "\n", - " buckets = [0., 0.2, 0.4, 0.6, 0.8, 1]\n", - "\n", - " direct_effect_treated = 0\n", - " direct_effect_control = 0\n", - " indirect_effect_treated = 0\n", - " indirect_effect_control = 0\n", - "\n", - " for i, b in enumerate(buckets):\n", - "\n", - " mb = m1 * b\n", - " mu_1bx = y_reg.predict(get_interactions(interaction, x, t1, mb)[test_index, :])\n", - " mu_0bx = y_reg.predict(get_interactions(interaction, x, t0, mb)[test_index, :])\n", - " f_1bx[test_index] = m_prob.predict_proba(get_interactions(interaction, t1, x)[test_index, :])[:, i]\n", - " f_0bx[test_index] = m_prob.predict_proba(get_interactions(interaction, t0, x)[test_index, :])[:, i]\n", - " direct_effect_ib = mu_1bx - mu_0bx\n", - " direct_effect_treated += direct_effect_ib * f_1bx\n", - " direct_effect_control += direct_effect_ib * f_0bx\n", - " indirect_effect_ib = f_1bx - f_0bx\n", - " indirect_effect_treated += indirect_effect_ib * mu_1bx\n", - " indirect_effect_control += indirect_effect_ib * mu_0bx\n", - "\n", - " direct_effect_treated = direct_effect_treated.sum() / n\n", - " direct_effect_control = direct_effect_control.sum() / n\n", - " indirect_effect_treated = indirect_effect_treated.sum() / n\n", - " indirect_effect_control = indirect_effect_control.sum() / n\n" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "id": "e85e881c-e82a-42d2-b465-636566e21f9b", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[1.01, 0.2, 0.2, array([0.81]), array([0.81]), 0]" - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "causal_effects" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "id": "84006a50-43a5-464e-90e9-f56fe2d68d6d", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(0.06149657232696939,\n", - " 0.734283505124638,\n", - " -0.8715992158774716,\n", - " -0.19881228307980306)" - ] - }, - "execution_count": 33, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "direct_effect_treated, direct_effect_control, indirect_effect_treated, indirect_effect_control" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "id": "ab3b83fe", - "metadata": {}, - "outputs": [ - { - "ename": "SyntaxError", - "evalue": "invalid syntax (619621430.py, line 3)", - "output_type": "error", - "traceback": [ - "\u001b[0;36m Cell \u001b[0;32mIn[20], line 3\u001b[0;36m\u001b[0m\n\u001b[0;31m direct effect_treated = 0\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" - ] - } - ], - "source": [ - "buckets = [0., 0.2, 0.4, 0.6, 0.8, 1]\n", - "\n", - "direct effect_treated = 0\n", - "direct_effect_control = 0\n", - "indirect_effect_treated = 0\n", - "indirect_effect_control = 0\n", - "\n", - "for i, b in enumerate(buckets):\n", - " \n", - " mb = m1 * b\n", - " mu_1bx = y_reg.predict(get_interactions(interaction, x, t1, mb)[test_index, :])\n", - " mu_0bx = y_reg.predict(get_interactions(interaction, x, t0, mb)[test_index, :])\n", - " f_1bx[test_index] = m_prob.predict_proba(get_interactions(interaction, t1, x)[test_index, :])[:, i]\n", - " f_0bx[test_index] = m_prob.predict_proba(get_interactions(interaction, t0, x)[test_index, :])[:, i]\n", - " direct_effect_ib = mu_1bx - mu_0bx\n", - " direct_effect_treated += direct_effect_ib * f_1bx\n", - " direct_effect_control += direct_effect_ib * f_0bx\n", - " indirect_effect_ib = f_1bx - f_0bx\n", - " indirect_effect_treated += indirect_effect_ib * mu_1bx\n", - " indirect_effect_control += indirect_effect_ib * mu_0bx\n", - " \n", - "direct_effect_treated = direct_effect_treated.sum() / n\n", - "direct_effect_control = direct_effect_control.sum() / n\n", - "indirect_effect_treated = indirect_effect_treated.sum() / n\n", - "indirect_effect_control = indirect_effect_control.sum() / n" - ] - }, - { - "cell_type": "code", - "execution_count": 62, - "id": "eb1adce2", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ 0, 1, 2, ..., 9997, 9998, 9999])" - ] - }, - "execution_count": 62, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "test_index" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3632820b", - "metadata": {}, - "outputs": [], - "source": [ - "direct_effect_i1 = mu_11x - mu_01x\n", - "direct_effect_i0 = mu_10x - mu_00x\n", - "direct_effect_treated = (direct_effect_i1 * f_11x + direct_effect_i0 * f_10x).sum() / n\n", - "direct_effect_control = (direct_effect_i1 * f_01x + direct_effect_i0 * f_00x).sum() / n\n", - "indirect_effect_i1 = f_11x - f_01x\n", - "indirect_effect_i0 = f_10x - f_00x\n", - "indirect_effect_treated = (indirect_effect_i1 * mu_11x + indirect_effect_i0 * mu_10x).sum() / n\n", - "indirect_effect_control = (indirect_effect_i1 * mu_01x + indirect_effect_i0 * mu_00x).sum() / n\n", - "total_effect = direct_effect_control + indirect_effect_treated" - ] - }, - { - "cell_type": "code", - "execution_count": 63, - "id": "681bfa5f", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[0],\n", - " [1],\n", - " [1],\n", - " ...,\n", - " [0],\n", - " [0],\n", - " [0]])" - ] - }, - "execution_count": 63, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "id": "21bcc8b3", - "metadata": {}, - "outputs": [], - "source": [ - "zmar = np.array([0.2, 6.4, 3.0, 1.6])\n", - "bins = np.array([-np.inf, 0.0, 1.0, 2.5, 4.0, 10.0])\n", - "inds = np.digitize(zmar, bins)" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "id": "9f065267", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([2, 5, 4, 3])" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "inds" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "id": "07d3c72f", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ 1. , 10. , 4. , 2.5])" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "bins[inds]" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "id": "f1546dec", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([2, 5, 4, 3])" - ] - }, - "execution_count": 28, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "inds" - ] - }, - { - "cell_type": "code", - "execution_count": 92, - "id": "60fa05b5", - "metadata": {}, - "outputs": [], - "source": [ - "m_classes = np.arange(buckets.shape[0])" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "id": "c2f431ab", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ 1. , 10. , 4. , 2.5])" - ] - }, - "execution_count": 29, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "bins[inds]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "049fa7d3-c25f-456e-a4b3-762e1c78af5e", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.18" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} From cf8af6d4a10e7a7da53157d75af1303a204377b5 Mon Sep 17 00:00:00 2001 From: houssamzenati Date: Wed, 6 Nov 2024 17:12:04 +0100 Subject: [PATCH 42/84] line formatting --- .gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index 834d0a8..c9e01a6 100644 --- a/.gitignore +++ b/.gitignore @@ -131,3 +131,9 @@ dmypy.json # DS_STORE files src/.DS_Store .DS_Store + +# Mac +.idea/ + +# Ignore PDFs +*.pdf \ No newline at end of file From d022006efbd66400edfbe96dc615273e321b7a67 Mon Sep 17 00:00:00 2001 From: houssamzenati Date: Wed, 6 Nov 2024 17:23:35 +0100 Subject: [PATCH 43/84] line formatting changes --- .gitignore | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index c9e01a6..54eecfc 100644 --- a/.gitignore +++ b/.gitignore @@ -136,4 +136,8 @@ src/.DS_Store .idea/ # Ignore PDFs -*.pdf \ No newline at end of file +*.pdf + +# Ignore local scripts + +scripts/ \ No newline at end of file From 6378d4318af2c23ec76999d758ad47475dd26d6e Mon Sep 17 00:00:00 2001 From: houssamzenati Date: Wed, 6 Nov 2024 17:31:54 +0100 Subject: [PATCH 44/84] line formatting --- src/med_bench/estimation/base.py | 143 +++--- .../mediation_coefficient_product.py | 23 +- src/med_bench/estimation/mediation_dml.py | 36 +- .../estimation/mediation_g_computation.py | 29 +- src/med_bench/estimation/mediation_ipw.py | 33 +- src/med_bench/estimation/mediation_mr.py | 57 ++- src/med_bench/estimation/mediation_tmle.py | 97 ++-- src/med_bench/mediation.py | 434 ++++++++++-------- .../nuisances/conditional_outcome.py | 15 +- .../nuisances/cross_conditional_outcome.py | 96 ++-- src/med_bench/nuisances/density.py | 33 +- src/med_bench/nuisances/propensities.py | 3 +- src/med_bench/nuisances/utils.py | 16 +- src/med_bench/utils/constants.py | 7 +- src/med_bench/utils/nuisances.py | 30 +- src/med_bench/utils/scores.py | 10 +- src/med_bench/utils/utils.py | 46 +- 17 files changed, 573 insertions(+), 535 deletions(-) diff --git a/src/med_bench/estimation/base.py b/src/med_bench/estimation/base.py index 0d7500b..caa1560 100644 --- a/src/med_bench/estimation/base.py +++ b/src/med_bench/estimation/base.py @@ -11,8 +11,8 @@ class Estimator: - """General abstract class for causal mediation Estimator - """ + """General abstract class for causal mediation Estimator""" + __metaclass__ = ABCMeta def __init__(self, regressor, classifier, verbose: bool = True, crossfit: int = 0): @@ -20,23 +20,23 @@ def __init__(self, regressor, classifier, verbose: bool = True, crossfit: int = Parameters ---------- - regressor + regressor Regressor used for mu estimation, can be any object with a fit and predict method - classifier + classifier Classifier used for propensity estimation, can be any object with a fit and predict_proba method verbose : bool will print some logs if True crossfit : int number of crossfit folds, if 0 no crossfit is performed """ + assert hasattr(regressor, "fit"), "The model does not have a 'fit' method." assert hasattr( - regressor, 'fit'), "The model does not have a 'fit' method." - assert hasattr( - regressor, 'predict'), "The model does not have a 'predict' method." - assert hasattr( - classifier, 'fit'), "The model does not have a 'fit' method." + regressor, "predict" + ), "The model does not have a 'predict' method." + assert hasattr(classifier, "fit"), "The model does not have a 'fit' method." assert hasattr( - classifier, 'predict_proba'), "The model does not have a 'predict_proba' method." + classifier, "predict_proba" + ), "The model does not have a 'predict_proba' method." self.regressor = regressor self.classifier = classifier @@ -52,17 +52,18 @@ def verbose(self): return self._verbose def _crossfit_check(self): - """Checks if the estimator inputs are valid - """ + """Checks if the estimator inputs are valid""" if self._crossfit > 0: - raise NotImplementedError("""Crossfit is not implemented yet + raise NotImplementedError( + """Crossfit is not implemented yet You should perform something like this on your side : cf_iterator = KFold(k=5) for data_train, data_test in cf_iterator: result.append(DML(...., cross_fitting=False) .fit(train_data.X, train_data.t, train_data.m, train_data.y)\ .estimate(test_data.X, test_data.t, test_data.m, test_data.y)) - np.mean(result)""") + np.mean(result)""" + ) @abstractmethod def fit(self, t, m, x, y): @@ -140,8 +141,7 @@ def _resize(self, t, m, x, y): m = m.reshape(n, 1) if n != len(x) or n != len(m) or n != len(t): - raise ValueError( - "Inputs don't have the same number of observations") + raise ValueError("Inputs don't have the same number of observations") y = y.ravel() t = t.ravel() @@ -149,8 +149,7 @@ def _resize(self, t, m, x, y): return t, m, x, y def _input_reshape(self, t, m, x): - """Reshape data for the right shape - """ + """Reshape data for the right shape""" if len(t.shape) == 1: t = t.reshape(-1, 1) if len(m.shape) == 1: @@ -161,16 +160,14 @@ def _input_reshape(self, t, m, x): return t, m, x def _fit_treatment_propensity_x_nuisance(self, t, x): - """ Fits the nuisance parameter for the propensity P(T=1|X) - """ + """Fits the nuisance parameter for the propensity P(T=1|X)""" classifier = clone(self.classifier) self._classifier_t_x = classifier.fit(x, t) return self def _fit_treatment_propensity_xm_nuisance(self, t, m, x): - """ Fits the nuisance parameter for the propensity P(T=1|X, M) - """ + """Fits the nuisance parameter for the propensity P(T=1|X, M)""" xm = np.hstack((x, m)) self._classifier_t_xm = self.classifier.fit(xm, t) @@ -178,8 +175,7 @@ def _fit_treatment_propensity_xm_nuisance(self, t, m, x): # TODO : Enable any sklearn object as classifier or regressor def _fit_mediator_nuisance(self, t, m, x): - """ Fits the nuisance parameter for the density f(M=m|T, X) - """ + """Fits the nuisance parameter for the density f(M=m|T, X)""" # estimate mediator densities clf_param_grid = {} classifier_m = GridSearchCV(self.classifier, clf_param_grid) @@ -192,8 +188,7 @@ def _fit_mediator_nuisance(self, t, m, x): return self def _fit_conditional_mean_outcome_nuisance(self, t, m, x, y): - """ Fits the nuisance for the conditional mean outcome for the density f(M=m|T, X) - """ + """Fits the nuisance for the conditional mean outcome for the density f(M=m|T, X)""" x_t_m = np.hstack([x, t.reshape(-1, 1), m]) reg_param_grid = {} @@ -206,8 +201,7 @@ def _fit_conditional_mean_outcome_nuisance(self, t, m, x, y): return self def _fit_cross_conditional_mean_outcome_nuisance(self, t, m, x, y): - """ Fits the cross conditional mean outcome E[E[Y|T=t,M,X]|T=t',X] - """ + """Fits the cross conditional mean outcome E[E[Y|T=t,M,X]|T=t',X]""" xm = np.hstack((x, m)) @@ -237,34 +231,34 @@ def _fit_cross_conditional_mean_outcome_nuisance(self, t, m, x, y): self.regressors = {} # predict E[Y|T=1,M,X] - self.regressors['y_t1_mx'] = clone(regressor_y) - self.regressors['y_t1_mx'].fit(xm[train_mean1], y[train_mean1]) - mu_1mx_nested[train_nested] = self.regressors['y_t1_mx'].predict( - xm[train_nested]) + self.regressors["y_t1_mx"] = clone(regressor_y) + self.regressors["y_t1_mx"].fit(xm[train_mean1], y[train_mean1]) + mu_1mx_nested[train_nested] = self.regressors["y_t1_mx"].predict( + xm[train_nested] + ) # predict E[Y|T=0,M,X] - self.regressors['y_t0_mx'] = clone(regressor_y) - self.regressors['y_t0_mx'].fit(xm[train_mean0], y[train_mean0]) - mu_0mx_nested[train_nested] = self.regressors['y_t0_mx'].predict( - xm[train_nested]) + self.regressors["y_t0_mx"] = clone(regressor_y) + self.regressors["y_t0_mx"].fit(xm[train_mean0], y[train_mean0]) + mu_0mx_nested[train_nested] = self.regressors["y_t0_mx"].predict( + xm[train_nested] + ) # predict E[E[Y|T=1,M,X]|T=0,X] - self.regressors['y_t1_x_t0'] = clone(regressor_y) - self.regressors['y_t1_x_t0'].fit( - x[train_nested0], mu_1mx_nested[train_nested0]) + self.regressors["y_t1_x_t0"] = clone(regressor_y) + self.regressors["y_t1_x_t0"].fit(x[train_nested0], mu_1mx_nested[train_nested0]) # predict E[E[Y|T=0,M,X]|T=1,X] - self.regressors['y_t0_x_t1'] = clone(regressor_y) - self.regressors['y_t0_x_t1'].fit( - x[train_nested1], mu_0mx_nested[train_nested1]) + self.regressors["y_t0_x_t1"] = clone(regressor_y) + self.regressors["y_t0_x_t1"].fit(x[train_nested1], mu_0mx_nested[train_nested1]) # predict E[Y|T=1,X] - self.regressors['y_t1_x'] = clone(regressor_y) - self.regressors['y_t1_x'].fit(x[train1], y[train1]) + self.regressors["y_t1_x"] = clone(regressor_y) + self.regressors["y_t1_x"].fit(x[train1], y[train1]) # predict E[Y|T=0,X] - self.regressors['y_t0_x'] = clone(regressor_y) - self.regressors['y_t0_x'].fit(x[train0], y[train0]) + self.regressors["y_t0_x"] = clone(regressor_y) + self.regressors["y_t0_x"].fit(x[train0], y[train0]) return self @@ -298,13 +292,11 @@ def _fit_cross_conditional_mean_outcome_nuisance_discrete(self, t, m, x, y): self.regressors = {} # mu_tm model fitting - self.regressors['y_t_mx'] = clone(regressor_y).fit(x_t_m, y) + self.regressors["y_t_mx"] = clone(regressor_y).fit(x_t_m, y) # predict E[Y|T=t,M,X] - mu_1mx[test_index] = self.regressors['y_t_mx'].predict( - x_t1_m[test_index, :]) - mu_0mx[test_index] = self.regressors['y_t_mx'].predict( - x_t0_m[test_index, :]) + mu_1mx[test_index] = self.regressors["y_t_mx"].predict(x_t1_m[test_index, :]) + mu_0mx[test_index] = self.regressors["y_t_mx"].predict(x_t0_m[test_index, :]) for i, b in enumerate(np.unique(m)): mb = m1 * b @@ -316,29 +308,28 @@ def _fit_cross_conditional_mean_outcome_nuisance_discrete(self, t, m, x, y): x_t1_mb = np.hstack([x, t1.reshape(-1, 1), mb]) x_t0_mb = np.hstack([x, t0.reshape(-1, 1), mb]) - mu_0bx[test_index] = self.regressors['y_t_mx'].predict( - x_t0_mb[test_index, :]) - mu_1bx[test_index] = self.regressors['y_t_mx'].predict( - x_t1_mb[test_index, :]) + mu_0bx[test_index] = self.regressors["y_t_mx"].predict( + x_t0_mb[test_index, :] + ) + mu_1bx[test_index] = self.regressors["y_t_mx"].predict( + x_t1_mb[test_index, :] + ) # E[E[Y|T=1,M=m,X]|T=t,X] model fitting - self.regressors['reg_y_t1m{}_t0'.format(i)] = clone( - regressor_y).fit( - x[test_index, :][ind_t0, :], - mu_1bx[test_index][ind_t0]) - self.regressors['reg_y_t1m{}_t1'.format(i)] = clone( - regressor_y).fit( - x[test_index, :][~ind_t0, :], mu_1bx[test_index][~ind_t0]) + self.regressors["reg_y_t1m{}_t0".format(i)] = clone(regressor_y).fit( + x[test_index, :][ind_t0, :], mu_1bx[test_index][ind_t0] + ) + self.regressors["reg_y_t1m{}_t1".format(i)] = clone(regressor_y).fit( + x[test_index, :][~ind_t0, :], mu_1bx[test_index][~ind_t0] + ) # E[E[Y|T=0,M=m,X]|T=t,X] model fitting - self.regressors['reg_y_t0m{}_t0'.format(i)] = clone( - regressor_y).fit( - x[test_index, :][ind_t0, :], - mu_0bx[test_index][ind_t0]) - self.regressors['reg_y_t0m{}_t1'.format(i)] = clone( - regressor_y).fit( - x[test_index, :][~ind_t0, :], - mu_0bx[test_index][~ind_t0]) + self.regressors["reg_y_t0m{}_t0".format(i)] = clone(regressor_y).fit( + x[test_index, :][ind_t0, :], mu_0bx[test_index][ind_t0] + ) + self.regressors["reg_y_t0m{}_t1".format(i)] = clone(regressor_y).fit( + x[test_index, :][~ind_t0, :], mu_0bx[test_index][~ind_t0] + ) return self @@ -500,21 +491,21 @@ def _estimate_cross_conditional_mean_outcome_nesting(self, m, x, y): xm = np.hstack((x, m)) # predict E[Y|T=1,M,X] - mu_1mx = self.regressors['y_t1_mx'].predict(xm) + mu_1mx = self.regressors["y_t1_mx"].predict(xm) # predict E[Y|T=0,M,X] - mu_0mx = self.regressors['y_t0_mx'].predict(xm) + mu_0mx = self.regressors["y_t0_mx"].predict(xm) # predict E[E[Y|T=1,M,X]|T=0,X] - E_mu_t1_t0 = self.regressors['y_t1_x_t0'].predict(x) + E_mu_t1_t0 = self.regressors["y_t1_x_t0"].predict(x) # predict E[E[Y|T=0,M,X]|T=1,X] - E_mu_t0_t1 = self.regressors['y_t0_x_t1'].predict(x) + E_mu_t0_t1 = self.regressors["y_t0_x_t1"].predict(x) # predict E[Y|T=1,X] - mu_1x = self.regressors['y_t1_x'].predict(x) + mu_1x = self.regressors["y_t1_x"].predict(x) # predict E[Y|T=0,X] - mu_0x = self.regressors['y_t0_x'].predict(x) + mu_0x = self.regressors["y_t0_x"].predict(x) return mu_0mx, mu_1mx, mu_0x, E_mu_t0_t1, E_mu_t1_t0, mu_1x diff --git a/src/med_bench/estimation/mediation_coefficient_product.py b/src/med_bench/estimation/mediation_coefficient_product.py index 0e3b75f..14c2078 100644 --- a/src/med_bench/estimation/mediation_coefficient_product.py +++ b/src/med_bench/estimation/mediation_coefficient_product.py @@ -45,11 +45,9 @@ def fit(self, t, m, x, y): self._coef_t_m = np.zeros(m.shape[1]) for i in range(m.shape[1]): - m_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) \ - .fit(np.hstack((x, t)), m[:, i]) + m_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit(np.hstack((x, t)), m[:, i]) self._coef_t_m[i] = m_reg.coef_[-1] - y_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) \ - .fit(np.hstack((x, t, m)), y.ravel()) + y_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit(np.hstack((x, t, m)), y.ravel()) self._coef_y = y_reg.coef_ @@ -60,20 +58,17 @@ def fit(self, t, m, x, y): @fitted def estimate(self, t, m, x, y): - """Estimates causal effect on data - - """ + """Estimates causal effect on data""" direct_effect_treated = self._coef_y[x.shape[1]] direct_effect_control = direct_effect_treated - indirect_effect_treated = sum( - self._coef_y[x.shape[1] + 1:] * self._coef_t_m) + indirect_effect_treated = sum(self._coef_y[x.shape[1] + 1 :] * self._coef_t_m) indirect_effect_control = indirect_effect_treated causal_effects = { - 'total_effect': direct_effect_treated+indirect_effect_control, - 'direct_effect_treated': direct_effect_treated, - 'direct_effect_control': direct_effect_control, - 'indirect_effect_treated': indirect_effect_treated, - 'indirect_effect_control': indirect_effect_control + "total_effect": direct_effect_treated + indirect_effect_control, + "direct_effect_treated": direct_effect_treated, + "direct_effect_control": direct_effect_control, + "indirect_effect_treated": indirect_effect_treated, + "indirect_effect_control": indirect_effect_control, } return causal_effects diff --git a/src/med_bench/estimation/mediation_dml.py b/src/med_bench/estimation/mediation_dml.py index ceea223..9f76879 100644 --- a/src/med_bench/estimation/mediation_dml.py +++ b/src/med_bench/estimation/mediation_dml.py @@ -21,9 +21,7 @@ def __init__(self, clip: float, trim: float, normalized: bool, **kwargs): self._normalized = normalized def fit(self, t, m, x, y): - """Fits nuisance parameters to data - - """ + """Fits nuisance parameters to data""" t, m, x, y = self._resize(t, m, x, y) self._fit_treatment_propensity_x_nuisance(t, x) @@ -35,15 +33,14 @@ def fit(self, t, m, x, y): print("Nuisance models fitted") def estimate(self, t, m, x, y): - """Estimates causal effect on data - - """ + """Estimates causal effect on data""" t, m, x, y = self._resize(t, m, x, y) p_x, p_xm = self._estimate_treatment_probabilities(t, m, x) - mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 = self._estimate_cross_conditional_mean_outcome_nesting( - m, x, y) + mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 = ( + self._estimate_cross_conditional_mean_outcome_nesting(m, x, y) + ) # score computing if self._normalized: @@ -52,17 +49,14 @@ def estimate(self, t, m, x, y): sum_score_t1m0 = np.mean(t * (1 - p_xm) / (p_xm * (1 - p_x))) sum_score_t0m1 = np.mean((1 - t) * p_xm / ((1 - p_xm) * p_x)) y1m1 = (t / p_x * (y - E_mu_t1_t1)) / sum_score_m1 + E_mu_t1_t1 - y0m0 = (((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / sum_score_m0 - + E_mu_t0_t0) + y0m0 = ((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / sum_score_m0 + E_mu_t0_t0 y1m0 = ( - (t * (1 - p_xm) / (p_xm * (1 - p_x)) * (y - mu_1mx)) - / sum_score_t1m0 + ( - (1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0)) - / sum_score_m0 + E_mu_t1_t0 + (t * (1 - p_xm) / (p_xm * (1 - p_x)) * (y - mu_1mx)) / sum_score_t1m0 + + ((1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0)) / sum_score_m0 + + E_mu_t1_t0 ) y0m1 = ( - ((1 - t) * p_xm / ((1 - p_xm) * p_x) * (y - mu_0mx)) - / sum_score_t0m1 + ((1 - t) * p_xm / ((1 - p_xm) * p_x) * (y - mu_0mx)) / sum_score_t0m1 + (t / p_x * (mu_0mx - E_mu_t0_t1)) / sum_score_m1 + E_mu_t0_t1 ) @@ -95,11 +89,11 @@ def estimate(self, t, m, x, y): indirect_effect_control = eta_t0t1 - eta_t0t0 causal_effects = { - 'total_effect': total_effect, - 'direct_effect_treated': direct_effect_treated, - 'direct_effect_control': direct_effect_control, - 'indirect_effect_treated': indirect_effect_treated, - 'indirect_effect_control': indirect_effect_control + "total_effect": total_effect, + "direct_effect_treated": direct_effect_treated, + "direct_effect_control": direct_effect_control, + "indirect_effect_treated": indirect_effect_treated, + "indirect_effect_control": indirect_effect_control, } return causal_effects diff --git a/src/med_bench/estimation/mediation_g_computation.py b/src/med_bench/estimation/mediation_g_computation.py index 430f10e..2beff67 100644 --- a/src/med_bench/estimation/mediation_g_computation.py +++ b/src/med_bench/estimation/mediation_g_computation.py @@ -6,18 +6,14 @@ class GComputation(Estimator): - """GComputation estimation method class - """ + """GComputation estimation method class""" def __init__(self, **kwargs): - """Initalization of the GComputation estimation method class - """ + """Initalization of the GComputation estimation method class""" super().__init__(**kwargs) def fit(self, t, m, x, y): - """Fits nuisance parameters to data - - """ + """Fits nuisance parameters to data""" t, m, x, y = self._resize(t, m, x, y) self._fit_cross_conditional_mean_outcome_nuisance(t, m, x, y) @@ -30,14 +26,13 @@ def fit(self, t, m, x, y): @fitted def estimate(self, t, m, x, y): - """Estimates causal effect on data - - """ + """Estimates causal effect on data""" t, m, x, y = self._resize(t, m, x, y) - mu_0mx, mu_1mx, y0m0, y0m1, y1m0, y1m1 = self._estimate_cross_conditional_mean_outcome_nesting( - m, x, y) + mu_0mx, mu_1mx, y0m0, y0m1, y1m0, y1m1 = ( + self._estimate_cross_conditional_mean_outcome_nesting(m, x, y) + ) # mean score computing eta_t1t1 = np.mean(y1m1) @@ -54,11 +49,11 @@ def estimate(self, t, m, x, y): indirect_effect_control = eta_t0t1 - eta_t0t0 causal_effects = { - 'total_effect': total_effect, - 'direct_effect_treated': direct_effect_treated, - 'direct_effect_control': direct_effect_control, - 'indirect_effect_treated': indirect_effect_treated, - 'indirect_effect_control': indirect_effect_control + "total_effect": total_effect, + "direct_effect_treated": direct_effect_treated, + "direct_effect_control": direct_effect_control, + "indirect_effect_treated": indirect_effect_treated, + "indirect_effect_control": indirect_effect_control, } return causal_effects diff --git a/src/med_bench/estimation/mediation_ipw.py b/src/med_bench/estimation/mediation_ipw.py index 16294f7..2aaec46 100644 --- a/src/med_bench/estimation/mediation_ipw.py +++ b/src/med_bench/estimation/mediation_ipw.py @@ -19,9 +19,7 @@ def __init__(self, clip: float, trim: float, **kwargs): self._trim = trim def fit(self, t, m, x, y): - """Fits nuisance parameters to data - - """ + """Fits nuisance parameters to data""" t, m, x, y = self._resize(t, m, x, y) self._fit_treatment_propensity_x_nuisance(t, x) @@ -36,13 +34,11 @@ def fit(self, t, m, x, y): @fitted def estimate(self, t, m, x, y): - """Estimates causal effect on data - - """ + """Estimates causal effect on data""" t, m, x, y = self._resize(t, m, x, y) p_x, p_xm = self._estimate_treatment_probabilities(t, m, x) - ind = ((p_xm > self._trim) & (p_xm < (1 - self._trim))) + ind = (p_xm > self._trim) & (p_xm < (1 - self._trim)) y, t, p_x, p_xm = y[ind], t[ind], p_x[ind], p_xm[ind] # note on the names, ytmt' = Y(t, M(t')), the treatment needs to be @@ -52,12 +48,13 @@ def estimate(self, t, m, x, y): # importance weighting y1m1 = np.sum(y * t / p_x) / np.sum(t / p_x) - y1m0 = np.sum(y * t * (1 - p_xm) / (p_xm * (1 - p_x))) /\ - np.sum(t * (1 - p_xm) / (p_xm * (1 - p_x))) - y0m0 = np.sum(y * (1 - t) / (1 - p_x)) /\ - np.sum((1 - t) / (1 - p_x)) - y0m1 = np.sum(y * (1 - t) * p_xm / ((1 - p_xm) * p_x)) /\ - np.sum((1 - t) * p_xm / ((1 - p_xm) * p_x)) + y1m0 = np.sum(y * t * (1 - p_xm) / (p_xm * (1 - p_x))) / np.sum( + t * (1 - p_xm) / (p_xm * (1 - p_x)) + ) + y0m0 = np.sum(y * (1 - t) / (1 - p_x)) / np.sum((1 - t) / (1 - p_x)) + y0m1 = np.sum(y * (1 - t) * p_xm / ((1 - p_xm) * p_x)) / np.sum( + (1 - t) * p_xm / ((1 - p_xm) * p_x) + ) total_effect = y1m1 - y0m0 direct_effect_treated = y1m1 - y0m1 @@ -66,11 +63,11 @@ def estimate(self, t, m, x, y): indirect_effect_control = y0m1 - y0m0 causal_effects = { - 'total_effect': total_effect, - 'direct_effect_treated': direct_effect_treated, - 'direct_effect_control': direct_effect_control, - 'indirect_effect_treated': indirect_effect_treated, - 'indirect_effect_control': indirect_effect_control + "total_effect": total_effect, + "direct_effect_treated": direct_effect_treated, + "direct_effect_control": direct_effect_control, + "indirect_effect_treated": indirect_effect_treated, + "indirect_effect_control": indirect_effect_control, } return causal_effects diff --git a/src/med_bench/estimation/mediation_mr.py b/src/med_bench/estimation/mediation_mr.py index 655768e..2f9696f 100644 --- a/src/med_bench/estimation/mediation_mr.py +++ b/src/med_bench/estimation/mediation_mr.py @@ -6,33 +6,33 @@ class MultiplyRobust(Estimator): - """Implementation of multiply robust estimator - """ + """Implementation of multiply robust estimator""" def __init__(self, ratio: str, clip: float, normalized, **kwargs): super().__init__(**kwargs) - assert ratio in ['density', 'propensities'] + assert ratio in ["density", "propensities"] self._ratio = ratio self._clip = clip self._normalized = normalized def fit(self, t, m, x, y): - """Fits nuisance parameters to data - """ + """Fits nuisance parameters to data""" t, m, x, y = self._resize(t, m, x, y) - if self._ratio == 'density' and is_array_integer(m): + if self._ratio == "density" and is_array_integer(m): self._fit_treatment_propensity_x_nuisance(t, x) self._fit_mediator_nuisance(t, m, x) - elif self._ratio == 'propensities': + elif self._ratio == "propensities": self._fit_treatment_propensity_x_nuisance(t, x) self._fit_treatment_propensity_xm_nuisance(t, m, x) - elif self._ratio == 'density' and not is_array_integer(m): - raise NotImplementedError("""Continuous mediator cannot use the density ratio method, - use a discrete mediator or set the ratio to 'propensities'""") + elif self._ratio == "density" and not is_array_integer(m): + raise NotImplementedError( + """Continuous mediator cannot use the density ratio method, + use a discrete mediator or set the ratio to 'propensities'""" + ) self._fit_cross_conditional_mean_outcome_nuisance(t, m, x, y) @@ -45,25 +45,24 @@ def fit(self, t, m, x, y): @fitted def estimate(self, t, m, x, y): - """Estimates causal effect on data - - """ + """Estimates causal effect on data""" # Format checking t, m, x, y = self._resize(t, m, x, y) - if self._ratio == 'density': + if self._ratio == "density": f_m0x, f_m1x = self._estimate_mediator_probability(t, m, x, y) p_x = self._estimate_treatment_propensity_x(t, m, x) ratio_t1_m0 = f_m0x / (p_x * f_m1x) ratio_t0_m1 = f_m1x / ((1 - p_x) * f_m0x) - elif self._ratio == 'propensities': + elif self._ratio == "propensities": p_x, p_xm = self._estimate_treatment_probabilities(t, m, x) - ratio_t1_m0 = (1-p_xm) / ((1 - p_x) * p_xm) + ratio_t1_m0 = (1 - p_xm) / ((1 - p_x) * p_xm) ratio_t0_m1 = p_xm / ((1 - p_xm) * p_x) mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 = ( - self._estimate_cross_conditional_mean_outcome_nesting(m, x, y)) + self._estimate_cross_conditional_mean_outcome_nesting(m, x, y) + ) # score computing if self._normalized: @@ -73,21 +72,17 @@ def estimate(self, t, m, x, y): sum_score_t0m1 = np.mean((1 - t) * ratio_t0_m1) y1m1 = (t / p_x * (y - E_mu_t1_t1)) / sum_score_m1 + E_mu_t1_t1 - y0m0 = (((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / sum_score_m0 - + E_mu_t0_t0) + y0m0 = ((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / sum_score_m0 + E_mu_t0_t0 y1m0 = ( - (t * ratio_t1_m0 * ( - y - mu_1mx)) / sum_score_t1m0 - + ((1 - t) / (1 - p_x) * ( - mu_1mx - E_mu_t1_t0)) / sum_score_m0 + (t * ratio_t1_m0 * (y - mu_1mx)) / sum_score_t1m0 + + ((1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0)) / sum_score_m0 + E_mu_t1_t0 ) y0m1 = ( - ((1 - t) * ratio_t0_m1 * (y - mu_0mx)) - / sum_score_t0m1 + t / p_x * ( - mu_0mx - E_mu_t0_t1) / sum_score_m1 + ((1 - t) * ratio_t0_m1 * (y - mu_0mx)) / sum_score_t0m1 + + t / p_x * (mu_0mx - E_mu_t0_t1) / sum_score_m1 + E_mu_t0_t1 ) else: @@ -113,10 +108,10 @@ def estimate(self, t, m, x, y): indirect0 = np.mean(y0m1 - y0m0) causal_effects = { - 'total_effect': total, - 'direct_effect_treated': direct1, - 'direct_effect_control': direct0, - 'indirect_effect_treated': indirect1, - 'indirect_effect_control': indirect0 + "total_effect": total, + "direct_effect_treated": direct1, + "direct_effect_control": direct0, + "indirect_effect_treated": indirect1, + "indirect_effect_control": indirect0, } return causal_effects diff --git a/src/med_bench/estimation/mediation_tmle.py b/src/med_bench/estimation/mediation_tmle.py index 21de660..6e99d66 100644 --- a/src/med_bench/estimation/mediation_tmle.py +++ b/src/med_bench/estimation/mediation_tmle.py @@ -38,52 +38,58 @@ def _one_step_correction_direct(self, t, m, x, y): t1 = np.ones((n)) # estimate mediator densities - if self._ratio == 'density': + if self._ratio == "density": f_m0x, f_m1x = self._estimate_mediator_probability(t, m, x, y) p_x = self._estimate_treatment_propensity_x(t, m, x) ratio = f_m0x / (p_x * f_m1x) - elif self._ratio == 'propensities': + elif self._ratio == "propensities": p_x, p_xm = self._estimate_treatment_probabilities(t, m, x) - ratio = (1-p_xm) / ((1 - p_x) * p_xm) + ratio = (1 - p_xm) / ((1 - p_x) * p_xm) - h_corrector = t * ratio - (1 - t)/(1 - p_x) + h_corrector = t * ratio - (1 - t) / (1 - p_x) x_t_mr = np.hstack( - [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t, m]]) + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t, m]] + ) mu_tmx = self._regressor_y.predict(x_t_mr) # import pdb; pdb.set_trace() reg = LinearRegression(fit_intercept=False).fit( - h_corrector.reshape(-1, 1), (y-mu_tmx).squeeze()) + h_corrector.reshape(-1, 1), (y - mu_tmx).squeeze() + ) epsilon_h = reg.coef_ # epsilon_h = 0 print(epsilon_h) x_t0_m = np.hstack( - [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t0, m]]) + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t0, m]] + ) x_t1_m = np.hstack( - [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t1, m]]) + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t1, m]] + ) mu_t0_mx = self._regressor_y.predict(x_t0_m) - h_corrector_t0 = t0 * ratio - (1 - t0)/(1 - p_x) + h_corrector_t0 = t0 * ratio - (1 - t0) / (1 - p_x) mu_t1_mx = self._regressor_y.predict(x_t1_m) - h_corrector_t1 = t1 * ratio - (1 - t1)/(1 - p_x) + h_corrector_t1 = t1 * ratio - (1 - t1) / (1 - p_x) mu_t0_mx_star = mu_t0_mx + epsilon_h * h_corrector_t0 mu_t1_mx_star = mu_t1_mx + epsilon_h * h_corrector_t1 - regressor_y = _get_regressor(self._regularize, - self._use_forest) + regressor_y = _get_regressor(self._regularize, self._use_forest) reg_cross = clone(regressor_y) - reg_cross.fit(x[t == 0], (mu_t1_mx_star[t == 0] - - mu_t0_mx_star[t == 0]).squeeze()) + reg_cross.fit( + x[t == 0], (mu_t1_mx_star[t == 0] - mu_t0_mx_star[t == 0]).squeeze() + ) theta_0 = reg_cross.predict(x) - c_corrector = (1 - t)/(1 - p_x) + c_corrector = (1 - t) / (1 - p_x) reg = LinearRegression(fit_intercept=False).fit( - c_corrector.reshape(-1, 1)[t == 0], (mu_t1_mx_star[t == 0] - y[t == 0]-theta_0[t == 0]).squeeze()) + c_corrector.reshape(-1, 1)[t == 0], + (mu_t1_mx_star[t == 0] - y[t == 0] - theta_0[t == 0]).squeeze(), + ) epsilon_c = reg.coef_ - theta_0_star = theta_0 + epsilon_c*c_corrector + theta_0_star = theta_0 + epsilon_c * c_corrector theta_0_star = np.mean(theta_0_star) return theta_0_star @@ -96,39 +102,41 @@ def _one_step_correction_indirect(self, t, m, x, y): t1 = np.ones((n)) # estimate mediator densities - if self._ratio == 'density': + if self._ratio == "density": f_m0x, f_m1x = self._estimate_mediator_probability(t, m, x, y) p_x = self._estimate_treatment_propensity_x(t, m, x) ratio = f_m0x / (p_x * f_m1x) - elif self._ratio == 'propensities': + elif self._ratio == "propensities": p_x, p_xm = self._estimate_treatment_probabilities(t, m, x) - ratio = (1-p_xm) / ((1 - p_x) * p_xm) + ratio = (1 - p_xm) / ((1 - p_x) * p_xm) h_corrector = t / p_x - t * ratio x_t_mr = np.hstack( - [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t, m]]) + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t, m]] + ) mu_tmx = self._regressor_y.predict(x_t_mr) reg = LinearRegression(fit_intercept=False).fit( - h_corrector.reshape(-1, 1), (y-mu_tmx).squeeze()) + h_corrector.reshape(-1, 1), (y - mu_tmx).squeeze() + ) epsilon_h = reg.coef_ # epsilon_h = 0 - print('indirect', epsilon_h) + print("indirect", epsilon_h) # mu_t0_mx = self._regressor_y.predict(_get_interactions(False, x, t0, m)) # h_corrector_t0 = t0 * f_t0 / (p_x * f_t1) - (1 - t0)/(1 - p_x) x_t1_m = np.hstack( - [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t1, m]]) + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t1, m]] + ) mu_t1_mx = self._regressor_y.predict(x_t1_m) h_corrector_t1 = t1 / p_x - t1 * ratio # mu_t0_mx_star = mu_t0_mx + epsilon_h * h_corrector_t0 mu_t1_mx_star = mu_t1_mx + epsilon_h * h_corrector_t1 - regressor_y = _get_regressor(self._regularize, - self._use_forest) + regressor_y = _get_regressor(self._regularize, self._use_forest) # reg_cross.fit(x, (mu_t1_mx_star).squeeze()) @@ -140,41 +148,42 @@ def _one_step_correction_indirect(self, t, m, x, y): reg_cross = clone(regressor_y) reg_cross.fit(x[t == 0], mu_t1_mx_star[t == 0]) omega_t0x = reg_cross.predict(x) - c_corrector_t0 = (2*t0 - 1) / p_x[:, None] + c_corrector_t0 = (2 * t0 - 1) / p_x[:, None] reg = LinearRegression(fit_intercept=False).fit( - c_corrector_t0[t == 0], (mu_t1_mx_star[t == 0]-omega_t0x[t == 0]).squeeze()) + c_corrector_t0[t == 0], + (mu_t1_mx_star[t == 0] - omega_t0x[t == 0]).squeeze(), + ) epsilon_c_t0 = reg.coef_ # epsilon_c_t0 = 0 - omega_t0x_star = omega_t0x + epsilon_c_t0*c_corrector_t0 + omega_t0x_star = omega_t0x + epsilon_c_t0 * c_corrector_t0 reg_cross = clone(regressor_y) reg_cross.fit(x[t == 1], y[t == 1]) omega_t1x = reg_cross.predict(x) - c_corrector_t1 = (2*t1 - 1) / p_x[:, None] + c_corrector_t1 = (2 * t1 - 1) / p_x[:, None] reg = LinearRegression(fit_intercept=False).fit( - c_corrector_t1[t == 1], (y[t == 1]-omega_t1x[t == 1]).squeeze()) + c_corrector_t1[t == 1], (y[t == 1] - omega_t1x[t == 1]).squeeze() + ) epsilon_c_t1 = reg.coef_ # epsilon_c_t1 = 0 - omega_t1x_star = omega_t1x + epsilon_c_t1*c_corrector_t1 + omega_t1x_star = omega_t1x + epsilon_c_t1 * c_corrector_t1 delta_1 = np.mean(omega_t1x_star - omega_t0x_star) return delta_1 def fit(self, t, m, x, y): - """Fits nuisance parameters to data - - """ + """Fits nuisance parameters to data""" # bucketize if needed t, m, x, y = self._resize(t, m, x, y) self._fit_treatment_propensity_x_nuisance(t, x) self._fit_conditional_mean_outcome_nuisance(t, m, x, y) - if self._ratio == 'density': + if self._ratio == "density": self._fit_mediator_nuisance(t, m, x) - elif self._ratio == 'propensities': + elif self._ratio == "propensities": self._fit_treatment_propensity_xm_nuisance(t, m, x) self._fitted = True @@ -186,9 +195,7 @@ def fit(self, t, m, x, y): @fitted def estimate(self, t, m, x, y): - """Estimates causal effect on data - - """ + """Estimates causal effect on data""" theta_0 = self._one_step_correction_direct(t, m, x, y) delta_1 = self._one_step_correction_indirect(t, m, x, y) total_effect = theta_0 + delta_1 @@ -198,10 +205,10 @@ def estimate(self, t, m, x, y): indirect_effect_control = np.copy(delta_1) causal_effects = { - 'total_effect': total_effect, - 'direct_effect_treated': direct_effect_treated, - 'direct_effect_control': direct_effect_control, - 'indirect_effect_treated': indirect_effect_treated, - 'indirect_effect_control': indirect_effect_control + "total_effect": total_effect, + "direct_effect_treated": direct_effect_treated, + "direct_effect_control": direct_effect_control, + "indirect_effect_treated": indirect_effect_treated, + "indirect_effect_control": indirect_effect_control, } return causal_effects diff --git a/src/med_bench/mediation.py b/src/med_bench/mediation.py index 7f3bf68..80cf592 100644 --- a/src/med_bench/mediation.py +++ b/src/med_bench/mediation.py @@ -12,21 +12,34 @@ from sklearn.linear_model import RidgeCV -from .utils.nuisances import (_estimate_conditional_mean_outcome, - _estimate_cross_conditional_mean_outcome, - _estimate_cross_conditional_mean_outcome_nesting, - _estimate_mediator_density, - _estimate_treatment_probabilities, - _get_classifier, _get_regressor) +from .utils.nuisances import ( + _estimate_conditional_mean_outcome, + _estimate_cross_conditional_mean_outcome, + _estimate_cross_conditional_mean_outcome_nesting, + _estimate_mediator_density, + _estimate_treatment_probabilities, + _get_classifier, + _get_regressor, +) from .utils.utils import r_dependency_required, _check_input ALPHAS = np.logspace(-5, 5, 8) CV_FOLDS = 5 -TINY = 1.e-12 - - -def mediation_IPW(y, t, m, x, trim=0.05, regularization=True, forest=False, - crossfit=0, clip=1e-6, calibration='sigmoid'): +TINY = 1.0e-12 + + +def mediation_IPW( + y, + t, + m, + x, + trim=0.05, + regularization=True, + forest=False, + crossfit=0, + clip=1e-6, + calibration="sigmoid", +): """ IPW estimator presented in HUBER, Martin. Identifying causal mechanisms (primarily) based on inverse @@ -91,18 +104,18 @@ def mediation_IPW(y, t, m, x, trim=0.05, regularization=True, forest=False, number of used observations (non trimmed) """ # check input - y, t, m, x = _check_input(y, t, m, x, setting='multidimensional') + y, t, m, x = _check_input(y, t, m, x, setting="multidimensional") # estimate propensities classifier_t_x = _get_classifier(regularization, forest, calibration) classifier_t_xm = _get_classifier(regularization, forest, calibration) - p_x, p_xm = _estimate_treatment_probabilities(t, m, x, crossfit, - classifier_t_x, - classifier_t_xm) + p_x, p_xm = _estimate_treatment_probabilities( + t, m, x, crossfit, classifier_t_x, classifier_t_xm + ) - # trimming. Following causal weight code, not sure I understand + # trimming. Following causal weight code, not sure I understand # why we trim only on p_xm and not on p_x - ind = ((p_xm > trim) & (p_xm < (1 - trim))) + ind = (p_xm > trim) & (p_xm < (1 - trim)) y, t, p_x, p_xm = y[ind], t[ind], p_x[ind], p_xm[ind] # note on the names, ytmt' = Y(t, M(t')), the treatment needs to be @@ -112,23 +125,25 @@ def mediation_IPW(y, t, m, x, trim=0.05, regularization=True, forest=False, # importance weighting y1m1 = np.sum(y * t / p_x) / np.sum(t / p_x) - y1m0 = np.sum(y * t * (1 - p_xm) / (p_xm * (1 - p_x))) /\ - np.sum(t * (1 - p_xm) / (p_xm * (1 - p_x))) - y0m0 = np.sum(y * (1 - t) / (1 - p_x)) /\ - np.sum((1 - t) / (1 - p_x)) - y0m1 = np.sum(y * (1 - t) * p_xm / ((1 - p_xm) * p_x)) /\ - np.sum((1 - t) * p_xm / ((1 - p_xm) * p_x)) - - return (y1m1 - y0m0, - y1m1 - y0m1, - y1m0 - y0m0, - y1m1 - y1m0, - y0m1 - y0m0, - np.sum(ind)) - - -def mediation_coefficient_product(y, t, m, x, interaction=False, - regularization=True): + y1m0 = np.sum(y * t * (1 - p_xm) / (p_xm * (1 - p_x))) / np.sum( + t * (1 - p_xm) / (p_xm * (1 - p_x)) + ) + y0m0 = np.sum(y * (1 - t) / (1 - p_x)) / np.sum((1 - t) / (1 - p_x)) + y0m1 = np.sum(y * (1 - t) * p_xm / ((1 - p_xm) * p_x)) / np.sum( + (1 - t) * p_xm / ((1 - p_xm) * p_x) + ) + + return ( + y1m1 - y0m0, + y1m1 - y0m1, + y1m0 - y0m0, + y1m1 - y1m0, + y0m1 - y0m0, + np.sum(ind), + ) + + +def mediation_coefficient_product(y, t, m, x, interaction=False, regularization=True): """ found an R implementation https://cran.r-project.org/package=regmedint @@ -184,33 +199,41 @@ def mediation_coefficient_product(y, t, m, x, interaction=False, alphas = [TINY] # check input - y, t, m, x = _check_input(y, t, m, x, setting='multidimensional') + y, t, m, x = _check_input(y, t, m, x, setting="multidimensional") if len(t.shape) == 1: t = t.reshape(-1, 1) coef_t_m = np.zeros(m.shape[1]) for i in range(m.shape[1]): - m_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS)\ - .fit(np.hstack((x, t)), m[:, i]) + m_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit(np.hstack((x, t)), m[:, i]) coef_t_m[i] = m_reg.coef_[-1] - y_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS)\ - .fit(np.hstack((x, t, m)), y.ravel()) + y_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit(np.hstack((x, t, m)), y.ravel()) # return total, direct and indirect effect direct_effect = y_reg.coef_[x.shape[1]] - indirect_effect = sum(y_reg.coef_[x.shape[1] + 1:] * coef_t_m) - return (direct_effect + indirect_effect, - direct_effect, - direct_effect, - indirect_effect, - indirect_effect, - None) - - -def mediation_g_formula(y, t, m, x, interaction=False, forest=False, - crossfit=0, regularization=True, - calibration='sigmoid'): + indirect_effect = sum(y_reg.coef_[x.shape[1] + 1 :] * coef_t_m) + return ( + direct_effect + indirect_effect, + direct_effect, + direct_effect, + indirect_effect, + indirect_effect, + None, + ) + + +def mediation_g_formula( + y, + t, + m, + x, + interaction=False, + forest=False, + crossfit=0, + regularization=True, + calibration="sigmoid", +): """ Warning : m needs to be binary @@ -253,43 +276,48 @@ def mediation_g_formula(y, t, m, x, interaction=False, forest=False, calibration mode; for example using a sigmoid function """ # check input - y, t, m, x = _check_input(y, t, m, x, setting='binary') + y, t, m, x = _check_input(y, t, m, x, setting="binary") # estimate mediator densities classifier_m = _get_classifier(regularization, forest, calibration) - f_00x, f_01x, f_10x, f_11x, _, _ = _estimate_mediator_density(y, t, m, x, - crossfit, - classifier_m, - interaction) + f_00x, f_01x, f_10x, f_11x, _, _ = _estimate_mediator_density( + y, t, m, x, crossfit, classifier_m, interaction + ) # estimate conditional mean outcomes regressor_y = _get_regressor(regularization, forest) - mu_00x, mu_01x, mu_10x, mu_11x, _, _ = ( - _estimate_conditional_mean_outcome(y, t, m, x, crossfit, regressor_y, - interaction)) + mu_00x, mu_01x, mu_10x, mu_11x, _, _ = _estimate_conditional_mean_outcome( + y, t, m, x, crossfit, regressor_y, interaction + ) # G computation direct_effect_i1 = mu_11x - mu_01x direct_effect_i0 = mu_10x - mu_00x n = len(y) - direct_effect_treated = (direct_effect_i1 * f_11x - + direct_effect_i0 * f_10x).sum() / n - direct_effect_control = (direct_effect_i1 * f_01x - + direct_effect_i0 * f_00x).sum() / n + direct_effect_treated = ( + direct_effect_i1 * f_11x + direct_effect_i0 * f_10x + ).sum() / n + direct_effect_control = ( + direct_effect_i1 * f_01x + direct_effect_i0 * f_00x + ).sum() / n indirect_effect_i1 = f_11x - f_01x indirect_effect_i0 = f_10x - f_00x - indirect_effect_treated = (indirect_effect_i1 * mu_11x - + indirect_effect_i0 * mu_10x).sum() / n - indirect_effect_control = (indirect_effect_i1 * mu_01x - + indirect_effect_i0 * mu_00x).sum() / n + indirect_effect_treated = ( + indirect_effect_i1 * mu_11x + indirect_effect_i0 * mu_10x + ).sum() / n + indirect_effect_control = ( + indirect_effect_i1 * mu_01x + indirect_effect_i0 * mu_00x + ).sum() / n total_effect = direct_effect_control + indirect_effect_treated - return (total_effect, - direct_effect_treated, - direct_effect_control, - indirect_effect_treated, - indirect_effect_control, - None) + return ( + total_effect, + direct_effect_treated, + direct_effect_control, + indirect_effect_treated, + indirect_effect_control, + None, + ) def alternative_estimator(y, t, m, x, regularization=True): @@ -328,40 +356,52 @@ def alternative_estimator(y, t, m, x, regularization=True): alphas = [TINY] # check input - y, t, m, x = _check_input(y, t, m, x, setting='multidimensional') - treated = (t == 1) + y, t, m, x = _check_input(y, t, m, x, setting="multidimensional") + treated = t == 1 # computation of direct effect y_treated_reg_m = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit( - np.hstack((x[treated], m[treated])), y[treated]) + np.hstack((x[treated], m[treated])), y[treated] + ) y_ctrl_reg_m = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit( - np.hstack((x[~treated], m[~treated])), y[~treated]) + np.hstack((x[~treated], m[~treated])), y[~treated] + ) xm = np.hstack((x, m)) - direct_effect = np.sum(y_treated_reg_m.predict(xm) - - y_ctrl_reg_m.predict(xm)) / len(y) + direct_effect = np.sum( + y_treated_reg_m.predict(xm) - y_ctrl_reg_m.predict(xm) + ) / len(y) # computation of total effect - y_treated_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit( - x[treated], y[treated]) - y_ctrl_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit( - x[~treated], y[~treated]) - total_effect = np.sum(y_treated_reg.predict(x) - - y_ctrl_reg.predict(x)) / len(y) + y_treated_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit(x[treated], y[treated]) + y_ctrl_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit(x[~treated], y[~treated]) + total_effect = np.sum(y_treated_reg.predict(x) - y_ctrl_reg.predict(x)) / len(y) # computation of indirect effect indirect_effect = total_effect - direct_effect - return (total_effect, - direct_effect, - direct_effect, - indirect_effect, - indirect_effect, - None) + return ( + total_effect, + direct_effect, + direct_effect, + indirect_effect, + indirect_effect, + None, + ) -def mediation_multiply_robust(y, t, m, x, interaction=False, forest=False, - crossfit=0, clip=1e-6, normalized=True, - regularization=True, calibration="sigmoid"): +def mediation_multiply_robust( + y, + t, + m, + x, + interaction=False, + forest=False, + crossfit=0, + clip=1e-6, + normalized=True, + regularization=True, + calibration="sigmoid", +): """ Presented in Eric J. Tchetgen Tchetgen. Ilya Shpitser. "Semiparametric theory for causal mediation analysis: Efficiency bounds, @@ -440,29 +480,29 @@ def mediation_multiply_robust(y, t, m, x, interaction=False, forest=False, - If m is not binary. """ # check input - y, t, m, x = _check_input(y, t, m, x, setting='binary') + y, t, m, x = _check_input(y, t, m, x, setting="binary") # estimate propensities classifier_t_x = _get_classifier(regularization, forest, calibration) - p_x, _ = _estimate_treatment_probabilities(t, m, x, crossfit, - classifier_t_x, - clone(classifier_t_x)) + p_x, _ = _estimate_treatment_probabilities( + t, m, x, crossfit, classifier_t_x, clone(classifier_t_x) + ) # estimate mediator densities classifier_m = _get_classifier(regularization, forest, calibration) - f_00x, f_01x, f_10x, f_11x, f_m0x, f_m1x = ( - _estimate_mediator_density(y, t, m, x, crossfit, - classifier_m, interaction)) + f_00x, f_01x, f_10x, f_11x, f_m0x, f_m1x = _estimate_mediator_density( + y, t, m, x, crossfit, classifier_m, interaction + ) f = f_00x, f_01x, f_10x, f_11x # estimate conditional mean outcomes regressor_y = _get_regressor(regularization, forest) regressor_cross_y = _get_regressor(regularization, forest) mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 = ( - _estimate_cross_conditional_mean_outcome(y, t, m, x, crossfit, - regressor_y, - regressor_cross_y, f, - interaction)) + _estimate_cross_conditional_mean_outcome( + y, t, m, x, crossfit, regressor_y, regressor_cross_y, f, interaction + ) + ) # clipping p_x_clip = p_x != np.clip(p_x, clip, 1 - clip) @@ -485,17 +525,15 @@ def mediation_multiply_robust(y, t, m, x, interaction=False, forest=False, sum_score_t0m1 = np.mean((1 - t) / (1 - p_x) * (f_m1x / f_m0x)) y1m1 = (t / p_x * (y - E_mu_t1_t1)) / sum_score_m1 + E_mu_t1_t1 - y0m0 = (((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / sum_score_m0 - + E_mu_t0_t0) + y0m0 = ((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / sum_score_m0 + E_mu_t0_t0 y1m0 = ( ((t / p_x) * (f_m0x / f_m1x) * (y - mu_1mx)) / sum_score_t1m0 + ((1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0)) / sum_score_m0 + E_mu_t1_t0 ) y0m1 = ( - ((1 - t) / (1 - p_x) * (f_m1x / f_m0x) * (y - mu_0mx)) - / sum_score_t0m1 + t / p_x * ( - mu_0mx - E_mu_t0_t1) / sum_score_m1 + ((1 - t) / (1 - p_x) * (f_m1x / f_m0x) * (y - mu_0mx)) / sum_score_t0m1 + + t / p_x * (mu_0mx - E_mu_t0_t1) / sum_score_m1 + E_mu_t0_t1 ) else: @@ -522,7 +560,7 @@ def mediation_multiply_robust(y, t, m, x, interaction=False, forest=False, return total, direct1, direct0, indirect1, indirect0, n_discarded -@r_dependency_required(['mediation', 'stats', 'base']) +@r_dependency_required(["mediation", "stats", "base"]) def r_mediate(y, t, m, x, interaction=False): """ This function calls the R function mediate from the package mediation @@ -555,52 +593,50 @@ def r_mediate(y, t, m, x, interaction=False): pandas2ri.activate() numpy2ri.activate() - mediation = rpackages.importr('mediation') - Rstats = rpackages.importr('stats') - base = rpackages.importr('base') + mediation = rpackages.importr("mediation") + Rstats = rpackages.importr("stats") + base = rpackages.importr("base") # check input - y, t, m, x = _check_input(y, t, m, x, setting='binary') + y, t, m, x = _check_input(y, t, m, x, setting="binary") m = m.ravel() - var_names = [[y, 'y'], - [t, 't'], - [m, 'm'], - [x, 'x']] + var_names = [[y, "y"], [t, "t"], [m, "m"], [x, "x"]] df_list = list() for var, name in var_names: if len(var.shape) > 1: var_dim = var.shape[1] - col_names = ['{}_{}'.format(name, i) for i in range(var_dim)] + col_names = ["{}_{}".format(name, i) for i in range(var_dim)] sub_df = pd.DataFrame(var, columns=col_names) else: sub_df = pd.DataFrame(var, columns=[name]) df_list.append(sub_df) df = pd.concat(df_list, axis=1) - m_features = [c for c in df.columns if ('y' not in c) and ('m' not in c)] - y_features = [c for c in df.columns if ('y' not in c)] + m_features = [c for c in df.columns if ("y" not in c) and ("m" not in c)] + y_features = [c for c in df.columns if ("y" not in c)] if not interaction: - m_formula = 'm ~ ' + ' + '.join(m_features) - y_formula = 'y ~ ' + ' + '.join(y_features) + m_formula = "m ~ " + " + ".join(m_features) + y_formula = "y ~ " + " + ".join(y_features) else: - m_formula = 'm ~ ' + ' + '.join(m_features + - [':'.join(p) for p in - combinations(m_features, 2)]) - y_formula = 'y ~ ' + ' + '.join(y_features + - [':'.join(p) for p in - combinations(y_features, 2)]) - robjects.globalenv['df'] = df - mediator_model = Rstats.lm(m_formula, data=base.as_symbol('df')) - outcome_model = Rstats.lm(y_formula, data=base.as_symbol('df')) - res = mediation.mediate(mediator_model, outcome_model, treat='t', - mediator='m', boot=True, sims=1) - - relevant_variables = ['tau.coef', 'z1', 'z0', 'd1', 'd0'] + m_formula = "m ~ " + " + ".join( + m_features + [":".join(p) for p in combinations(m_features, 2)] + ) + y_formula = "y ~ " + " + ".join( + y_features + [":".join(p) for p in combinations(y_features, 2)] + ) + robjects.globalenv["df"] = df + mediator_model = Rstats.lm(m_formula, data=base.as_symbol("df")) + outcome_model = Rstats.lm(y_formula, data=base.as_symbol("df")) + res = mediation.mediate( + mediator_model, outcome_model, treat="t", mediator="m", boot=True, sims=1 + ) + + relevant_variables = ["tau.coef", "z1", "z0", "d1", "d0"] to_return = [np.array(res.rx2(v))[0] for v in relevant_variables] return to_return + [None] -@r_dependency_required(['plmed', 'base']) +@r_dependency_required(["plmed", "base"]) def r_mediation_g_estimator(y, t, m, x): """ This function calls the R G-estimator from the package plmed @@ -614,50 +650,51 @@ def r_mediation_g_estimator(y, t, m, x): pandas2ri.activate() numpy2ri.activate() - plmed = rpackages.importr('plmed') - base = rpackages.importr('base') + plmed = rpackages.importr("plmed") + base = rpackages.importr("base") # check input - y, t, m, x = _check_input(y, t, m, x, setting='binary') + y, t, m, x = _check_input(y, t, m, x, setting="binary") m = m.ravel() - var_names = [[y, 'y'], - [t, 't'], - [m, 'm'], - [x, 'x']] + var_names = [[y, "y"], [t, "t"], [m, "m"], [x, "x"]] df_list = list() for var, name in var_names: if len(var.shape) > 1: var_dim = var.shape[1] - col_names = ['{}_{}'.format(name, i) for i in range(var_dim)] + col_names = ["{}_{}".format(name, i) for i in range(var_dim)] sub_df = pd.DataFrame(var, columns=col_names) else: sub_df = pd.DataFrame(var, columns=[name]) df_list.append(sub_df) df = pd.concat(df_list, axis=1) - m_features = [c for c in df.columns if ('x' in c)] - y_features = [c for c in df.columns if ('x' in c)] - t_features = [c for c in df.columns if ('x' in c)] - m_formula = 'm ~ ' + ' + '.join(m_features) - y_formula = 'y ~ ' + ' + '.join(y_features) - t_formula = 't ~ ' + ' + '.join(t_features) - robjects.globalenv['df'] = df - res = plmed.G_estimation(t_formula, - m_formula, - y_formula, - exposure_family='binomial', - data=base.as_symbol('df')) - direct_effect = res.rx2('coef')[0] - indirect_effect = res.rx2('coef')[1] - return (direct_effect + indirect_effect, - direct_effect, - direct_effect, - indirect_effect, - indirect_effect, - None) - - -@r_dependency_required(['causalweight', 'base']) + m_features = [c for c in df.columns if ("x" in c)] + y_features = [c for c in df.columns if ("x" in c)] + t_features = [c for c in df.columns if ("x" in c)] + m_formula = "m ~ " + " + ".join(m_features) + y_formula = "y ~ " + " + ".join(y_features) + t_formula = "t ~ " + " + ".join(t_features) + robjects.globalenv["df"] = df + res = plmed.G_estimation( + t_formula, + m_formula, + y_formula, + exposure_family="binomial", + data=base.as_symbol("df"), + ) + direct_effect = res.rx2("coef")[0] + indirect_effect = res.rx2("coef")[1] + return ( + direct_effect + indirect_effect, + direct_effect, + direct_effect, + indirect_effect, + indirect_effect, + None, + ) + + +@r_dependency_required(["causalweight", "base"]) def r_mediation_dml(y, t, m, x, trim=0.05, order=1): """ This function calls the R Double Machine Learning estimator from the @@ -701,23 +738,35 @@ def r_mediation_dml(y, t, m, x, trim=0.05, order=1): pandas2ri.activate() numpy2ri.activate() - causalweight = rpackages.importr('causalweight') - base = rpackages.importr('base') + causalweight = rpackages.importr("causalweight") + base = rpackages.importr("base") # check input - y, t, m, x = _check_input(y, t, m, x, setting='multidimensional') + y, t, m, x = _check_input(y, t, m, x, setting="multidimensional") - x_r, t_r, m_r, y_r = [base.as_matrix(_convert_array_to_R(uu)) for uu in - (x, t, m, y)] + x_r, t_r, m_r, y_r = [ + base.as_matrix(_convert_array_to_R(uu)) for uu in (x, t, m, y) + ] res = causalweight.medDML(y_r, t_r, m_r, x_r, trim=trim, order=order) - raw_res_R = np.array(res.rx2('results')) - ntrimmed = res.rx2('ntrimmed')[0] + raw_res_R = np.array(res.rx2("results")) + ntrimmed = res.rx2("ntrimmed")[0] return list(raw_res_R[0, :5]) + [ntrimmed] -def mediation_dml(y, t, m, x, forest=False, crossfit=0, trim=0.05, clip=1e-6, - normalized=True, regularization=True, random_state=None, - calibration=None): +def mediation_dml( + y, + t, + m, + x, + forest=False, + crossfit=0, + trim=0.05, + clip=1e-6, + normalized=True, + regularization=True, + random_state=None, + calibration=None, +): """ Python implementation of Double Machine Learning procedure, as described in : @@ -800,7 +849,7 @@ def mediation_dml(y, t, m, x, forest=False, crossfit=0, trim=0.05, clip=1e-6, - If x, t, m, or y don't have the same length. """ # check input - y, t, m, x = _check_input(y, t, m, x, setting='multidimensional') + y, t, m, x = _check_input(y, t, m, x, setting="multidimensional") n = len(y) nobs = 0 @@ -819,18 +868,19 @@ def mediation_dml(y, t, m, x, forest=False, crossfit=0, trim=0.05, clip=1e-6, # estimate propensities classifier_t_x = _get_classifier(regularization, forest, calibration) classifier_t_xm = _get_classifier(regularization, forest, calibration) - p_x, p_xm = _estimate_treatment_probabilities(t, m, x, crossfit, - classifier_t_x, - classifier_t_xm) + p_x, p_xm = _estimate_treatment_probabilities( + t, m, x, crossfit, classifier_t_x, classifier_t_xm + ) # estimate conditional mean outcomes regressor_y = _get_regressor(regularization, forest) regressor_cross_y = _get_regressor(regularization, forest) mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 = ( - _estimate_cross_conditional_mean_outcome_nesting(y, t, m, x, crossfit, - regressor_y, - regressor_cross_y)) + _estimate_cross_conditional_mean_outcome_nesting( + y, t, m, x, crossfit, regressor_y, regressor_cross_y + ) + ) # trimming not_trimmed = ( @@ -854,16 +904,14 @@ def mediation_dml(y, t, m, x, forest=False, crossfit=0, trim=0.05, clip=1e-6, sum_score_t1m0 = np.mean(t * (1 - p_xm) / (p_xm * (1 - p_x))) sum_score_t0m1 = np.mean((1 - t) * p_xm / ((1 - p_xm) * p_x)) y1m1 = (t / p_x * (y - E_mu_t1_t1)) / sum_score_m1 + E_mu_t1_t1 - y0m0 = (((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / sum_score_m0 - + E_mu_t0_t0) + y0m0 = ((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / sum_score_m0 + E_mu_t0_t0 y1m0 = ( - (t * (1 - p_xm) / (p_xm * (1 - p_x)) * (y - mu_1mx)) - / sum_score_t1m0 + ((1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0)) - / sum_score_m0 + E_mu_t1_t0 + (t * (1 - p_xm) / (p_xm * (1 - p_x)) * (y - mu_1mx)) / sum_score_t1m0 + + ((1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0)) / sum_score_m0 + + E_mu_t1_t0 ) y0m1 = ( - ((1 - t) * p_xm / ((1 - p_xm) * p_x) * (y - mu_0mx)) - / sum_score_t0m1 + ((1 - t) * p_xm / ((1 - p_xm) * p_x) * (y - mu_0mx)) / sum_score_t0m1 + (t / p_x * (mu_0mx - E_mu_t0_t1)) / sum_score_m1 + E_mu_t0_t1 ) diff --git a/src/med_bench/nuisances/conditional_outcome.py b/src/med_bench/nuisances/conditional_outcome.py index 5df10ad..72adc1a 100644 --- a/src/med_bench/nuisances/conditional_outcome.py +++ b/src/med_bench/nuisances/conditional_outcome.py @@ -8,8 +8,9 @@ from med_bench.utils.utils import _get_train_test_lists, _get_interactions -def estimate_conditional_mean_outcome(t, m, x, y, crossfit, reg_y, - interaction, fit=False): +def estimate_conditional_mean_outcome( + t, m, x, y, crossfit, reg_y, interaction, fit=False +): """ Estimate conditional mean outcome E[Y|T,M,X] with train test lists from crossfitting @@ -67,13 +68,13 @@ def estimate_conditional_mean_outcome(t, m, x, y, crossfit, reg_y, # predict E[Y|T=t,M=m,X] mu_0bx[test_index] = reg_y.predict( - _get_interactions(interaction, x, t0, mb)[test_index, - :]).squeeze() + _get_interactions(interaction, x, t0, mb)[test_index, :] + ).squeeze() mu_1bx[test_index] = reg_y.predict( - _get_interactions(interaction, x, t1, mb)[test_index, - :]).squeeze() + _get_interactions(interaction, x, t1, mb)[test_index, :] + ).squeeze() mu_t0.append(mu_0bx) mu_t1.append(mu_1bx) - return mu_t0, mu_t1, mu_0mx, mu_1mx \ No newline at end of file + return mu_t0, mu_t1, mu_0mx, mu_1mx diff --git a/src/med_bench/nuisances/cross_conditional_outcome.py b/src/med_bench/nuisances/cross_conditional_outcome.py index 9d7c3bd..1371f6e 100644 --- a/src/med_bench/nuisances/cross_conditional_outcome.py +++ b/src/med_bench/nuisances/cross_conditional_outcome.py @@ -9,6 +9,7 @@ from med_bench.utils.utils import _get_train_test_lists, _get_interactions + def estimate_cross_conditional_mean_outcome_discrete(m, x, y, f, regressors): """ Estimate the conditional mean outcome, @@ -53,8 +54,8 @@ def estimate_cross_conditional_mean_outcome_discrete(m, x, y, f, regressors): test_index = np.arange(n) # predict E[Y|T=t,M,X] - mu_1mx[test_index] = regressors['y_t_mx'].predict(x_t1_m[test_index, :]) - mu_0mx[test_index] = regressors['y_t_mx'].predict(x_t0_m[test_index, :]) + mu_1mx[test_index] = regressors["y_t_mx"].predict(x_t1_m[test_index, :]) + mu_0mx[test_index] = regressors["y_t_mx"].predict(x_t0_m[test_index, :]) for i, b in enumerate(np.unique(m)): @@ -62,28 +63,31 @@ def estimate_cross_conditional_mean_outcome_discrete(m, x, y, f, regressors): f_0bx, f_1bx = f_t0[i], f_t1[i] # predict E[E[Y|T=1,M=m,X]|T=t,X] - E_mu_t1_t0[test_index] += regressors['reg_y_t1m{}_t0'.format(i)].predict( - x[test_index, :]) * \ - f_0bx[test_index] - E_mu_t1_t1[test_index] += regressors['reg_y_t1m{}_t1'.format(i)].predict( - x[test_index, :]) * \ - f_1bx[test_index] + E_mu_t1_t0[test_index] += ( + regressors["reg_y_t1m{}_t0".format(i)].predict(x[test_index, :]) + * f_0bx[test_index] + ) + E_mu_t1_t1[test_index] += ( + regressors["reg_y_t1m{}_t1".format(i)].predict(x[test_index, :]) + * f_1bx[test_index] + ) # predict E[E[Y|T=0,M=m,X]|T=t,X] - E_mu_t0_t0[test_index] += regressors['reg_y_t0m{}_t0'.format(i)].predict( - x[test_index, :]) * \ - f_0bx[test_index] - E_mu_t0_t1[test_index] += regressors['reg_y_t0m{}_t1'.format(i)].predict( - x[test_index, :]) * \ - f_1bx[test_index] + E_mu_t0_t0[test_index] += ( + regressors["reg_y_t0m{}_t0".format(i)].predict(x[test_index, :]) + * f_0bx[test_index] + ) + E_mu_t0_t1[test_index] += ( + regressors["reg_y_t0m{}_t1".format(i)].predict(x[test_index, :]) + * f_1bx[test_index] + ) return mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 -def estimate_cross_conditional_mean_outcome(t, m, x, y, crossfit, - reg_y, - reg_cross_y, f, - interaction): +def estimate_cross_conditional_mean_outcome( + t, m, x, y, crossfit, reg_y, reg_cross_y, f, interaction +): """ Estimate the conditional mean outcome, the cross conditional mean outcome @@ -148,33 +152,43 @@ def estimate_cross_conditional_mean_outcome(t, m, x, y, crossfit, # predict E[Y|T=t,M=m,X] mu_0bx[test_index] = reg_y.predict( - _get_interactions(interaction, x, t0, mb)[test_index, :]) + _get_interactions(interaction, x, t0, mb)[test_index, :] + ) mu_1bx[test_index] = reg_y.predict( - _get_interactions(interaction, x, t1, mb)[test_index, :]) + _get_interactions(interaction, x, t1, mb)[test_index, :] + ) # E[E[Y|T=1,M=m,X]|T=t,X] model fitting - reg_y_t1mb_t0 = clone(reg_cross_y).fit(x[test_index, :][ind_t0, :], - mu_1bx[test_index][ind_t0]) + reg_y_t1mb_t0 = clone(reg_cross_y).fit( + x[test_index, :][ind_t0, :], mu_1bx[test_index][ind_t0] + ) reg_y_t1mb_t1 = clone(reg_cross_y).fit( - x[test_index, :][~ind_t0, :], mu_1bx[test_index][~ind_t0]) + x[test_index, :][~ind_t0, :], mu_1bx[test_index][~ind_t0] + ) # predict E[E[Y|T=1,M=m,X]|T=t,X] - E_mu_t1_t0[test_index] += reg_y_t1mb_t0.predict(x[test_index, :]) * \ - f_0bx[test_index] - E_mu_t1_t1[test_index] += reg_y_t1mb_t1.predict(x[test_index, :]) * \ - f_1bx[test_index] + E_mu_t1_t0[test_index] += ( + reg_y_t1mb_t0.predict(x[test_index, :]) * f_0bx[test_index] + ) + E_mu_t1_t1[test_index] += ( + reg_y_t1mb_t1.predict(x[test_index, :]) * f_1bx[test_index] + ) # E[E[Y|T=0,M=m,X]|T=t,X] model fitting - reg_y_t0mb_t0 = clone(reg_cross_y).fit(x[test_index, :][ind_t0, :], - mu_0bx[test_index][ind_t0]) + reg_y_t0mb_t0 = clone(reg_cross_y).fit( + x[test_index, :][ind_t0, :], mu_0bx[test_index][ind_t0] + ) reg_y_t0mb_t1 = clone(reg_cross_y).fit( - x[test_index, :][~ind_t0, :], mu_0bx[test_index][~ind_t0]) + x[test_index, :][~ind_t0, :], mu_0bx[test_index][~ind_t0] + ) # predict E[E[Y|T=0,M=m,X]|T=t,X] - E_mu_t0_t0[test_index] += reg_y_t0mb_t0.predict(x[test_index, :]) * \ - f_0bx[test_index] - E_mu_t0_t1[test_index] += reg_y_t0mb_t1.predict(x[test_index, :]) * \ - f_1bx[test_index] + E_mu_t0_t0[test_index] += ( + reg_y_t0mb_t0.predict(x[test_index, :]) * f_0bx[test_index] + ) + E_mu_t0_t1[test_index] += ( + reg_y_t0mb_t1.predict(x[test_index, :]) * f_1bx[test_index] + ) return mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 @@ -204,21 +218,21 @@ def estimate_cross_conditional_mean_outcome_nesting(m, x, y, regressors): xm = np.hstack((x, m)) # predict E[Y|T=1,M,X] - mu_1mx = regressors['y_t1_mx'].predict(xm) + mu_1mx = regressors["y_t1_mx"].predict(xm) # predict E[Y|T=0,M,X] - mu_0mx = regressors['y_t0_mx'].predict(xm) + mu_0mx = regressors["y_t0_mx"].predict(xm) # predict E[E[Y|T=1,M,X]|T=0,X] - E_mu_t1_t0 = regressors['y_t1_x_t0'].predict(x) + E_mu_t1_t0 = regressors["y_t1_x_t0"].predict(x) # predict E[E[Y|T=0,M,X]|T=1,X] - E_mu_t0_t1 = regressors['y_t0_x_t1'].predict(x) + E_mu_t0_t1 = regressors["y_t0_x_t1"].predict(x) # predict E[Y|T=1,X] - mu_1x = regressors['y_t1_x'].predict(x) + mu_1x = regressors["y_t1_x"].predict(x) # predict E[Y|T=0,X] - mu_0x = regressors['y_t0_x'].predict(x) + mu_0x = regressors["y_t0_x"].predict(x) - return mu_0mx, mu_1mx, mu_0x, E_mu_t0_t1, E_mu_t1_t0, mu_1x \ No newline at end of file + return mu_0mx, mu_1mx, mu_0x, E_mu_t0_t1, E_mu_t1_t0, mu_1x diff --git a/src/med_bench/nuisances/density.py b/src/med_bench/nuisances/density.py index 1843ed7..e8e92c2 100644 --- a/src/med_bench/nuisances/density.py +++ b/src/med_bench/nuisances/density.py @@ -12,8 +12,8 @@ from sklearn.base import BaseEstimator from joblib import Parallel, delayed -def estimate_mediator_density(t, m, x, y, crossfit, clf_m, - interaction, fit=False): + +def estimate_mediator_density(t, m, x, y, crossfit, clf_m, interaction, fit=False): """ Estimate mediator density f(M|T,X) with train test lists from crossfitting @@ -32,12 +32,14 @@ def estimate_mediator_density(t, m, x, y, crossfit, clf_m, # if not is_array_integer(m): # return estimate_mediator_density_kde(t, m, x, y, crossfit, interaction) # else: - return estimate_mediator_probability(t, m, x, y, crossfit, clf_m, - interaction, fit=False) + return estimate_mediator_probability( + t, m, x, y, crossfit, clf_m, interaction, fit=False + ) -def estimate_mediators_probabilities(t, m, x, y, crossfit, clf_m, - interaction, fit=False): +def estimate_mediators_probabilities( + t, m, x, y, crossfit, clf_m, interaction, fit=False +): """ Estimate mediator density f(M|T,X) with train test lists from crossfitting @@ -71,7 +73,6 @@ def estimate_mediators_probabilities(t, m, x, y, crossfit, clf_m, for train_index, test_index in train_test_list: - # f_mtx model fitting if fit == True: clf_m = clf_m.fit(t_x[train_index, :], m[train_index]) @@ -79,7 +80,6 @@ def estimate_mediators_probabilities(t, m, x, y, crossfit, clf_m, fm_0 = clf_m.predict_proba(t0_x[test_index, :]) fm_1 = clf_m.predict_proba(t1_x[test_index, :]) - for i, b in enumerate(np.unique(m)): f_0bx, f_1bx = [np.zeros(n) for h in range(2)] @@ -92,8 +92,8 @@ def estimate_mediators_probabilities(t, m, x, y, crossfit, clf_m, return f_t0, f_t1 -def estimate_mediator_probability(t, m, x, y, crossfit, clf_m, - interaction, fit=False): + +def estimate_mediator_probability(t, m, x, y, crossfit, clf_m, interaction, fit=False): """ Estimate mediator density f(M|T,X) with train test lists from crossfitting @@ -149,6 +149,7 @@ def estimate_mediator_probability(t, m, x, y, crossfit, clf_m, return f_m0x, f_m1x + class ConditionalNearestNeighborsKDE(BaseEstimator): """Conditional Kernel Density Estimation using nearest neighbors. @@ -206,14 +207,12 @@ def predict(self, X): _, ind_X = self.nn_estimator_.kneighbors(X) if self.kde_estimator is None: kernel_density_list = [ - KernelDensity(bandwidth="scott").fit( - self.y_train_[ind].reshape(-1, 1)) + KernelDensity(bandwidth="scott").fit(self.y_train_[ind].reshape(-1, 1)) for ind in ind_X ] else: kernel_density_list = [ - clone(self.kde_estimator).fit( - self.y_train_[ind].reshape(-1, 1)) + clone(self.kde_estimator).fit(self.y_train_[ind].reshape(-1, 1)) for ind in ind_X ] return kernel_density_list @@ -235,6 +234,7 @@ def _evaluate_individual(y_, cde_pred): return individual_predictions + # def estimate_mediator_density_kde(t, m, x, y, crossfit, interaction): # """ # Estimate mediator density f(M|T,X) @@ -278,6 +278,7 @@ def _evaluate_individual(y_, cde_pred): # return f_m0x, f_m1x + def estimate_mediator_density_kde(t, m, x, y, crossfit, ckde_m, interaction): """ Estimate mediator density f(M|T,X) @@ -300,16 +301,14 @@ def estimate_mediator_density_kde(t, m, x, y, crossfit, ckde_m, interaction): t0 = np.zeros((n, 1)) t1 = np.ones((n, 1)) - f_m0x, f_m1x = [np.zeros(n) for _ in range(2)] t_x = _get_interactions(interaction, t, x) t0_x = _get_interactions(interaction, t0, x) t1_x = _get_interactions(interaction, t1, x) - # predict f(M|T=t,X) f_m0x = ckde_m.pdf(m, t0_x) f_m1x = ckde_m.pdf(m, t1_x) - return f_m0x, f_m1x \ No newline at end of file + return f_m0x, f_m1x diff --git a/src/med_bench/nuisances/propensities.py b/src/med_bench/nuisances/propensities.py index 1d5b9e4..182d754 100644 --- a/src/med_bench/nuisances/propensities.py +++ b/src/med_bench/nuisances/propensities.py @@ -41,6 +41,7 @@ def estimate_treatment_propensity_x(t, m, x, crossfit, clf_t_x): return p_x + def estimate_treatment_probabilities(t, m, x, crossfit, clf_t_x, clf_t_xm, fit=False): """ Estimate treatment probabilities P(T=1|X) and P(T=1|X, M) with train @@ -74,4 +75,4 @@ def estimate_treatment_probabilities(t, m, x, crossfit, clf_t_x, clf_t_xm, fit=F p_x[test_index] = clf_t_x.predict_proba(x[test_index, :])[:, 1] p_xm[test_index] = clf_t_xm.predict_proba(xm[test_index, :])[:, 1] - return p_x, p_xm \ No newline at end of file + return p_x, p_xm diff --git a/src/med_bench/nuisances/utils.py b/src/med_bench/nuisances/utils.py index 96eee0c..38f1d58 100644 --- a/src/med_bench/nuisances/utils.py +++ b/src/med_bench/nuisances/utils.py @@ -46,11 +46,11 @@ def _get_classifier(regularization, forest, calibration, random_state=42): cs, _ = _get_regularization_parameters(regularization) if not forest: - clf = LogisticRegressionCV(random_state=random_state, Cs=cs, - cv=CV_FOLDS) + clf = LogisticRegressionCV(random_state=random_state, Cs=cs, cv=CV_FOLDS) else: - clf = RandomForestClassifier(random_state=random_state, - n_estimators=100, min_samples_leaf=10) + clf = RandomForestClassifier( + random_state=random_state, n_estimators=100, min_samples_leaf=10 + ) if calibration in {"sigmoid", "isotonic"}: clf = CalibratedClassifierCV(clf, method=calibration) @@ -73,11 +73,3 @@ def _get_regressor(regularization, forest, random_state=42): reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10) return reg - - - - - - - - diff --git a/src/med_bench/utils/constants.py b/src/med_bench/utils/constants.py index 33a2433..f0d5358 100644 --- a/src/med_bench/utils/constants.py +++ b/src/med_bench/utils/constants.py @@ -101,7 +101,10 @@ def get_tolerance_array(tolerance_size: str) -> np.array: ESTIMATORS = list(TOLERANCE_DICT.keys()) R_DEPENDENT_ESTIMATORS = [ - "mediation_IPW_R", "simulation_based", "mediation_dml", "mediation_g_estimator" + "mediation_IPW_R", + "simulation_based", + "mediation_dml", + "mediation_g_estimator", ] # PARAMETERS VALUES FOR DATA GENERATION @@ -159,4 +162,4 @@ def get_tolerance_array(tolerance_size: str) -> np.array: ALPHAS = np.logspace(-5, 5, 8) CV_FOLDS = 5 -TINY = 1.e-12 +TINY = 1.0e-12 diff --git a/src/med_bench/utils/nuisances.py b/src/med_bench/utils/nuisances.py index cccad08..bb60e08 100644 --- a/src/med_bench/utils/nuisances.py +++ b/src/med_bench/utils/nuisances.py @@ -2,6 +2,7 @@ the objective of this script is to implement nuisances functions used in mediation estimators in causal inference """ + import numpy as np from sklearn.base import clone from sklearn.calibration import CalibratedClassifierCV @@ -17,7 +18,7 @@ ALPHAS = np.logspace(-5, 5, 8) CV_FOLDS = 5 -TINY = 1.e-12 +TINY = 1.0e-12 def _get_train_test_lists(crossfit, n, x): @@ -73,11 +74,11 @@ def _get_classifier(regularization, forest, calibration, random_state=42): cs, _ = _get_regularization_parameters(regularization) if not forest: - clf = LogisticRegressionCV(random_state=random_state, Cs=cs, - cv=CV_FOLDS) + clf = LogisticRegressionCV(random_state=random_state, Cs=cs, cv=CV_FOLDS) else: - clf = RandomForestClassifier(random_state=random_state, - n_estimators=100, min_samples_leaf=10) + clf = RandomForestClassifier( + random_state=random_state, n_estimators=100, min_samples_leaf=10 + ) if calibration in {"sigmoid", "isotonic"}: clf = CalibratedClassifierCV(clf, method=calibration) @@ -98,7 +99,8 @@ def _get_regressor(regularization, forest, random_state=42): reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) else: reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=random_state) + n_estimators=100, min_samples_leaf=10, random_state=random_state + ) return reg @@ -200,8 +202,7 @@ def _estimate_mediator_density(y, t, m, x, crossfit, clf_m, interaction): return f_00x, f_01x, f_10x, f_11x, f_m0x, f_m1x -def _estimate_conditional_mean_outcome(y, t, m, x, crossfit, reg_y, - interaction): +def _estimate_conditional_mean_outcome(y, t, m, x, crossfit, reg_y, interaction): """ Estimate conditional mean outcome E[Y|T,M,X] with train test lists from crossfitting @@ -233,8 +234,7 @@ def _estimate_conditional_mean_outcome(y, t, m, x, crossfit, reg_y, train_test_list = _get_train_test_lists(crossfit, n, x) - mu_11x, mu_10x, mu_01x, mu_00x, mu_1mx, mu_0mx = [np.zeros(n) for _ in - range(6)] + mu_11x, mu_10x, mu_01x, mu_00x, mu_1mx, mu_0mx = [np.zeros(n) for _ in range(6)] x_t_mr = _get_interactions(interaction, x, t, mr) @@ -264,8 +264,9 @@ def _estimate_conditional_mean_outcome(y, t, m, x, crossfit, reg_y, return mu_00x, mu_01x, mu_10x, mu_11x, mu_0mx, mu_1mx -def _estimate_cross_conditional_mean_outcome(y, t, m, x, crossfit, reg_y, - reg_cross_y, f, interaction): +def _estimate_cross_conditional_mean_outcome( + y, t, m, x, crossfit, reg_y, reg_cross_y, f, interaction +): """ Estimate the conditional mean outcome, the cross conditional mean outcome @@ -386,8 +387,9 @@ def _estimate_cross_conditional_mean_outcome(y, t, m, x, crossfit, reg_y, return mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 -def _estimate_cross_conditional_mean_outcome_nesting(y, t, m, x, crossfit, - reg_y, reg_cross_y): +def _estimate_cross_conditional_mean_outcome_nesting( + y, t, m, x, crossfit, reg_y, reg_cross_y +): """ Estimate treatment probabilities and the conditional mean outcome, cross conditional mean outcome diff --git a/src/med_bench/utils/scores.py b/src/med_bench/utils/scores.py index 02521e0..b8e36bf 100644 --- a/src/med_bench/utils/scores.py +++ b/src/med_bench/utils/scores.py @@ -1,5 +1,6 @@ import numpy as np + def ipw_risk(y, t, hat_y, hat_e, trimming=None): if trimming is not None: clipped_hat_e = np.clip(hat_e, trimming, 1 - trimming) @@ -22,8 +23,7 @@ def w_risk(y, t, hat_e, hat_tau, trimming=None): clipped_hat_e = np.clip(hat_e, trimming, 1 - trimming) else: clipped_hat_e = hat_e - pseudo_outcome = (y * (t - clipped_hat_e)) / ( - clipped_hat_e * (1 - clipped_hat_e)) + pseudo_outcome = (y * (t - clipped_hat_e)) / (clipped_hat_e * (1 - clipped_hat_e)) return np.mean((pseudo_outcome - hat_tau) ** 2) @@ -35,11 +35,9 @@ def ipw_r_risk(y, t, hat_mu_0, hat_mu_1, hat_e, hat_m, trimming=None): ipw_weights = t / clipped_hat_e + (1 - t) / (1 - clipped_hat_e) hat_tau = hat_mu_1 - hat_mu_0 - return np.sum( - (((y - hat_m) - (t - hat_e) * (hat_tau)) ** 2) * ipw_weights) / len(y) + return np.sum((((y - hat_m) - (t - hat_e) * (hat_tau)) ** 2) * ipw_weights) / len(y) def ipw_r_risk_oracle(y, t, hat_mu_0, hat_mu_1, e, mu_1, mu_0): m = mu_0 * (1 - e) + mu_1 * e - return ipw_r_risk(y=y, t=t, hat_mu_0=hat_mu_0, hat_mu_1=hat_mu_1, hat_e=e, - hat_m=m) + return ipw_r_risk(y=y, t=t, hat_mu_0=hat_mu_0, hat_mu_1=hat_mu_1, hat_e=e, hat_m=m) diff --git a/src/med_bench/utils/utils.py b/src/med_bench/utils/utils.py index 86bb8b8..2805d13 100644 --- a/src/med_bench/utils/utils.py +++ b/src/med_bench/utils/utils.py @@ -17,8 +17,14 @@ def check_r_dependencies(): # Assuming reaching here means R is accessible, now try importing rpy2 packages import rpy2.robjects.packages as rpackages + required_packages = [ - 'causalweight', 'mediation', 'stats', 'base', 'grf', 'plmed' + "causalweight", + "mediation", + "stats", + "base", + "grf", + "plmed", ] for package in required_packages: @@ -42,6 +48,7 @@ def is_r_installed(): def check_r_package(package_name): try: import rpy2.robjects.packages as rpackages + rpackages.importr(package_name) return True except: @@ -67,7 +74,7 @@ def wrapper(*args, **kwargs): for package in required_packages: if not check_r_package(package): - if package != 'plmed': + if package != "plmed": raise DependencyNotInstalledError( f"The '{package}' R package is not installed. " "Please install it using R by running:\n" @@ -89,7 +96,9 @@ def wrapper(*args, **kwargs): ) return None return func(*args, **kwargs) + return wrapper + return decorator @@ -140,7 +149,7 @@ def _get_interactions(interaction, *args): return pre_inter_variables new_cols = list() for i, var in enumerate(variables[:]): - for j, var2 in enumerate(variables[i+1:]): + for j, var2 in enumerate(variables[i + 1 :]): for ii in range(var.shape[1]): for jj in range(var2.shape[1]): new_cols.append((var[:, ii] * var2[:, jj]).reshape(-1, 1)) @@ -159,14 +168,15 @@ def _convert_array_to_R(x): if len(x.shape) == 1: return robjects.FloatVector(x) elif len(x.shape) == 2: - return robjects.r.matrix(robjects.FloatVector(x.ravel()), - nrow=x.shape[0], byrow='TRUE') + return robjects.r.matrix( + robjects.FloatVector(x.ravel()), nrow=x.shape[0], byrow="TRUE" + ) def _check_input(y, t, m, x, setting): """ internal function to check inputs. `_check_input` adjusts the dimension - of the input (matrix or vectors), and raises an error + of the input (matrix or vectors), and raises an error - if the size of input is not adequate, - or if the type of input is not supported (cotinuous treatment or non-binary one-dimensional mediator if the specified setting parameter @@ -230,12 +240,11 @@ def _check_input(y, t, m, x, setting): else: m_converted = m - if (m_converted.shape[1] > 1) and (setting != 'multidimensional'): + if (m_converted.shape[1] > 1) and (setting != "multidimensional"): raise ValueError("Multidimensional m (mediator) is not supported") - if (setting == 'binary') and (len(np.unique(m)) != 2): - raise ValueError( - "Only a binary one-dimensional m (mediator) is supported") + if (setting == "binary") and (len(np.unique(m)) != 2): + raise ValueError("Only a binary one-dimensional m (mediator) is supported") return y_converted, t_converted, m_converted, x_converted @@ -249,29 +258,26 @@ def is_array_integer(array): def str_to_bool(string): if bool(string) == string: return string - elif string == 'True': + elif string == "True": return True - elif string == 'False': + elif string == "False": return False else: raise ValueError # evil ValueError that doesn't tell you what the wrong value was def bucketize_mediators(m, n_buckets=10, random_state=42): - kmeans = KMeans(n_clusters=n_buckets, - random_state=random_state, n_init="auto").fit(m) + kmeans = KMeans(n_clusters=n_buckets, random_state=random_state, n_init="auto").fit( + m + ) return kmeans.predict(m) def train_test_split_data(causal_data, test_size=0.33, random_state=42): x, t, m, y = causal_data x_train, x_test, t_train, t_test, m_train, m_test, y_train, y_test = ( - train_test_split(x, - t, - m, - y, - test_size=test_size, - random_state=random_state)) + train_test_split(x, t, m, y, test_size=test_size, random_state=random_state) + ) causal_data_train = x_train, t_train, m_train, y_train causal_data_test = x_test, t_test, m_test, y_test return causal_data_train, causal_data_test From ae48827593177eb9977199cd9dcf6e301b15b619 Mon Sep 17 00:00:00 2001 From: houssamzenati Date: Wed, 6 Nov 2024 17:40:40 +0100 Subject: [PATCH 45/84] remove comments, main module --- src/med_bench/estimation/mediation_tmle.py | 19 --- src/med_bench/example.py | 187 ++++++++++----------- 2 files changed, 93 insertions(+), 113 deletions(-) diff --git a/src/med_bench/estimation/mediation_tmle.py b/src/med_bench/estimation/mediation_tmle.py index 6e99d66..c24d9bb 100644 --- a/src/med_bench/estimation/mediation_tmle.py +++ b/src/med_bench/estimation/mediation_tmle.py @@ -53,13 +53,10 @@ def _one_step_correction_direct(self, t, m, x, y): [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t, m]] ) mu_tmx = self._regressor_y.predict(x_t_mr) - # import pdb; pdb.set_trace() reg = LinearRegression(fit_intercept=False).fit( h_corrector.reshape(-1, 1), (y - mu_tmx).squeeze() ) epsilon_h = reg.coef_ - # epsilon_h = 0 - print(epsilon_h) x_t0_m = np.hstack( [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t0, m]] @@ -121,11 +118,6 @@ def _one_step_correction_indirect(self, t, m, x, y): h_corrector.reshape(-1, 1), (y - mu_tmx).squeeze() ) epsilon_h = reg.coef_ - # epsilon_h = 0 - print("indirect", epsilon_h) - - # mu_t0_mx = self._regressor_y.predict(_get_interactions(False, x, t0, m)) - # h_corrector_t0 = t0 * f_t0 / (p_x * f_t1) - (1 - t0)/(1 - p_x) x_t1_m = np.hstack( [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t1, m]] @@ -133,18 +125,9 @@ def _one_step_correction_indirect(self, t, m, x, y): mu_t1_mx = self._regressor_y.predict(x_t1_m) h_corrector_t1 = t1 / p_x - t1 * ratio - # mu_t0_mx_star = mu_t0_mx + epsilon_h * h_corrector_t0 mu_t1_mx_star = mu_t1_mx + epsilon_h * h_corrector_t1 regressor_y = _get_regressor(self._regularize, self._use_forest) - - # reg_cross.fit(x, (mu_t1_mx_star).squeeze()) - - # omega_t = reg_cross.predict(x) - # c_corrector = (2*t - 1)/p_x[:, None] - # reg = LinearRegression(fit_intercept=False).fit(c_corrector.reshape(-1, 1)[t==0], (mu_t1_mx_star - omega_t).squeeze()) - # epsilon_c = reg.coef_ - reg_cross = clone(regressor_y) reg_cross.fit(x[t == 0], mu_t1_mx_star[t == 0]) omega_t0x = reg_cross.predict(x) @@ -155,7 +138,6 @@ def _one_step_correction_indirect(self, t, m, x, y): (mu_t1_mx_star[t == 0] - omega_t0x[t == 0]).squeeze(), ) epsilon_c_t0 = reg.coef_ - # epsilon_c_t0 = 0 omega_t0x_star = omega_t0x + epsilon_c_t0 * c_corrector_t0 reg_cross = clone(regressor_y) @@ -166,7 +148,6 @@ def _one_step_correction_indirect(self, t, m, x, y): c_corrector_t1[t == 1], (y[t == 1] - omega_t1x[t == 1]).squeeze() ) epsilon_c_t1 = reg.coef_ - # epsilon_c_t1 = 0 omega_t1x_star = omega_t1x + epsilon_c_t1 * c_corrector_t1 delta_1 = np.mean(omega_t1x_star - omega_t0x_star) diff --git a/src/med_bench/example.py b/src/med_bench/example.py index 1737f4e..7768760 100644 --- a/src/med_bench/example.py +++ b/src/med_bench/example.py @@ -17,103 +17,102 @@ from med_bench.utils.constants import CV_FOLDS -if __name__ == "__main__": - print("get simulated data") - (x, t, m, y, - theta_1_delta_0, theta_1, theta_0, delta_1, delta_0, - p_t, th_p_t_mx) = simulate_data(n=1000, rg=default_rng(321), dim_x=5) - - (x_train, x_test, t_train, t_test, - m_train, m_test, y_train, y_test) = train_test_split(x, t, m, y, test_size=0.33, random_state=42) - - cs, alphas = _get_regularization_parameters(regularization=True) - - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) - - clf2 = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) - - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - - reg2 = RidgeCV(alphas=alphas, cv=CV_FOLDS) - - # Step 4: Define estimators (modularized and non-modularized) - estimators = { - "CoefficientProduct": { - "modular": CoefficientProduct( - regressor=reg, classifier=clf, regularize=True - ), - "non_modular": mediation_coefficient_product - }, - "DoubleMachineLearning": { - "modular": DoubleMachineLearning( - clip=1e-6, trim=0.05, normalized=True, regressor=reg2, classifier=clf2 - ), - "non_modular": mediation_dml - }, - "GComputation": { - "modular": GComputation( - regressor=reg2, classifier=CalibratedClassifierCV( - clf2, method="sigmoid") - ), - "non_modular": mediation_g_formula - }, - "ImportanceWeighting": { - "modular": ImportanceWeighting( - clip=1e-6, trim=0.01, regressor=reg2, classifier=CalibratedClassifierCV(clf2, method="sigmoid") - ), - "non_modular": mediation_IPW - }, - "MultiplyRobust": { - "modular": MultiplyRobust( - clip=1e-6, ratio="propensities", normalized=True, regressor=reg2, - classifier=CalibratedClassifierCV(clf2, method="sigmoid") - ), - "non_modular": mediation_multiply_robust - } +print("get simulated data") +(x, t, m, y, + theta_1_delta_0, theta_1, theta_0, delta_1, delta_0, + p_t, th_p_t_mx) = simulate_data(n=1000, rg=default_rng(321), dim_x=5) + +(x_train, x_test, t_train, t_test, + m_train, m_test, y_train, y_test) = train_test_split(x, t, m, y, test_size=0.33, random_state=42) + +cs, alphas = _get_regularization_parameters(regularization=True) + +clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + +clf2 = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) + +reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + +reg2 = RidgeCV(alphas=alphas, cv=CV_FOLDS) + +# Step 4: Define estimators (modularized and non-modularized) +estimators = { + "CoefficientProduct": { + "modular": CoefficientProduct( + regressor=reg, classifier=clf, regularize=True + ), + "non_modular": mediation_coefficient_product + }, + "DoubleMachineLearning": { + "modular": DoubleMachineLearning( + clip=1e-6, trim=0.05, normalized=True, regressor=reg2, classifier=clf2 + ), + "non_modular": mediation_dml + }, + "GComputation": { + "modular": GComputation( + regressor=reg2, classifier=CalibratedClassifierCV( + clf2, method="sigmoid") + ), + "non_modular": mediation_g_formula + }, + "ImportanceWeighting": { + "modular": ImportanceWeighting( + clip=1e-6, trim=0.01, regressor=reg2, classifier=CalibratedClassifierCV(clf2, method="sigmoid") + ), + "non_modular": mediation_IPW + }, + "MultiplyRobust": { + "modular": MultiplyRobust( + clip=1e-6, ratio="propensities", normalized=True, regressor=reg2, + classifier=CalibratedClassifierCV(clf2, method="sigmoid") + ), + "non_modular": mediation_multiply_robust } +} + +# Step 5: Initialize results DataFrame +results = [] + +# Step 6: Iterate over each estimator +for estimator_name, estimator_dict in estimators.items(): + # Non-Modularized Estimation + # Check if non-modular is a function + if callable(estimator_dict["non_modular"]): + (total_effect, direct_effect1, direct_effect2, indirect_effect1, indirect_effect2, _) = estimator_dict["non_modular"]( + y, t, m, x) - # Step 5: Initialize results DataFrame - results = [] - - # Step 6: Iterate over each estimator - for estimator_name, estimator_dict in estimators.items(): - # Non-Modularized Estimation - # Check if non-modular is a function - if callable(estimator_dict["non_modular"]): - (total_effect, direct_effect1, direct_effect2, indirect_effect1, indirect_effect2, _) = estimator_dict["non_modular"]( - y, t, m, x) - - results.append({ - "Estimator": estimator_name, - "Method": "Non-Modularized", - "Total Effect": total_effect, - "Direct Effect (Treated)": direct_effect1, - "Direct Effect (Control)": direct_effect2, - "Indirect Effect (Treated)": indirect_effect1, - "Indirect Effect (Control)": indirect_effect2, - }) - - # Modularized Estimation - modular_estimator = estimator_dict["modular"] - modular_estimator.fit(t_train, m_train, x_train, y_train) - causal_effects = modular_estimator.estimate( - t_test, m_test, x_test, y_test) - - # Append modularized results results.append({ "Estimator": estimator_name, - "Method": "Modularized", - "Total Effect": causal_effects['total_effect'], - "Direct Effect (Treated)": causal_effects['direct_effect_treated'], - "Direct Effect (Control)": causal_effects['direct_effect_control'], - "Indirect Effect (Treated)": causal_effects['indirect_effect_treated'], - "Indirect Effect (Control)": causal_effects['indirect_effect_control'], + "Method": "Non-Modularized", + "Total Effect": total_effect, + "Direct Effect (Treated)": direct_effect1, + "Direct Effect (Control)": direct_effect2, + "Indirect Effect (Treated)": indirect_effect1, + "Indirect Effect (Control)": indirect_effect2, }) - # Convert results to DataFrame - results_df = pd.DataFrame(results) - - # Display or save the DataFrame - print(results_df) + # Modularized Estimation + modular_estimator = estimator_dict["modular"] + modular_estimator.fit(t_train, m_train, x_train, y_train) + causal_effects = modular_estimator.estimate( + t_test, m_test, x_test, y_test) + + # Append modularized results + results.append({ + "Estimator": estimator_name, + "Method": "Modularized", + "Total Effect": causal_effects['total_effect'], + "Direct Effect (Treated)": causal_effects['direct_effect_treated'], + "Direct Effect (Control)": causal_effects['direct_effect_control'], + "Indirect Effect (Treated)": causal_effects['indirect_effect_treated'], + "Indirect Effect (Control)": causal_effects['indirect_effect_control'], + }) + +# Convert results to DataFrame +results_df = pd.DataFrame(results) + +# Display or save the DataFrame +print(results_df) From 6e59dd07fa537c49d91fb2f753831fa42e498bfb Mon Sep 17 00:00:00 2001 From: houssamzenati Date: Fri, 8 Nov 2024 13:58:53 +0100 Subject: [PATCH 46/84] partial tests of new modularized estimators --- src/med_bench/get_estimation.py | 257 ++++++++++++++++++++++++++++++++ 1 file changed, 257 insertions(+) diff --git a/src/med_bench/get_estimation.py b/src/med_bench/get_estimation.py index 4ee3ae6..8285908 100644 --- a/src/med_bench/get_estimation.py +++ b/src/med_bench/get_estimation.py @@ -14,6 +14,34 @@ r_mediate, ) +from estimation.mediation_coefficient_product import CoefficientProduct +from estimation.mediation_dml import DoubleMachineLearning +from estimation.mediation_g_computation import GComputation +from estimation.mediation_ipw import ImportanceWeighting +from estimation.mediation_mr import MultiplyRobust +from estimation.mediation_tmle import TMLE + +from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor +from sklearn.linear_model import LogisticRegressionCV, RidgeCV +from sklearn.calibration import CalibratedClassifierCV +from med_bench.utils.constants import CV_FOLDS +from med_bench.nuisances.utils import _get_regularization_parameters + +def transform_outputs(causal_effects): + """Transforms outputs in the old format + + Args: + causal_effects (dict): dictionary of causal effects + + Returns: + list: list of causal effects + """ + total = causal_effects['total_effect'] + direct_treated = causal_effects['direct_effect_treated'] + direct_control = causal_effects['direct_effect_control'] + indirect_treated = causal_effects['indirect_effect_treated'] + indirect_control = causal_effects['indirect_effect_control'] + return [total, direct_treated, direct_control, indirect_treated, indirect_control, 0] def get_estimation(x, t, m, y, estimator, config): """Wrapper estimator fonction ; calls an estimator given mediation data @@ -62,6 +90,11 @@ def get_estimation(x, t, m, y, estimator, config): effects = raw_res_R[0, :] elif estimator == "coefficient_product": effects = mediation_coefficient_product(y, t, m, x) + clf = RandomForestClassifier(random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10, random_state=42) + causal_effects = CoefficientProduct(regressor=reg, classifier=clf, regularize=True) + effects = transform_outputs(causal_effects) + elif estimator == "mediation_ipw_noreg": effects = mediation_IPW( y, @@ -75,6 +108,15 @@ def get_estimation(x, t, m, y, estimator, config): clip=1e-6, calibration=None, ) + cs, alphas = _get_regularization_parameters(regularization=False) + clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) + reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) + estimator = ImportanceWeighting( + clip=1e-6, trim=0, regressor=reg, classifier=clf + ) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) elif estimator == "mediation_ipw_noreg_cf": effects = mediation_IPW( y, @@ -101,6 +143,15 @@ def get_estimation(x, t, m, y, estimator, config): clip=1e-6, calibration=None, ) + cs, alphas = _get_regularization_parameters(regularization=True) + clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) + reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) + estimator = ImportanceWeighting( + clip=1e-6, trim=0, regressor=reg, classifier=clf + ) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) elif estimator == "mediation_ipw_reg_cf": effects = mediation_IPW( y, @@ -127,6 +178,15 @@ def get_estimation(x, t, m, y, estimator, config): clip=1e-6, calibration=None, ) + cs, alphas = _get_regularization_parameters(regularization=True) + clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) + reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) + estimator = ImportanceWeighting( + clip=1e-6, trim=0, regressor=reg, classifier=CalibratedClassifierCV(clf, method="sigmoid") + ) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) elif estimator == "mediation_ipw_reg_calibration_iso": effects = mediation_IPW( y, @@ -140,6 +200,15 @@ def get_estimation(x, t, m, y, estimator, config): clip=1e-6, calibration="isotonic", ) + cs, alphas = _get_regularization_parameters(regularization=True) + clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) + reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) + estimator = ImportanceWeighting( + clip=1e-6, trim=0, regressor=reg, classifier=CalibratedClassifierCV(clf, method="isotonic") + ) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) elif estimator == "mediation_ipw_reg_calibration_cf": effects = mediation_IPW( y, @@ -179,6 +248,15 @@ def get_estimation(x, t, m, y, estimator, config): clip=1e-6, calibration=None, ) + cs, alphas = _get_regularization_parameters(regularization=True) + clf = RandomForestClassifier(random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10, random_state=42) + estimator = ImportanceWeighting( + clip=1e-6, trim=0, regressor=reg, classifier=clf + ) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) elif estimator == "mediation_ipw_forest_cf": effects = mediation_IPW( y, @@ -205,6 +283,15 @@ def get_estimation(x, t, m, y, estimator, config): clip=1e-6, calibration=None, ) + cs, alphas = _get_regularization_parameters(regularization=True) + clf = RandomForestClassifier(random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10, random_state=42) + estimator = ImportanceWeighting( + clip=1e-6, trim=0, regressor=reg, classifier=CalibratedClassifierCV(clf, method="sigmoid") + ) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) elif estimator == "mediation_ipw_forest_calibration_iso": effects = mediation_IPW( y, @@ -218,6 +305,15 @@ def get_estimation(x, t, m, y, estimator, config): clip=1e-6, calibration="isotonic", ) + cs, alphas = _get_regularization_parameters(regularization=True) + clf = RandomForestClassifier(random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10, random_state=42) + estimator = ImportanceWeighting( + clip=1e-6, trim=0, regressor=reg, classifier=CalibratedClassifierCV(clf, method="isotonic") + ) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) elif estimator == "mediation_ipw_forest_calibration_cf": effects = mediation_IPW( y, @@ -257,6 +353,13 @@ def get_estimation(x, t, m, y, estimator, config): regularization=False, calibration=None, ) + cs, alphas = _get_regularization_parameters(regularization=False) + clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) + reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) + estimator = GComputation(regressor=reg, classifier=clf) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) elif estimator == "mediation_g_computation_noreg_cf": if config in (0, 1, 2): effects = mediation_g_formula( @@ -283,6 +386,13 @@ def get_estimation(x, t, m, y, estimator, config): regularization=True, calibration=None, ) + cs, alphas = _get_regularization_parameters(regularization=True) + clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) + reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) + estimator = GComputation(regressor=reg, classifier=clf) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) elif estimator == "mediation_g_computation_reg_cf": if config in (0, 1, 2): effects = mediation_g_formula( @@ -309,6 +419,13 @@ def get_estimation(x, t, m, y, estimator, config): regularization=True, calibration=None, ) + cs, alphas = _get_regularization_parameters(regularization=True) + clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) + reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) + estimator = GComputation(regressor=reg, classifier=CalibratedClassifierCV(clf, method="sigmoid")) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) elif estimator == "mediation_g_computation_reg_calibration_iso": if config in (0, 1, 2): effects = mediation_g_formula( @@ -322,6 +439,13 @@ def get_estimation(x, t, m, y, estimator, config): regularization=True, calibration="isotonic", ) + cs, alphas = _get_regularization_parameters(regularization=True) + clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) + reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) + estimator = GComputation(regressor=reg, classifier=CalibratedClassifierCV(clf, method="isotonic")) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) elif estimator == "mediation_g_computation_reg_calibration_cf": if config in (0, 1, 2): effects = mediation_g_formula( @@ -361,6 +485,13 @@ def get_estimation(x, t, m, y, estimator, config): regularization=True, calibration=None, ) + cs, alphas = _get_regularization_parameters(regularization=True) + clf = RandomForestClassifier(random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10, random_state=42) + estimator = GComputation(regressor=reg, classifier=clf) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) elif estimator == "mediation_g_computation_forest_cf": if config in (0, 1, 2): effects = mediation_g_formula( @@ -387,6 +518,14 @@ def get_estimation(x, t, m, y, estimator, config): regularization=True, calibration='sigmoid', ) + cs, alphas = _get_regularization_parameters(regularization=True) + clf = RandomForestClassifier(random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10, random_state=42) + estimator = GComputation(regressor=reg, classifier=CalibratedClassifierCV(clf, method="sigmoid")) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + elif estimator == "mediation_g_computation_forest_calibration_iso": if config in (0, 1, 2): effects = mediation_g_formula( @@ -400,6 +539,14 @@ def get_estimation(x, t, m, y, estimator, config): regularization=True, calibration="isotonic", ) + cs, alphas = _get_regularization_parameters(regularization=True) + clf = RandomForestClassifier(random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10, random_state=42) + estimator = GComputation(regressor=reg, classifier=CalibratedClassifierCV(clf, method="isotonic")) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + elif estimator == "mediation_g_computation_forest_calibration_cf": if config in (0, 1, 2): effects = mediation_g_formula( @@ -440,6 +587,16 @@ def get_estimation(x, t, m, y, estimator, config): regularization=False, calibration=None, ) + cs, alphas = _get_regularization_parameters(regularization=False) + clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) + reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) + estimator = MultiplyRobust( + clip=1e-6, ratio="propensities", normalized=True, regressor=reg, + classifier=clf) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + elif estimator == "mediation_multiply_robust_noreg_cf": if config in (0, 1, 2): effects = mediation_multiply_robust( @@ -468,6 +625,15 @@ def get_estimation(x, t, m, y, estimator, config): regularization=True, calibration=None, ) + cs, alphas = _get_regularization_parameters(regularization=True) + clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) + reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) + estimator = MultiplyRobust( + clip=1e-6, ratio="propensities", normalized=True, regressor=reg, + classifier=clf) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) elif estimator == "mediation_multiply_robust_reg_cf": if config in (0, 1, 2): effects = mediation_multiply_robust( @@ -496,6 +662,15 @@ def get_estimation(x, t, m, y, estimator, config): regularization=True, calibration='sigmoid', ) + cs, alphas = _get_regularization_parameters(regularization=False) + clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) + reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) + estimator = MultiplyRobust( + clip=1e-6, ratio="propensities", normalized=True, regressor=reg, + classifier=CalibratedClassifierCV(clf, method="sigmoid")) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) elif estimator == "mediation_multiply_robust_reg_calibration_iso": if config in (0, 1, 2): effects = mediation_multiply_robust( @@ -510,6 +685,15 @@ def get_estimation(x, t, m, y, estimator, config): regularization=True, calibration="isotonic", ) + cs, alphas = _get_regularization_parameters(regularization=False) + clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) + reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) + estimator = MultiplyRobust( + clip=1e-6, ratio="propensities", normalized=True, regressor=reg, + classifier=CalibratedClassifierCV(clf, method="isotonic")) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) elif estimator == "mediation_multiply_robust_reg_calibration_cf": if config in (0, 1, 2): effects = mediation_multiply_robust( @@ -552,6 +736,15 @@ def get_estimation(x, t, m, y, estimator, config): regularization=True, calibration=None, ) + cs, alphas = _get_regularization_parameters(regularization=False) + clf = RandomForestClassifier(random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10, random_state=42) + estimator = MultiplyRobust( + clip=1e-6, ratio="propensities", normalized=True, regressor=reg, + classifier=clf) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) elif estimator == "mediation_multiply_robust_forest_cf": if config in (0, 1, 2): effects = mediation_multiply_robust( @@ -580,6 +773,15 @@ def get_estimation(x, t, m, y, estimator, config): regularization=True, calibration='sigmoid', ) + cs, alphas = _get_regularization_parameters(regularization=False) + clf = RandomForestClassifier(random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10, random_state=42) + estimator = MultiplyRobust( + clip=1e-6, ratio="propensities", normalized=True, regressor=reg, + classifier=CalibratedClassifierCV(clf, method="sigmoid")) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) elif estimator == "mediation_multiply_robust_forest_calibration_iso": if config in (0, 1, 2): effects = mediation_multiply_robust( @@ -594,6 +796,15 @@ def get_estimation(x, t, m, y, estimator, config): regularization=True, calibration="isotonic", ) + cs, alphas = _get_regularization_parameters(regularization=False) + clf = RandomForestClassifier(random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10, random_state=42) + estimator = MultiplyRobust( + clip=1e-6, ratio="propensities", normalized=True, regressor=reg, + classifier=CalibratedClassifierCV(clf, method="isotonic")) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) elif estimator == "mediation_multiply_robust_forest_calibration_cf": if config in (0, 1, 2): effects = mediation_multiply_robust( @@ -638,9 +849,28 @@ def get_estimation(x, t, m, y, estimator, config): clip=1e-6, regularization=False, calibration=None) + cs, alphas = _get_regularization_parameters(regularization=False) + clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) + reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) + estimator = DoubleMachineLearning( + clip=1e-6, trim=0, normalized=True, regressor=reg, classifier=clf + ) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + elif estimator == "mediation_dml_reg": effects = mediation_dml( y, t, m, x, trim=0, clip=1e-6, calibration=None) + cs, alphas = _get_regularization_parameters(regularization=True) + clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) + reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) + estimator = DoubleMachineLearning( + clip=1e-6, trim=0, normalized=True, regressor=reg, classifier=clf + ) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) elif estimator == "mediation_dml_reg_fixed_seed": effects = mediation_dml( y, t, m, x, trim=0, clip=1e-6, random_state=321, calibration=None) @@ -661,6 +891,15 @@ def get_estimation(x, t, m, y, estimator, config): elif estimator == "mediation_dml_reg_calibration": effects = mediation_dml( y, t, m, x, trim=0, clip=1e-6, crossfit=0, calibration='sigmoid') + cs, alphas = _get_regularization_parameters(regularization=True) + clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) + reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) + estimator = DoubleMachineLearning( + clip=1e-6, trim=0, normalized=True, regressor=reg, classifier=CalibratedClassifierCV(clf, method="sigmoid") + ) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) elif estimator == "mediation_dml_forest": effects = mediation_dml( y, @@ -672,6 +911,15 @@ def get_estimation(x, t, m, y, estimator, config): crossfit=0, calibration=None, forest=True) + cs, alphas = _get_regularization_parameters(regularization=True) + clf = RandomForestClassifier(random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10, random_state=42) + estimator = DoubleMachineLearning( + clip=1e-6, trim=0, normalized=True, regressor=reg, classifier=clf + ) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) elif estimator == "mediation_dml_forest_calibration": effects = mediation_dml( y, @@ -683,6 +931,15 @@ def get_estimation(x, t, m, y, estimator, config): crossfit=0, calibration='sigmoid', forest=True) + cs, alphas = _get_regularization_parameters(regularization=True) + clf = RandomForestClassifier(random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10, random_state=42) + estimator = DoubleMachineLearning( + clip=1e-6, trim=0, normalized=True, regressor=reg, classifier=CalibratedClassifierCV(clf, method="sigmoid") + ) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) elif estimator == "mediation_dml_reg_calibration_cf": effects = mediation_dml( y, From f6ede7a7ae73997f0dae2c79693a319ec79191b0 Mon Sep 17 00:00:00 2001 From: houssamzenati Date: Fri, 8 Nov 2024 14:13:23 +0100 Subject: [PATCH 47/84] partial tests of new modularized estimators --- src/med_bench/get_estimation.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/med_bench/get_estimation.py b/src/med_bench/get_estimation.py index 8285908..8245c81 100644 --- a/src/med_bench/get_estimation.py +++ b/src/med_bench/get_estimation.py @@ -14,18 +14,17 @@ r_mediate, ) -from estimation.mediation_coefficient_product import CoefficientProduct -from estimation.mediation_dml import DoubleMachineLearning -from estimation.mediation_g_computation import GComputation -from estimation.mediation_ipw import ImportanceWeighting -from estimation.mediation_mr import MultiplyRobust -from estimation.mediation_tmle import TMLE +from med_bench.estimation.mediation_coefficient_product import CoefficientProduct +from med_bench.estimation.mediation_dml import DoubleMachineLearning +from med_bench.estimation.mediation_g_computation import GComputation +from med_bench.estimation.mediation_ipw import ImportanceWeighting +from med_bench.estimation.mediation_mr import MultiplyRobust +from med_bench.nuisances.utils import _get_regularization_parameters +from med_bench.utils.constants import CV_FOLDS from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor from sklearn.linear_model import LogisticRegressionCV, RidgeCV from sklearn.calibration import CalibratedClassifierCV -from med_bench.utils.constants import CV_FOLDS -from med_bench.nuisances.utils import _get_regularization_parameters def transform_outputs(causal_effects): """Transforms outputs in the old format @@ -92,7 +91,9 @@ def get_estimation(x, t, m, y, estimator, config): effects = mediation_coefficient_product(y, t, m, x) clf = RandomForestClassifier(random_state=42, n_estimators=100, min_samples_leaf=10) reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10, random_state=42) - causal_effects = CoefficientProduct(regressor=reg, classifier=clf, regularize=True) + estimator = CoefficientProduct(regressor=reg, classifier=clf, regularize=True) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) effects = transform_outputs(causal_effects) elif estimator == "mediation_ipw_noreg": From cef6b32d304a9988c4dd80f9d3fa3a4ef8b2ab78 Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 13 Nov 2024 15:37:13 +0100 Subject: [PATCH 48/84] rename ipw --- src/med_bench/estimation/mediation_ipw.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/med_bench/estimation/mediation_ipw.py b/src/med_bench/estimation/mediation_ipw.py index 16294f7..a322a14 100644 --- a/src/med_bench/estimation/mediation_ipw.py +++ b/src/med_bench/estimation/mediation_ipw.py @@ -4,7 +4,7 @@ from med_bench.utils.decorators import fitted -class ImportanceWeighting(Estimator): +class InversePropensityWeighting(Estimator): def __init__(self, clip: float, trim: float, **kwargs): """IPW estimator From 817abec7d6a5744cfeb12f15180fa599d6c8b166 Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 13 Nov 2024 16:01:27 +0100 Subject: [PATCH 49/84] regressor and classifier now child class variables --- src/med_bench/estimation/base.py | 25 ++--------- .../mediation_coefficient_product.py | 9 ++-- src/med_bench/estimation/mediation_dml.py | 38 +++++++++++----- .../estimation/mediation_g_computation.py | 24 ++++++++-- src/med_bench/estimation/mediation_ipw.py | 40 ++++++++++++----- src/med_bench/estimation/mediation_mr.py | 29 ++++++++++-- src/med_bench/estimation/mediation_tmle.py | 45 ++++++++++--------- 7 files changed, 138 insertions(+), 72 deletions(-) diff --git a/src/med_bench/estimation/base.py b/src/med_bench/estimation/base.py index 0d7500b..b4ae037 100644 --- a/src/med_bench/estimation/base.py +++ b/src/med_bench/estimation/base.py @@ -1,13 +1,9 @@ from abc import ABCMeta, abstractmethod - import numpy as np - +from sklearn import clone from sklearn.model_selection import GridSearchCV -from sklearn.base import clone, RegressorMixin, ClassifierMixin from med_bench.utils.decorators import fitted -from med_bench.utils.scores import r_risk -from med_bench.utils.utils import _get_train_test_lists class Estimator: @@ -15,31 +11,16 @@ class Estimator: """ __metaclass__ = ABCMeta - def __init__(self, regressor, classifier, verbose: bool = True, crossfit: int = 0): - """Initialize Estimator base class + def __init__(self, verbose: bool = True, crossfit: int = 0): + """Initializes Estimator base class Parameters ---------- - regressor - Regressor used for mu estimation, can be any object with a fit and predict method - classifier - Classifier used for propensity estimation, can be any object with a fit and predict_proba method verbose : bool will print some logs if True crossfit : int number of crossfit folds, if 0 no crossfit is performed """ - assert hasattr( - regressor, 'fit'), "The model does not have a 'fit' method." - assert hasattr( - regressor, 'predict'), "The model does not have a 'predict' method." - assert hasattr( - classifier, 'fit'), "The model does not have a 'fit' method." - assert hasattr( - classifier, 'predict_proba'), "The model does not have a 'predict_proba' method." - self.regressor = regressor - self.classifier = classifier - self._crossfit = crossfit self._crossfit_check() diff --git a/src/med_bench/estimation/mediation_coefficient_product.py b/src/med_bench/estimation/mediation_coefficient_product.py index 0e3b75f..eaf7a9a 100644 --- a/src/med_bench/estimation/mediation_coefficient_product.py +++ b/src/med_bench/estimation/mediation_coefficient_product.py @@ -7,15 +7,18 @@ class CoefficientProduct(Estimator): + """Coefficient Product estimatation method class + """ def __init__(self, regularize: bool, **kwargs): - """Coefficient product estimator + """Initializes Coefficient product estimatation method - Attributes: + Parameters + ---------- regularize (bool) : regularization parameter - """ super().__init__(**kwargs) + self._regularize = regularize def fit(self, t, m, x, y): diff --git a/src/med_bench/estimation/mediation_dml.py b/src/med_bench/estimation/mediation_dml.py index ceea223..5a04d9f 100644 --- a/src/med_bench/estimation/mediation_dml.py +++ b/src/med_bench/estimation/mediation_dml.py @@ -4,20 +4,38 @@ class DoubleMachineLearning(Estimator): - """Implementation of double machine learning - - Parameters - ---------- - alpha (float): regularization parameter - support_vec_tol (float): tolerance for discarding non-supporting vectors - if |alpha_i| < support_vec_tol * alpha then vector is discarded + """Double Machine Learning estimation method class """ - def __init__(self, clip: float, trim: float, normalized: bool, **kwargs): + def __init__(self, regressor, classifier, normalized: bool, **kwargs): + """Initializes Double Machine Learning estimation method + + Parameters + ---------- + regressor + Regressor used for mu estimation, can be any object with a fit and predict method + classifier + Classifier used for propensity estimation, can be any object with a fit and predict_proba method + clips : float + Clipping value for propensity scores + trim : float + Trimming value for propensity scores + normalized : bool + Whether to normalize the propensity scores + """ super().__init__(**kwargs) - self._clip = clip - self._trim = trim + assert hasattr( + regressor, 'fit'), "The model does not have a 'fit' method." + assert hasattr( + regressor, 'predict'), "The model does not have a 'predict' method." + assert hasattr( + classifier, 'fit'), "The model does not have a 'fit' method." + assert hasattr( + classifier, 'predict_proba'), "The model does not have a 'predict_proba' method." + self.regressor = regressor + self.classifier = classifier + self._normalized = normalized def fit(self, t, m, x, y): diff --git a/src/med_bench/estimation/mediation_g_computation.py b/src/med_bench/estimation/mediation_g_computation.py index 430f10e..c33006d 100644 --- a/src/med_bench/estimation/mediation_g_computation.py +++ b/src/med_bench/estimation/mediation_g_computation.py @@ -9,11 +9,29 @@ class GComputation(Estimator): """GComputation estimation method class """ - def __init__(self, **kwargs): - """Initalization of the GComputation estimation method class + def __init__(self, regressor, classifier, **kwargs): + """Initializes GComputation estimation method + + Parameters + ---------- + regressor + Regressor used for mu estimation, can be any object with a fit and predict method + classifier + Classifier used for propensity estimation, can be any object with a fit and predict_proba method """ super().__init__(**kwargs) + assert hasattr( + regressor, 'fit'), "The model does not have a 'fit' method." + assert hasattr( + regressor, 'predict'), "The model does not have a 'predict' method." + assert hasattr( + classifier, 'fit'), "The model does not have a 'fit' method." + assert hasattr( + classifier, 'predict_proba'), "The model does not have a 'predict_proba' method." + self.regressor = regressor + self.classifier = classifier + def fit(self, t, m, x, y): """Fits nuisance parameters to data @@ -36,7 +54,7 @@ def estimate(self, t, m, x, y): t, m, x, y = self._resize(t, m, x, y) - mu_0mx, mu_1mx, y0m0, y0m1, y1m0, y1m1 = self._estimate_cross_conditional_mean_outcome_nesting( + (mu_0mx, mu_1mx, y0m0, y0m1, y1m0, y1m1) = self._estimate_cross_conditional_mean_outcome_nesting( m, x, y) # mean score computing diff --git a/src/med_bench/estimation/mediation_ipw.py b/src/med_bench/estimation/mediation_ipw.py index a322a14..294525b 100644 --- a/src/med_bench/estimation/mediation_ipw.py +++ b/src/med_bench/estimation/mediation_ipw.py @@ -5,23 +5,43 @@ class InversePropensityWeighting(Estimator): - - def __init__(self, clip: float, trim: float, **kwargs): - """IPW estimator - - Attributes: - _clip (float): clipping the propensities - _trim (float): remove propensities which are below the trim threshold - + """Inverse propensity weighting estimation method class + """ + + def __init__(self, regressor, classifier, clip: float, trim: float, **kwargs): + """Initializes Inverse propensity weighting estimation method + + Parameters + ---------- + regressor + Regressor used for mu estimation, can be any object with a fit and predict method + classifier + Classifier used for propensity estimation, can be any object with a fit and predict_proba method + clips : float + Clipping value for propensity scores + trim : float + Trimming value for propensity scores """ super().__init__(**kwargs) + + assert hasattr( + regressor, 'fit'), "The model does not have a 'fit' method." + assert hasattr( + regressor, 'predict'), "The model does not have a 'predict' method." + assert hasattr( + classifier, 'fit'), "The model does not have a 'fit' method." + assert hasattr( + classifier, 'predict_proba'), "The model does not have a 'predict_proba' method." + self.regressor = regressor + self.classifier = classifier + self._clip = clip self._trim = trim def fit(self, t, m, x, y): """Fits nuisance parameters to data - """ + t, m, x, y = self._resize(t, m, x, y) self._fit_treatment_propensity_x_nuisance(t, x) @@ -37,8 +57,8 @@ def fit(self, t, m, x, y): @fitted def estimate(self, t, m, x, y): """Estimates causal effect on data - """ + t, m, x, y = self._resize(t, m, x, y) p_x, p_xm = self._estimate_treatment_probabilities(t, m, x) diff --git a/src/med_bench/estimation/mediation_mr.py b/src/med_bench/estimation/mediation_mr.py index 655768e..8a52057 100644 --- a/src/med_bench/estimation/mediation_mr.py +++ b/src/med_bench/estimation/mediation_mr.py @@ -6,15 +6,38 @@ class MultiplyRobust(Estimator): - """Implementation of multiply robust estimator + """Iniitializes Multiply Robust estimatation method class """ - def __init__(self, ratio: str, clip: float, normalized, **kwargs): + def __init__(self, regressor, classifier, ratio: str, normalized, **kwargs): + """Initializes MulitplyRobust estimatation method + + Parameters + ---------- + regressor + Regressor used for mu estimation, can be any object with a fit and predict method + classifier + Classifier used for propensity estimation, can be any object with a fit and predict_proba method + ratio : str + Ratio to use for estimation, can be either 'density' or 'propensities' + normalized : bool + Whether to normalize the propensity scores + """ super().__init__(**kwargs) + assert hasattr( + regressor, 'fit'), "The model does not have a 'fit' method." + assert hasattr( + regressor, 'predict'), "The model does not have a 'predict' method." + assert hasattr( + classifier, 'fit'), "The model does not have a 'fit' method." + assert hasattr( + classifier, 'predict_proba'), "The model does not have a 'predict_proba' method." + self.regressor = regressor + self.classifier = classifier + assert ratio in ['density', 'propensities'] self._ratio = ratio - self._clip = clip self._normalized = normalized def fit(self, t, m, x, y): diff --git a/src/med_bench/estimation/mediation_tmle.py b/src/med_bench/estimation/mediation_tmle.py index 21de660..4f53d72 100644 --- a/src/med_bench/estimation/mediation_tmle.py +++ b/src/med_bench/estimation/mediation_tmle.py @@ -10,25 +10,35 @@ class TMLE(Estimator): - """Implementation of targeted maximum likelihood estimator - - Parameters - ---------- - settings (dict): dictionnary of parameters - lbda (float): regularization parameter - support_vec_tol (float): tolerance for discarding non-supporting vectors - if |alpha_i| < support_vec_tol * lbda then vector is discarded - verbose (int): in {0, 1} + """Implementation of targeted maximum likelihood estimation method class """ - def __init__(self, procedure, ratio, clip, normalized, **kwargs): + def __init__(self, regressor, classifier, ratio, **kwargs): + """_summary_ + + Parameters + ---------- + regressor + Regressor used for mu estimation, can be any object with a fit and predict method + classifier + Classifier used for propensity estimation, can be any object with a fit and predict_proba method + ratio : str + Ratio to use for estimation, can be either 'density' or 'propensities' + """ super().__init__(**kwargs) - self._crossfit = 0 - self._procedure = procedure + assert hasattr( + regressor, 'fit'), "The model does not have a 'fit' method." + assert hasattr( + regressor, 'predict'), "The model does not have a 'predict' method." + assert hasattr( + classifier, 'fit'), "The model does not have a 'fit' method." + assert hasattr( + classifier, 'predict_proba'), "The model does not have a 'predict_proba' method." + self.regressor = regressor + self.classifier = classifier + self._ratio = ratio - self._clip = clip - self._normalized = normalized def _one_step_correction_direct(self, t, m, x, y): @@ -130,13 +140,6 @@ def _one_step_correction_indirect(self, t, m, x, y): regressor_y = _get_regressor(self._regularize, self._use_forest) - # reg_cross.fit(x, (mu_t1_mx_star).squeeze()) - - # omega_t = reg_cross.predict(x) - # c_corrector = (2*t - 1)/p_x[:, None] - # reg = LinearRegression(fit_intercept=False).fit(c_corrector.reshape(-1, 1)[t==0], (mu_t1_mx_star - omega_t).squeeze()) - # epsilon_c = reg.coef_ - reg_cross = clone(regressor_y) reg_cross.fit(x[t == 0], mu_t1_mx_star[t == 0]) omega_t0x = reg_cross.predict(x) From 47a3723bd2728c81cc3c80c84aca58f37852c5f9 Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 13 Nov 2024 17:57:49 +0100 Subject: [PATCH 50/84] Fixed GComputation --- src/med_bench/estimation/base.py | 71 +++++++++---------- .../estimation/mediation_g_computation.py | 61 +++++++++++----- 2 files changed, 78 insertions(+), 54 deletions(-) diff --git a/src/med_bench/estimation/base.py b/src/med_bench/estimation/base.py index b4ae037..0f6cd7a 100644 --- a/src/med_bench/estimation/base.py +++ b/src/med_bench/estimation/base.py @@ -355,25 +355,32 @@ def _estimate_mediators_probabilities(self, t, m, x, y): Returns ------- - f_t0: list - contains array-like, shape (n_samples) probabilities f(M=m|T=0,X) - f_t1, list - contains array-like, shape (n_samples) probabilities f(M=m|T=1,X) + f_00x: array-like, shape (n_samples) + probabilities f(M=0|T=0,X) + f_01x, array-like, shape (n_samples) + probabilities f(M=0|T=1,X) + f_10x, array-like, shape (n_samples) + probabilities f(M=1|T=0,X) + f_11x, array-like, shape (n_samples) + probabilities f(M=1|T=1,X) """ n = len(y) t0 = np.zeros((n, 1)) t1 = np.ones((n, 1)) - m = m.ravel() - t0_x = np.hstack([t0.reshape(-1, 1), x]) t1_x = np.hstack([t1.reshape(-1, 1), x]) - f_t0 = self._classifier_m.predict_proba(t0_x)[:, 1] - f_t1 = self._classifier_m.predict_proba(t1_x)[:, 1] + # predict f(M=m|T=t,X) + fm_0 = self._classifier_m.predict_proba(t0_x) + f_00x = fm_0[:, 0] + f_01x = fm_0[:, 1] + fm_1 = self._classifier_m.predict_proba(t1_x) + f_10x = fm_1[:, 0] + f_11x = fm_1[:, 1] - return f_t0, f_t1 + return f_00x, f_01x, f_10x, f_11x def _estimate_treatment_propensity_x(self, t, m, x): """ @@ -422,41 +429,33 @@ def _estimate_conditional_mean_outcome(self, t, m, x, y): Returns ------- - mu_t0: list - contains array-like, shape (n_samples) conditional mean outcome estimates E[Y|T=0,M=m,X] - mu_t1, list - contains array-like, shape (n_samples) conditional mean outcome estimates E[Y|T=1,M=m,X] - mu_m0x, array-like, shape (n_samples) - conditional mean outcome estimates E[Y|T=0,M,X] - mu_m1x, array-like, shape (n_samples) - conditional mean outcome estimates E[Y|T=1,M,X] + mu_00x: array-like, shape (n_samples) + conditional mean outcome estimates E[Y|T=0,M=0,X] + mu_01x, array-like, shape (n_samples) + conditional mean outcome estimates E[Y|T=0,M=1,X] + mu_10x, array-like, shape (n_samples) + conditional mean outcome estimates E[Y|T=1,M=0,X] + mu_11x, array-like, shape (n_samples) + conditional mean outcome estimates E[Y|T=1,M=1,X] """ n = len(y) t0 = np.zeros((n, 1)) t1 = np.ones((n, 1)) - intercept = np.ones((n, 1)) + m0 = np.zeros((n, 1)) + m1 = np.ones((n, 1)) - mu_t1, mu_t0 = [], [] + x_t1_m1 = np.hstack([x, t1.reshape(-1, 1), m1]) + x_t1_m0 = np.hstack([x, t1.reshape(-1, 1), m0]) + x_t0_m1 = np.hstack([x, t0.reshape(-1, 1), m1]) + x_t0_m0 = np.hstack([x, t0.reshape(-1, 1), m0]) - x_t1_m = np.hstack([x, t1.reshape(-1, 1), m]) - x_t0_m = np.hstack([x, t0.reshape(-1, 1), m]) - - # predict E[Y|T=t,M,X] for all indices - mu_0mx = self._regressor_y.predict(x_t0_m).squeeze() - mu_1mx = self._regressor_y.predict(x_t1_m).squeeze() - - for i, b in enumerate(np.unique(m)): - mb = intercept * b - x_t1_mb = np.hstack([x, t1.reshape(-1, 1), mb]) - x_t0_mb = np.hstack([x, t0.reshape(-1, 1), mb]) - # predict E[Y|T=t,M=m,X] for all indices - mu_0bx = self._regressor_y.predict(x_t0_mb).squeeze() - mu_1bx = self._regressor_y.predict(x_t1_mb).squeeze() - mu_t0.append(mu_0bx) - mu_t1.append(mu_1bx) + mu_00x = self._regressor_y.predict(x_t0_m0) + mu_01x = self._regressor_y.predict(x_t0_m1) + mu_10x = self._regressor_y.predict(x_t1_m0) + mu_11x = self._regressor_y.predict(x_t1_m1) - return mu_t0, mu_t1, mu_0mx, mu_1mx + return mu_00x, mu_01x, mu_10x, mu_11x def _estimate_cross_conditional_mean_outcome_nesting(self, m, x, y): """ diff --git a/src/med_bench/estimation/mediation_g_computation.py b/src/med_bench/estimation/mediation_g_computation.py index c33006d..2726ac5 100644 --- a/src/med_bench/estimation/mediation_g_computation.py +++ b/src/med_bench/estimation/mediation_g_computation.py @@ -38,7 +38,12 @@ def fit(self, t, m, x, y): """ t, m, x, y = self._resize(t, m, x, y) - self._fit_cross_conditional_mean_outcome_nuisance(t, m, x, y) + if is_array_integer(m): + self._fit_mediator_nuisance(t, m, x, y) + self._fit_conditional_mean_outcome_nuisance + else: + self._fit_cross_conditional_mean_outcome_nuisance(t, m, x, y) + self._fitted = True if self.verbose: @@ -51,25 +56,45 @@ def estimate(self, t, m, x, y): """Estimates causal effect on data """ - t, m, x, y = self._resize(t, m, x, y) - (mu_0mx, mu_1mx, y0m0, y0m1, y1m0, y1m1) = self._estimate_cross_conditional_mean_outcome_nesting( - m, x, y) - - # mean score computing - eta_t1t1 = np.mean(y1m1) - eta_t0t0 = np.mean(y0m0) - eta_t1t0 = np.mean(y1m0) - eta_t0t1 = np.mean(y0m1) - - # effects computing - total_effect = eta_t1t1 - eta_t0t0 - - direct_effect_treated = eta_t1t1 - eta_t0t1 - direct_effect_control = eta_t1t0 - eta_t0t0 - indirect_effect_treated = eta_t1t1 - eta_t1t0 - indirect_effect_control = eta_t0t1 - eta_t0t0 + if is_array_integer(m): + mu_00x, mu_01x, mu_10x, mu_11x = self._estimate_mediators_probabilities( + t, m, x, y) + f_00x, f_01x, f_10x, f_11x = self._estimate_conditional_mean_outcome( + t, m, x, y) + + direct_effect_i1 = mu_11x - mu_01x + direct_effect_i0 = mu_10x - mu_00x + n = len(y) + direct_effect_treated = (direct_effect_i1 * f_11x + + direct_effect_i0 * f_10x).sum() / n + direct_effect_control = (direct_effect_i1 * f_01x + + direct_effect_i0 * f_00x).sum() / n + indirect_effect_i1 = f_11x - f_01x + indirect_effect_i0 = f_10x - f_00x + indirect_effect_treated = (indirect_effect_i1 * mu_11x + + indirect_effect_i0 * mu_10x).sum() / n + indirect_effect_control = (indirect_effect_i1 * mu_01x + + indirect_effect_i0 * mu_00x).sum() / n + total_effect = direct_effect_control + indirect_effect_treated + else: + (mu_0mx, mu_1mx, y0m0, y0m1, y1m0, y1m1) = self._estimate_cross_conditional_mean_outcome_nesting( + m, x, y) + + # mean score computing + eta_t1t1 = np.mean(y1m1) + eta_t0t0 = np.mean(y0m0) + eta_t1t0 = np.mean(y1m0) + eta_t0t1 = np.mean(y0m1) + + # effects computing + total_effect = eta_t1t1 - eta_t0t0 + + direct_effect_treated = eta_t1t1 - eta_t0t1 + direct_effect_control = eta_t1t0 - eta_t0t0 + indirect_effect_treated = eta_t1t1 - eta_t1t0 + indirect_effect_control = eta_t0t1 - eta_t0t0 causal_effects = { 'total_effect': total_effect, From 192ea20e89f87a9dbbcb7e5f4cd625cfeb1df784 Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 13 Nov 2024 23:14:27 +0100 Subject: [PATCH 51/84] tests refactor --- src/med_bench/estimation/base.py | 2 +- .../estimation/mediation_g_computation.py | 8 +- src/med_bench/get_estimation.py | 135 +++-- src/med_bench/get_estimation_results.py | 529 ++++++++++++++++++ src/tests/estimation/test_exact_estimation.py | 109 ---- src/tests/estimation/test_get_estimation.py | 122 +++- 6 files changed, 723 insertions(+), 182 deletions(-) create mode 100644 src/med_bench/get_estimation_results.py delete mode 100644 src/tests/estimation/test_exact_estimation.py diff --git a/src/med_bench/estimation/base.py b/src/med_bench/estimation/base.py index cdd8b73..6bfa501 100644 --- a/src/med_bench/estimation/base.py +++ b/src/med_bench/estimation/base.py @@ -156,7 +156,7 @@ def _fit_treatment_propensity_xm_nuisance(self, t, m, x): return self # TODO : Enable any sklearn object as classifier or regressor - def _fit_mediator_nuisance(self, t, m, x): + def _fit_mediator_nuisance(self, t, m, x, y): """Fits the nuisance parameter for the density f(M=m|T, X)""" # estimate mediator densities clf_param_grid = {} diff --git a/src/med_bench/estimation/mediation_g_computation.py b/src/med_bench/estimation/mediation_g_computation.py index b531640..a813b41 100644 --- a/src/med_bench/estimation/mediation_g_computation.py +++ b/src/med_bench/estimation/mediation_g_computation.py @@ -13,9 +13,9 @@ def __init__(self, regressor, classifier, **kwargs): Parameters ---------- - regressor + regressor Regressor used for mu estimation, can be any object with a fit and predict method - classifier + classifier Classifier used for propensity estimation, can be any object with a fit and predict_proba method """ super().__init__(**kwargs) @@ -37,7 +37,7 @@ def fit(self, t, m, x, y): if is_array_integer(m): self._fit_mediator_nuisance(t, m, x, y) - self._fit_conditional_mean_outcome_nuisance + self._fit_conditional_mean_outcome_nuisance(t, m, x, y) else: self._fit_cross_conditional_mean_outcome_nuisance(t, m, x, y) @@ -48,7 +48,7 @@ def fit(self, t, m, x, y): return self - @fitted + @ fitted def estimate(self, t, m, x, y): """Estimates causal effect on data diff --git a/src/med_bench/get_estimation.py b/src/med_bench/get_estimation.py index 8245c81..c58e2a2 100644 --- a/src/med_bench/get_estimation.py +++ b/src/med_bench/get_estimation.py @@ -17,7 +17,7 @@ from med_bench.estimation.mediation_coefficient_product import CoefficientProduct from med_bench.estimation.mediation_dml import DoubleMachineLearning from med_bench.estimation.mediation_g_computation import GComputation -from med_bench.estimation.mediation_ipw import ImportanceWeighting +from med_bench.estimation.mediation_ipw import InversePropensityWeighting from med_bench.estimation.mediation_mr import MultiplyRobust from med_bench.nuisances.utils import _get_regularization_parameters from med_bench.utils.constants import CV_FOLDS @@ -26,6 +26,7 @@ from sklearn.linear_model import LogisticRegressionCV, RidgeCV from sklearn.calibration import CalibratedClassifierCV + def transform_outputs(causal_effects): """Transforms outputs in the old format @@ -42,6 +43,7 @@ def transform_outputs(causal_effects): indirect_control = causal_effects['indirect_effect_control'] return [total, direct_treated, direct_control, indirect_treated, indirect_control, 0] + def get_estimation(x, t, m, y, estimator, config): """Wrapper estimator fonction ; calls an estimator given mediation data in order to estimate total, direct, and indirect effects. @@ -89,9 +91,12 @@ def get_estimation(x, t, m, y, estimator, config): effects = raw_res_R[0, :] elif estimator == "coefficient_product": effects = mediation_coefficient_product(y, t, m, x) - clf = RandomForestClassifier(random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10, random_state=42) - estimator = CoefficientProduct(regressor=reg, classifier=clf, regularize=True) + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + estimator = CoefficientProduct( + regressor=reg, classifier=clf, regularize=True) estimator.fit(t, m, x, y) causal_effects = estimator.estimate(t, m, x, y) effects = transform_outputs(causal_effects) @@ -112,7 +117,7 @@ def get_estimation(x, t, m, y, estimator, config): cs, alphas = _get_regularization_parameters(regularization=False) clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) - estimator = ImportanceWeighting( + estimator = InversePropensityWeighting( clip=1e-6, trim=0, regressor=reg, classifier=clf ) estimator.fit(t, m, x, y) @@ -147,7 +152,7 @@ def get_estimation(x, t, m, y, estimator, config): cs, alphas = _get_regularization_parameters(regularization=True) clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) - estimator = ImportanceWeighting( + estimator = InversePropensityWeighting( clip=1e-6, trim=0, regressor=reg, classifier=clf ) estimator.fit(t, m, x, y) @@ -182,7 +187,7 @@ def get_estimation(x, t, m, y, estimator, config): cs, alphas = _get_regularization_parameters(regularization=True) clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) - estimator = ImportanceWeighting( + estimator = InversePropensityWeighting( clip=1e-6, trim=0, regressor=reg, classifier=CalibratedClassifierCV(clf, method="sigmoid") ) estimator.fit(t, m, x, y) @@ -204,7 +209,7 @@ def get_estimation(x, t, m, y, estimator, config): cs, alphas = _get_regularization_parameters(regularization=True) clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) - estimator = ImportanceWeighting( + estimator = InversePropensityWeighting( clip=1e-6, trim=0, regressor=reg, classifier=CalibratedClassifierCV(clf, method="isotonic") ) estimator.fit(t, m, x, y) @@ -250,9 +255,11 @@ def get_estimation(x, t, m, y, estimator, config): calibration=None, ) cs, alphas = _get_regularization_parameters(regularization=True) - clf = RandomForestClassifier(random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10, random_state=42) - estimator = ImportanceWeighting( + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + estimator = InversePropensityWeighting( clip=1e-6, trim=0, regressor=reg, classifier=clf ) estimator.fit(t, m, x, y) @@ -285,9 +292,11 @@ def get_estimation(x, t, m, y, estimator, config): calibration=None, ) cs, alphas = _get_regularization_parameters(regularization=True) - clf = RandomForestClassifier(random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10, random_state=42) - estimator = ImportanceWeighting( + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + estimator = InversePropensityWeighting( clip=1e-6, trim=0, regressor=reg, classifier=CalibratedClassifierCV(clf, method="sigmoid") ) estimator.fit(t, m, x, y) @@ -307,9 +316,11 @@ def get_estimation(x, t, m, y, estimator, config): calibration="isotonic", ) cs, alphas = _get_regularization_parameters(regularization=True) - clf = RandomForestClassifier(random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10, random_state=42) - estimator = ImportanceWeighting( + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + estimator = InversePropensityWeighting( clip=1e-6, trim=0, regressor=reg, classifier=CalibratedClassifierCV(clf, method="isotonic") ) estimator.fit(t, m, x, y) @@ -423,7 +434,8 @@ def get_estimation(x, t, m, y, estimator, config): cs, alphas = _get_regularization_parameters(regularization=True) clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) - estimator = GComputation(regressor=reg, classifier=CalibratedClassifierCV(clf, method="sigmoid")) + estimator = GComputation( + regressor=reg, classifier=CalibratedClassifierCV(clf, method="sigmoid")) estimator.fit(t, m, x, y) causal_effects = estimator.estimate(t, m, x, y) effects = transform_outputs(causal_effects) @@ -443,7 +455,8 @@ def get_estimation(x, t, m, y, estimator, config): cs, alphas = _get_regularization_parameters(regularization=True) clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) - estimator = GComputation(regressor=reg, classifier=CalibratedClassifierCV(clf, method="isotonic")) + estimator = GComputation( + regressor=reg, classifier=CalibratedClassifierCV(clf, method="isotonic")) estimator.fit(t, m, x, y) causal_effects = estimator.estimate(t, m, x, y) effects = transform_outputs(causal_effects) @@ -487,8 +500,10 @@ def get_estimation(x, t, m, y, estimator, config): calibration=None, ) cs, alphas = _get_regularization_parameters(regularization=True) - clf = RandomForestClassifier(random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10, random_state=42) + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) estimator = GComputation(regressor=reg, classifier=clf) estimator.fit(t, m, x, y) causal_effects = estimator.estimate(t, m, x, y) @@ -520,9 +535,12 @@ def get_estimation(x, t, m, y, estimator, config): calibration='sigmoid', ) cs, alphas = _get_regularization_parameters(regularization=True) - clf = RandomForestClassifier(random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10, random_state=42) - estimator = GComputation(regressor=reg, classifier=CalibratedClassifierCV(clf, method="sigmoid")) + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + estimator = GComputation( + regressor=reg, classifier=CalibratedClassifierCV(clf, method="sigmoid")) estimator.fit(t, m, x, y) causal_effects = estimator.estimate(t, m, x, y) effects = transform_outputs(causal_effects) @@ -541,9 +559,12 @@ def get_estimation(x, t, m, y, estimator, config): calibration="isotonic", ) cs, alphas = _get_regularization_parameters(regularization=True) - clf = RandomForestClassifier(random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10, random_state=42) - estimator = GComputation(regressor=reg, classifier=CalibratedClassifierCV(clf, method="isotonic")) + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + estimator = GComputation( + regressor=reg, classifier=CalibratedClassifierCV(clf, method="isotonic")) estimator.fit(t, m, x, y) causal_effects = estimator.estimate(t, m, x, y) effects = transform_outputs(causal_effects) @@ -592,8 +613,8 @@ def get_estimation(x, t, m, y, estimator, config): clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) estimator = MultiplyRobust( - clip=1e-6, ratio="propensities", normalized=True, regressor=reg, - classifier=clf) + clip=1e-6, ratio="propensities", normalized=True, regressor=reg, + classifier=clf) estimator.fit(t, m, x, y) causal_effects = estimator.estimate(t, m, x, y) effects = transform_outputs(causal_effects) @@ -630,8 +651,8 @@ def get_estimation(x, t, m, y, estimator, config): clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) estimator = MultiplyRobust( - clip=1e-6, ratio="propensities", normalized=True, regressor=reg, - classifier=clf) + clip=1e-6, ratio="propensities", normalized=True, regressor=reg, + classifier=clf) estimator.fit(t, m, x, y) causal_effects = estimator.estimate(t, m, x, y) effects = transform_outputs(causal_effects) @@ -667,8 +688,8 @@ def get_estimation(x, t, m, y, estimator, config): clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) estimator = MultiplyRobust( - clip=1e-6, ratio="propensities", normalized=True, regressor=reg, - classifier=CalibratedClassifierCV(clf, method="sigmoid")) + clip=1e-6, ratio="propensities", normalized=True, regressor=reg, + classifier=CalibratedClassifierCV(clf, method="sigmoid")) estimator.fit(t, m, x, y) causal_effects = estimator.estimate(t, m, x, y) effects = transform_outputs(causal_effects) @@ -690,8 +711,8 @@ def get_estimation(x, t, m, y, estimator, config): clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) estimator = MultiplyRobust( - clip=1e-6, ratio="propensities", normalized=True, regressor=reg, - classifier=CalibratedClassifierCV(clf, method="isotonic")) + clip=1e-6, ratio="propensities", normalized=True, regressor=reg, + classifier=CalibratedClassifierCV(clf, method="isotonic")) estimator.fit(t, m, x, y) causal_effects = estimator.estimate(t, m, x, y) effects = transform_outputs(causal_effects) @@ -738,11 +759,13 @@ def get_estimation(x, t, m, y, estimator, config): calibration=None, ) cs, alphas = _get_regularization_parameters(regularization=False) - clf = RandomForestClassifier(random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10, random_state=42) + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) estimator = MultiplyRobust( - clip=1e-6, ratio="propensities", normalized=True, regressor=reg, - classifier=clf) + clip=1e-6, ratio="propensities", normalized=True, regressor=reg, + classifier=clf) estimator.fit(t, m, x, y) causal_effects = estimator.estimate(t, m, x, y) effects = transform_outputs(causal_effects) @@ -775,11 +798,13 @@ def get_estimation(x, t, m, y, estimator, config): calibration='sigmoid', ) cs, alphas = _get_regularization_parameters(regularization=False) - clf = RandomForestClassifier(random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10, random_state=42) + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) estimator = MultiplyRobust( - clip=1e-6, ratio="propensities", normalized=True, regressor=reg, - classifier=CalibratedClassifierCV(clf, method="sigmoid")) + clip=1e-6, ratio="propensities", normalized=True, regressor=reg, + classifier=CalibratedClassifierCV(clf, method="sigmoid")) estimator.fit(t, m, x, y) causal_effects = estimator.estimate(t, m, x, y) effects = transform_outputs(causal_effects) @@ -798,11 +823,13 @@ def get_estimation(x, t, m, y, estimator, config): calibration="isotonic", ) cs, alphas = _get_regularization_parameters(regularization=False) - clf = RandomForestClassifier(random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10, random_state=42) + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) estimator = MultiplyRobust( - clip=1e-6, ratio="propensities", normalized=True, regressor=reg, - classifier=CalibratedClassifierCV(clf, method="isotonic")) + clip=1e-6, ratio="propensities", normalized=True, regressor=reg, + classifier=CalibratedClassifierCV(clf, method="isotonic")) estimator.fit(t, m, x, y) causal_effects = estimator.estimate(t, m, x, y) effects = transform_outputs(causal_effects) @@ -859,7 +886,7 @@ def get_estimation(x, t, m, y, estimator, config): estimator.fit(t, m, x, y) causal_effects = estimator.estimate(t, m, x, y) effects = transform_outputs(causal_effects) - + elif estimator == "mediation_dml_reg": effects = mediation_dml( y, t, m, x, trim=0, clip=1e-6, calibration=None) @@ -913,8 +940,10 @@ def get_estimation(x, t, m, y, estimator, config): calibration=None, forest=True) cs, alphas = _get_regularization_parameters(regularization=True) - clf = RandomForestClassifier(random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10, random_state=42) + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) estimator = DoubleMachineLearning( clip=1e-6, trim=0, normalized=True, regressor=reg, classifier=clf ) @@ -933,8 +962,10 @@ def get_estimation(x, t, m, y, estimator, config): calibration='sigmoid', forest=True) cs, alphas = _get_regularization_parameters(regularization=True) - clf = RandomForestClassifier(random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10, random_state=42) + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) estimator = DoubleMachineLearning( clip=1e-6, trim=0, normalized=True, regressor=reg, classifier=CalibratedClassifierCV(clf, method="sigmoid") ) diff --git a/src/med_bench/get_estimation_results.py b/src/med_bench/get_estimation_results.py new file mode 100644 index 0000000..5498021 --- /dev/null +++ b/src/med_bench/get_estimation_results.py @@ -0,0 +1,529 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import numpy as np + +from .mediation import ( + mediation_IPW, + mediation_g_formula, + mediation_multiply_robust, + mediation_dml, + r_mediation_g_estimator, + r_mediation_dml, + r_mediate, +) + +from med_bench.estimation.mediation_coefficient_product import CoefficientProduct +from med_bench.estimation.mediation_dml import DoubleMachineLearning +from med_bench.estimation.mediation_g_computation import GComputation +from med_bench.estimation.mediation_ipw import InversePropensityWeighting +from med_bench.estimation.mediation_mr import MultiplyRobust +from med_bench.nuisances.utils import _get_regularization_parameters +from med_bench.utils.constants import CV_FOLDS + +from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor +from sklearn.linear_model import LogisticRegressionCV, RidgeCV +from sklearn.calibration import CalibratedClassifierCV + + +def transform_outputs(causal_effects): + """Transforms outputs in the old format + + Args: + causal_effects (dict): dictionary of causal effects + + Returns: + list: list of causal effects + """ + total = causal_effects['total_effect'] + direct_treated = causal_effects['direct_effect_treated'] + direct_control = causal_effects['direct_effect_control'] + indirect_treated = causal_effects['indirect_effect_treated'] + indirect_control = causal_effects['indirect_effect_control'] + return [total, direct_treated, direct_control, indirect_treated, indirect_control, 0] + + +def get_estimation_results(x, t, m, y, estimator, config): + """Dynamically selects and calls an estimator (class-based or legacy function) to estimate total, direct, and indirect effects.""" + + effects = None # Initialize variable to store the effects + + # Helper function for regularized regressor and classifier initialization + def get_regularized_regressor_and_classifier(regularize=True, calibration=None, method="sigmoid"): + cs, alphas = _get_regularization_parameters(regularization=regularize) + clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) + reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) + if calibration: + clf = CalibratedClassifierCV(clf, method=method) + return clf, reg + + if estimator == "mediation_IPW_R": + # Use R-based mediation estimator with direct output extraction + x_r, t_r, m_r, y_r = [_convert_array_to_R(uu) for uu in (x, t, m, y)] + output_w = causalweight.medweight( + y=y_r, d=t_r, m=m_r, x=x_r, trim=0.0, ATET="FALSE", logit="TRUE", boot=2 + ) + raw_res_R = np.array(output_w.rx2("results")) + effects = raw_res_R[0, :] + + elif estimator == "coefficient_product": + # Class-based implementation for CoefficientProduct + estimator_obj = CoefficientProduct(regularize=True) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + + elif estimator == "mediation_ipw_noreg": + # Class-based implementation for InversePropensityWeighting without regularization + clf, reg = get_regularized_regressor_and_classifier(regularize=False) + estimator_obj = InversePropensityWeighting( + clip=1e-6, trim=0, regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + + elif estimator == "mediation_ipw_noreg_cf": + # Legacy function for crossfit with no regularization + effects = mediation_IPW( + y, t, m, x, trim=0, regularization=False, forest=False, crossfit=2, clip=1e-6, calibration=None + ) + + elif estimator == "mediation_ipw_reg": + # Class-based implementation with regularization + clf, reg = get_regularized_regressor_and_classifier(regularize=True) + estimator_obj = InversePropensityWeighting( + clip=1e-6, trim=0, regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + + elif estimator == "mediation_ipw_reg_cf": + # Legacy function with crossfit and regularization + effects = mediation_IPW( + y, t, m, x, trim=0, regularization=True, forest=False, crossfit=2, clip=1e-6, calibration=None + ) + + elif estimator == "mediation_ipw_reg_calibration": + # Class-based implementation with regularization and calibration (sigmoid) + clf, reg = get_regularized_regressor_and_classifier( + regularize=True, calibration=True, method="sigmoid") + estimator_obj = InversePropensityWeighting( + clip=1e-6, trim=0, regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + + elif estimator == "mediation_ipw_reg_calibration_iso": + # Class-based implementation with isotonic calibration + clf, reg = get_regularized_regressor_and_classifier( + regularize=True, calibration=True, method="isotonic") + estimator_obj = InversePropensityWeighting( + clip=1e-6, trim=0, regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + + elif estimator == "mediation_ipw_reg_calibration_cf": + # Legacy function with crossfit and sigmoid calibration + effects = mediation_IPW( + y, t, m, x, trim=0, regularization=True, forest=False, crossfit=2, clip=1e-6, calibration="sigmoid" + ) + + elif estimator == "mediation_ipw_reg_calibration_iso_cf": + # Legacy function with crossfit and isotonic calibration + effects = mediation_IPW( + y, t, m, x, trim=0, regularization=True, forest=False, crossfit=2, clip=1e-6, calibration="isotonic" + ) + + elif estimator == "mediation_ipw_forest": + # Class-based implementation with forest models + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + estimator_obj = InversePropensityWeighting( + clip=1e-6, trim=0, regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + + elif estimator == "mediation_ipw_forest_cf": + # Legacy function with forest and crossfit + effects = mediation_IPW( + y, t, m, x, trim=0, regularization=True, forest=True, crossfit=2, clip=1e-6, calibration=None + ) + + elif estimator == "mediation_ipw_forest_calibration": + # Class-based implementation with forest and calibrated sigmoid + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + calibrated_clf = CalibratedClassifierCV(clf, method="sigmoid") + estimator_obj = InversePropensityWeighting( + clip=1e-6, trim=0, regressor=reg, classifier=calibrated_clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + + elif estimator == "mediation_ipw_forest_calibration_iso": + # Class-based implementation with isotonic calibration + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + calibrated_clf = CalibratedClassifierCV(clf, method="isotonic") + estimator_obj = InversePropensityWeighting( + clip=1e-6, trim=0, regressor=reg, classifier=calibrated_clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + + elif estimator == "mediation_g_computation_noreg": + # Class-based implementation of GComputation without regularization + clf, reg = get_regularized_regressor_and_classifier(regularize=False) + estimator_obj = GComputation(regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + + elif estimator == "mediation_g_computation_noreg_cf": + # Legacy function with crossfit and no regularization + effects = mediation_g_formula( + y, t, m, x, interaction=False, forest=False, crossfit=2, regularization=False, calibration=None + ) + + elif estimator == "mediation_g_computation_reg": + # Class-based implementation of GComputation with regularization + clf, reg = get_regularized_regressor_and_classifier(regularize=True) + estimator_obj = GComputation(regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + + elif estimator == "mediation_g_computation_reg_cf": + # Legacy function with regularization and crossfit + effects = mediation_g_formula( + y, t, m, x, interaction=False, forest=False, crossfit=2, regularization=True, calibration=None + ) + + elif estimator == "mediation_g_computation_forest_cf": + if config in (0, 1, 2): + effects = mediation_g_formula( + y, + t, + m, + x, + interaction=False, + forest=True, + crossfit=2, + regularization=True, + calibration=None, + ) + + elif estimator == "mediation_g_computation_reg_calibration": + # Class-based implementation with regularization and calibrated sigmoid + clf, reg = get_regularized_regressor_and_classifier( + regularize=True, calibration=True, method="sigmoid") + estimator_obj = GComputation(regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + + elif estimator == "mediation_g_computation_reg_calibration_iso": + # Class-based implementation with isotonic calibration + clf, reg = get_regularized_regressor_and_classifier( + regularize=True, calibration=True, method="isotonic") + estimator_obj = GComputation(regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + + elif estimator == "mediation_g_computation_forest": + # Class-based implementation with forest models + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + estimator_obj = GComputation(regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + + elif estimator == "mediation_multiply_robust_noreg": + # Class-based implementation for MultiplyRobust without regularization + clf, reg = get_regularized_regressor_and_classifier(regularize=False) + estimator_obj = MultiplyRobust( + ratio="propensities", normalized=True, regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + + elif estimator == "simulation_based": + # R-based function for simulation + effects = r_mediate(y, t, m, x, interaction=False) + + elif estimator == "mediation_dml": + # R-based function for Double Machine Learning with legacy config + effects = r_mediation_dml(y, t, m, x, trim=0.0, order=1) + + elif estimator == "mediation_dml_noreg": + # Class-based implementation for DoubleMachineLearning without regularization + clf, reg = get_regularized_regressor_and_classifier(regularize=False) + estimator_obj = DoubleMachineLearning( + clip=1e-6, trim=0, normalized=True, regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + + # Regularized, crossfitting, calibration (isotonic) for InversePropensityWeighting + elif estimator == "mediation_ipw_reg_calibration_iso_cf": + effects = mediation_IPW( + y, t, m, x, trim=0, regularization=True, forest=False, crossfit=2, clip=1e-6, calibration="isotonic" + ) + + # Forest and crossfit with sigmoid calibration for InversePropensityWeighting + elif estimator == "mediation_ipw_forest_calibration_cf": + effects = mediation_IPW( + y, t, m, x, trim=0, regularization=True, forest=True, crossfit=2, clip=1e-6, calibration="sigmoid" + ) + + # Forest and crossfit with isotonic calibration for InversePropensityWeighting + elif estimator == "mediation_ipw_forest_calibration_iso_cf": + effects = mediation_IPW( + y, t, m, x, trim=0, regularization=True, forest=True, crossfit=2, clip=1e-6, calibration="isotonic" + ) + + # MultiplyRobust without regularization, with crossfitting + elif estimator == "mediation_multiply_robust_noreg_cf": + effects = mediation_multiply_robust( + y, t, m.astype(int), x, interaction=False, forest=False, crossfit=2, clip=1e-6, regularization=False, calibration=None + ) + + # Regularized MultiplyRobust estimator + elif estimator == "mediation_multiply_robust_reg": + clf, reg = get_regularized_regressor_and_classifier(regularize=True) + estimator_obj = MultiplyRobust( + ratio="propensities", normalized=True, regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + + # Regularized MultiplyRobust with crossfitting + elif estimator == "mediation_multiply_robust_reg_cf": + effects = mediation_multiply_robust( + y, t, m.astype(int), x, interaction=False, forest=False, crossfit=2, clip=1e-6, regularization=True, calibration=None + ) + + # Regularized MultiplyRobust with sigmoid calibration + elif estimator == "mediation_multiply_robust_reg_calibration": + clf, reg = get_regularized_regressor_and_classifier( + regularize=True, calibration=True, method="sigmoid") + estimator_obj = MultiplyRobust( + ratio="propensities", normalized=True, regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + + # Regularized MultiplyRobust with isotonic calibration + elif estimator == "mediation_multiply_robust_reg_calibration_iso": + clf, reg = get_regularized_regressor_and_classifier( + regularize=True, calibration=True, method="isotonic") + estimator_obj = MultiplyRobust( + ratio="propensities", normalized=True, regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + + # Regularized MultiplyRobust with sigmoid calibration and crossfitting + elif estimator == "mediation_multiply_robust_reg_calibration_cf": + effects = mediation_multiply_robust( + y, t, m.astype(int), x, interaction=False, forest=False, crossfit=2, clip=1e-6, regularization=True, calibration="sigmoid" + ) + + # Regularized MultiplyRobust with isotonic calibration and crossfitting + elif estimator == "mediation_multiply_robust_reg_calibration_iso_cf": + effects = mediation_multiply_robust( + y, t, m.astype(int), x, interaction=False, forest=False, crossfit=2, clip=1e-6, regularization=True, calibration="isotonic" + ) + + elif estimator == "mediation_multiply_robust_forest": + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + estimator = MultiplyRobust( + ratio="propensities", normalized=True, regressor=reg, + classifier=clf) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + + # MultiplyRobust with forest and crossfitting + elif estimator == "mediation_multiply_robust_forest_cf": + effects = mediation_multiply_robust( + y, t, m.astype(int), x, interaction=False, forest=True, crossfit=2, clip=1e-6, regularization=True, calibration=None + ) + + # MultiplyRobust with forest and sigmoid calibration + elif estimator == "mediation_multiply_robust_forest_calibration": + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + calibrated_clf = CalibratedClassifierCV(clf, method="sigmoid") + estimator_obj = MultiplyRobust( + ratio="propensities", normalized=True, regressor=reg, classifier=calibrated_clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + + # MultiplyRobust with forest and isotonic calibration + elif estimator == "mediation_multiply_robust_forest_calibration_iso": + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + calibrated_clf = CalibratedClassifierCV(clf, method="isotonic") + estimator_obj = MultiplyRobust( + ratio="propensities", normalized=True, regressor=reg, classifier=calibrated_clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + + # MultiplyRobust with forest, sigmoid calibration, and crossfitting + elif estimator == "mediation_multiply_robust_forest_calibration_cf": + effects = mediation_multiply_robust( + y, t, m.astype(int), x, interaction=False, forest=True, crossfit=2, clip=1e-6, regularization=True, calibration="sigmoid" + ) + + # MultiplyRobust with forest, isotonic calibration, and crossfitting + elif estimator == "mediation_multiply_robust_forest_calibration_iso_cf": + effects = mediation_multiply_robust( + y, t, m.astype(int), x, interaction=False, forest=True, crossfit=2, clip=1e-6, regularization=True, calibration="isotonic" + ) + + # Regularized Double Machine Learning + elif estimator == "mediation_dml_reg": + clf, reg = get_regularized_regressor_and_classifier(regularize=True) + estimator_obj = DoubleMachineLearning( + clip=1e-6, trim=0, normalized=True, regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + + # Double Machine Learning with fixed seed + elif estimator == "mediation_dml_reg_fixed_seed": + effects = mediation_dml( + y, t, m, x, trim=0, clip=1e-6, random_state=321, calibration=None) + + # Double Machine Learning without regularization, with crossfitting + elif estimator == "mediation_dml_noreg_cf": + effects = mediation_dml(y, t, m, x, trim=0, clip=1e-6, + crossfit=2, regularization=False, calibration=None) + + # Regularized Double Machine Learning with crossfitting + elif estimator == "mediation_dml_reg_cf": + effects = mediation_dml( + y, t, m, x, trim=0, clip=1e-6, crossfit=2, calibration=None) + + # Regularized Double Machine Learning with sigmoid calibration + elif estimator == "mediation_dml_reg_calibration": + clf, reg = get_regularized_regressor_and_classifier( + regularize=True, calibration=True, method="sigmoid") + estimator_obj = DoubleMachineLearning( + clip=1e-6, trim=0, normalized=True, regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + + # Regularized Double Machine Learning with forest models + elif estimator == "mediation_dml_forest": + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + estimator_obj = DoubleMachineLearning( + clip=1e-6, trim=0, normalized=True, regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + + # Double Machine Learning with forest and calibrated sigmoid + elif estimator == "mediation_dml_forest_calibration": + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + calibrated_clf = CalibratedClassifierCV(clf, method="sigmoid") + estimator_obj = DoubleMachineLearning( + clip=1e-6, trim=0, normalized=True, regressor=reg, classifier=calibrated_clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + + # Double Machine Learning with forest, crossfitting, and sigmoid calibration + elif estimator == "mediation_dml_reg_calibration_cf": + effects = mediation_dml( + y, t, m, x, trim=0, clip=1e-6, crossfit=2, calibration="sigmoid", forest=False) + + # Double Machine Learning with forest and crossfitting + elif estimator == "mediation_dml_forest_cf": + effects = mediation_dml( + y, t, m, x, trim=0, clip=1e-6, crossfit=2, calibration=None, forest=True) + + # Double Machine Learning with forest, crossfitting, and calibrated sigmoid + elif estimator == "mediation_dml_forest_calibration_cf": + effects = mediation_dml( + y, t, m, x, trim=0, clip=1e-6, crossfit=2, calibration="sigmoid", forest=True) + + # GComputation with regularization, crossfitting, and sigmoid calibration + elif estimator == "mediation_g_computation_reg_calibration_cf": + effects = mediation_g_formula( + y, t, m, x, interaction=False, forest=False, crossfit=2, regularization=True, calibration="sigmoid") + + # GComputation with forest and sigmoid calibration + elif estimator == "mediation_g_computation_forest_calibration": + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + calibrated_clf = CalibratedClassifierCV(clf, method="sigmoid") + estimator_obj = GComputation(regressor=reg, classifier=calibrated_clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + + # GComputation with forest and isotonic calibration + elif estimator == "mediation_g_computation_forest_calibration_iso": + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + calibrated_clf = CalibratedClassifierCV(clf, method="isotonic") + estimator_obj = GComputation(regressor=reg, classifier=calibrated_clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = transform_outputs(causal_effects) + + # GComputation with forest, crossfitting, and sigmoid calibration + elif estimator == "mediation_g_computation_forest_calibration_cf": + effects = mediation_g_formula( + y, t, m, x, interaction=False, forest=True, crossfit=2, regularization=True, calibration="sigmoid") + + # GComputation with forest, crossfitting, and isotonic calibration + elif estimator == "mediation_g_computation_forest_calibration_iso_cf": + effects = mediation_g_formula( + y, t, m, x, interaction=False, forest=True, crossfit=2, regularization=True, calibration="isotonic") + + elif estimator == "mediation_g_estimator": + if config in (0, 1, 2): + effects = r_mediation_g_estimator(y, t, m, x) + else: + raise ValueError("Unrecognized estimator label.") + + # Catch unsupported estimators and raise an error + if effects is None: + raise ValueError( + f"Estimation failed for {estimator}. Check inputs or configuration.") + return effects diff --git a/src/tests/estimation/test_exact_estimation.py b/src/tests/estimation/test_exact_estimation.py deleted file mode 100644 index 3e4fab1..0000000 --- a/src/tests/estimation/test_exact_estimation.py +++ /dev/null @@ -1,109 +0,0 @@ -""" -Pytest file for get_estimation.py - -It tests all the benchmark_mediation estimators : -- for a certain tolerance -- whether their effects satisfy "total = direct + indirect" -- whether they support (n,1) and (n,) inputs - -To be robust to future updates, tests are adjusted with a smaller tolerance when possible. -The test is skipped if estimator has not been implemented yet, i.e. if ValueError is raised. -The test fails for any other unwanted behavior. -""" - -from pprint import pprint -import pytest -import os -import numpy as np - -from med_bench.get_estimation import get_estimation -from med_bench.utils.constants import R_DEPENDENT_ESTIMATORS -from med_bench.utils.utils import DependencyNotInstalledError, check_r_dependencies - -current_dir = os.path.dirname(__file__) -true_estimations_file_path = os.path.join(current_dir, 'tests_results.npy') -TRUE_ESTIMATIONS = np.load(true_estimations_file_path, allow_pickle=True) - - -@pytest.fixture(params=range(TRUE_ESTIMATIONS.shape[0])) -def tests_results_idx(request): - return request.param - - -@pytest.fixture -def data(tests_results_idx): - return TRUE_ESTIMATIONS[tests_results_idx] - - -@pytest.fixture -def estimator(data): - return data[0] - - -@pytest.fixture -def x(data): - return data[1] - - -# t is raveled because some estimators fail with (n,1) inputs -@pytest.fixture -def t(data): - return data[2] - - -@pytest.fixture -def m(data): - return data[3] - - -@pytest.fixture -def y(data): - return data[4] - - -@pytest.fixture -def config(data): - return data[5] - - -@pytest.fixture -def result(data): - return data[6] - - -@pytest.fixture -def effects_chap(x, t, m, y, estimator, config): - # try whether estimator is implemented or not - - try: - res = get_estimation(x, t, m, y, estimator, config)[0:5] - - # NaN situations - if np.all(np.isnan(res)): - pytest.xfail("all effects are NaN") - elif np.any(np.isnan(res)): - pprint("NaN found") - - except Exception as e: - if str(e) in ( - "Estimator only supports 1D binary mediator.", - "Estimator does not support 1D binary mediator.", - ): - pytest.skip(f"{e}") - - # We skip the test if an error with function from glmet rpy2 package occurs - elif "glmnet::glmnet" in str(e): - pytest.skip(f"{e}") - - elif estimator in R_DEPENDENT_ESTIMATORS and not check_r_dependencies(): - assert isinstance(e, DependencyNotInstalledError) == True - pytest.skip(f"{e}") - - else: - pytest.fail(f"{e}") - - return res - - -def test_estimation_exactness(result, effects_chap): - assert np.all(effects_chap == pytest.approx(result, abs=1.e-3)) diff --git a/src/tests/estimation/test_get_estimation.py b/src/tests/estimation/test_get_estimation.py index 9a99b90..04d57c8 100644 --- a/src/tests/estimation/test_get_estimation.py +++ b/src/tests/estimation/test_get_estimation.py @@ -14,48 +14,53 @@ from pprint import pprint import pytest import numpy as np +import os +from med_bench.get_estimation_results import get_estimation_results from med_bench.get_simulated_data import simulate_data -from med_bench.get_estimation import get_estimation - from med_bench.utils.utils import DependencyNotInstalledError, check_r_dependencies from med_bench.utils.constants import PARAMETER_LIST, PARAMETER_NAME, R_DEPENDENT_ESTIMATORS, TOLERANCE_DICT +current_dir = os.path.dirname(__file__) +true_estimations_file_path = os.path.join(current_dir, 'tests_results.npy') +TRUE_ESTIMATIONS = np.load(true_estimations_file_path, allow_pickle=True) + @pytest.fixture(params=PARAMETER_LIST) def dict_param(request): return dict(zip(PARAMETER_NAME, request.param)) +# Two distinct data fixtures @pytest.fixture -def data(dict_param): +def data_simulated(dict_param): return simulate_data(**dict_param) @pytest.fixture -def x(data): - return data[0] +def x(data_simulated): + return data_simulated[0] # t is raveled because some estimators fail with (n,1) inputs @pytest.fixture -def t(data): - return data[1].ravel() +def t(data_simulated): + return data_simulated[1].ravel() @pytest.fixture -def m(data): - return data[2] +def m(data_simulated): + return data_simulated[2] @pytest.fixture -def y(data): - return data[3].ravel() # same reason as t +def y(data_simulated): + return data_simulated[3].ravel() # same reason as t @pytest.fixture -def effects(data): - return np.array(data[4:9]) +def effects(data_simulated): + return np.array(data_simulated[4:9]) @pytest.fixture(params=list(TOLERANCE_DICT.keys())) @@ -80,7 +85,7 @@ def effects_chap(x, t, m, y, estimator, config): # try whether estimator is implemented or not try: - res = get_estimation(x, t, m, y, estimator, config)[0:5] + res = get_estimation_results(x, t, m, y, estimator, config)[0:5] except Exception as e: if str(e) in ( "Estimator only supports 1D binary mediator.", @@ -126,9 +131,94 @@ def test_robustness_to_ravel_format(data, estimator, config, effects_chap): if "forest" in estimator: pytest.skip("Forest estimator skipped") assert np.all( - get_estimation(data[0], data[1], data[2], - data[3], estimator, config)[0:5] + get_estimation_results(data[0], data[1], data[2], + data[3], estimator, config)[0:5] == pytest.approx( effects_chap, nan_ok=True ) # effects_chap is obtained with data[1].ravel() and data[3].ravel() ) + + +@pytest.fixture(params=range(TRUE_ESTIMATIONS.shape[0])) +def tests_results_idx(request): + return request.param + + +@pytest.fixture +def data_true(tests_results_idx): + return TRUE_ESTIMATIONS[tests_results_idx] + + +@pytest.fixture +def estimator_true(data_true): + return data_true[0] + + +@pytest.fixture +def x_true(data_true): + return data_true[1] + + +# t is raveled because some estimators fail with (n,1) inputs +@pytest.fixture +def t_true(data_true): + return data_true[2] + + +@pytest.fixture +def m_true(data_true): + return data_true[3] + + +@pytest.fixture +def y_true(data_true): + return data_true[4] + + +@pytest.fixture +def config_true(data_true): + return data_true[5] + + +@pytest.fixture +def result_true(data_true): + return data_true[6] + + +@pytest.fixture +def effects_chap_true(x_true, t_true, m_true, y_true, estimator_true, config_true): + # try whether estimator is implemented or not + + try: + res = get_estimation_results(x_true, t_true, m_true, + y_true, estimator_true, config_true)[0:5] + + # NaN situations + if np.all(np.isnan(res)): + pytest.xfail("all effects are NaN") + elif np.any(np.isnan(res)): + pprint("NaN found") + + except Exception as e: + if str(e) in ( + "Estimator only supports 1D binary mediator.", + "Estimator does not support 1D binary mediator.", + ): + pytest.skip(f"{e}") + + # We skip the test if an error with function from glmet rpy2 package occurs + elif "glmnet::glmnet" in str(e): + pytest.skip(f"{e}") + + elif estimator in R_DEPENDENT_ESTIMATORS and not check_r_dependencies(): + assert isinstance(e, DependencyNotInstalledError) == True + pytest.skip(f"{e}") + + else: + pytest.fail(f"{e}") + + return res + + +def test_estimation_exactness(result_true, effects_chap_true): + assert np.all(effects_chap_true == pytest.approx(result_true, abs=1.e-3)) From b29becf6c4cff45e2acdb0b28a4796505dd5cd78 Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 13 Nov 2024 23:17:03 +0100 Subject: [PATCH 52/84] remove reg from IPW --- src/med_bench/estimation/mediation_ipw.py | 9 +-------- src/med_bench/get_estimation_results.py | 14 +++++++------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/src/med_bench/estimation/mediation_ipw.py b/src/med_bench/estimation/mediation_ipw.py index ef2f899..6eb7041 100644 --- a/src/med_bench/estimation/mediation_ipw.py +++ b/src/med_bench/estimation/mediation_ipw.py @@ -8,13 +8,11 @@ class InversePropensityWeighting(Estimator): """Inverse propensity weighting estimation method class """ - def __init__(self, regressor, classifier, clip: float, trim: float, **kwargs): + def __init__(self, classifier, clip: float, trim: float, **kwargs): """Initializes Inverse propensity weighting estimation method Parameters ---------- - regressor - Regressor used for mu estimation, can be any object with a fit and predict method classifier Classifier used for propensity estimation, can be any object with a fit and predict_proba method clips : float @@ -24,15 +22,10 @@ def __init__(self, regressor, classifier, clip: float, trim: float, **kwargs): """ super().__init__(**kwargs) - assert hasattr( - regressor, 'fit'), "The model does not have a 'fit' method." - assert hasattr( - regressor, 'predict'), "The model does not have a 'predict' method." assert hasattr( classifier, 'fit'), "The model does not have a 'fit' method." assert hasattr( classifier, 'predict_proba'), "The model does not have a 'predict_proba' method." - self.regressor = regressor self.classifier = classifier self._clip = clip diff --git a/src/med_bench/get_estimation_results.py b/src/med_bench/get_estimation_results.py index 5498021..5130433 100644 --- a/src/med_bench/get_estimation_results.py +++ b/src/med_bench/get_estimation_results.py @@ -77,7 +77,7 @@ def get_regularized_regressor_and_classifier(regularize=True, calibration=None, # Class-based implementation for InversePropensityWeighting without regularization clf, reg = get_regularized_regressor_and_classifier(regularize=False) estimator_obj = InversePropensityWeighting( - clip=1e-6, trim=0, regressor=reg, classifier=clf) + clip=1e-6, trim=0, classifier=clf) estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) effects = transform_outputs(causal_effects) @@ -92,7 +92,7 @@ def get_regularized_regressor_and_classifier(regularize=True, calibration=None, # Class-based implementation with regularization clf, reg = get_regularized_regressor_and_classifier(regularize=True) estimator_obj = InversePropensityWeighting( - clip=1e-6, trim=0, regressor=reg, classifier=clf) + clip=1e-6, trim=0, classifier=clf) estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) effects = transform_outputs(causal_effects) @@ -108,7 +108,7 @@ def get_regularized_regressor_and_classifier(regularize=True, calibration=None, clf, reg = get_regularized_regressor_and_classifier( regularize=True, calibration=True, method="sigmoid") estimator_obj = InversePropensityWeighting( - clip=1e-6, trim=0, regressor=reg, classifier=clf) + clip=1e-6, trim=0, classifier=clf) estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) effects = transform_outputs(causal_effects) @@ -118,7 +118,7 @@ def get_regularized_regressor_and_classifier(regularize=True, calibration=None, clf, reg = get_regularized_regressor_and_classifier( regularize=True, calibration=True, method="isotonic") estimator_obj = InversePropensityWeighting( - clip=1e-6, trim=0, regressor=reg, classifier=clf) + clip=1e-6, trim=0, classifier=clf) estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) effects = transform_outputs(causal_effects) @@ -142,7 +142,7 @@ def get_regularized_regressor_and_classifier(regularize=True, calibration=None, reg = RandomForestRegressor( n_estimators=100, min_samples_leaf=10, random_state=42) estimator_obj = InversePropensityWeighting( - clip=1e-6, trim=0, regressor=reg, classifier=clf) + clip=1e-6, trim=0, classifier=clf) estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) effects = transform_outputs(causal_effects) @@ -161,7 +161,7 @@ def get_regularized_regressor_and_classifier(regularize=True, calibration=None, n_estimators=100, min_samples_leaf=10, random_state=42) calibrated_clf = CalibratedClassifierCV(clf, method="sigmoid") estimator_obj = InversePropensityWeighting( - clip=1e-6, trim=0, regressor=reg, classifier=calibrated_clf) + clip=1e-6, trim=0, classifier=calibrated_clf) estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) effects = transform_outputs(causal_effects) @@ -174,7 +174,7 @@ def get_regularized_regressor_and_classifier(regularize=True, calibration=None, n_estimators=100, min_samples_leaf=10, random_state=42) calibrated_clf = CalibratedClassifierCV(clf, method="isotonic") estimator_obj = InversePropensityWeighting( - clip=1e-6, trim=0, regressor=reg, classifier=calibrated_clf) + clip=1e-6, trim=0, classifier=calibrated_clf) estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) effects = transform_outputs(causal_effects) From 046e977134cc2cdb819f6feb9b962baa9e942e33 Mon Sep 17 00:00:00 2001 From: brash6 Date: Wed, 13 Nov 2024 23:18:36 +0100 Subject: [PATCH 53/84] clean dml docstrings --- src/med_bench/estimation/mediation_dml.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/med_bench/estimation/mediation_dml.py b/src/med_bench/estimation/mediation_dml.py index a45c6e0..3f075b3 100644 --- a/src/med_bench/estimation/mediation_dml.py +++ b/src/med_bench/estimation/mediation_dml.py @@ -16,10 +16,6 @@ def __init__(self, regressor, classifier, normalized: bool, **kwargs): Regressor used for mu estimation, can be any object with a fit and predict method classifier Classifier used for propensity estimation, can be any object with a fit and predict_proba method - clips : float - Clipping value for propensity scores - trim : float - Trimming value for propensity scores normalized : bool Whether to normalize the propensity scores """ @@ -67,14 +63,17 @@ def estimate(self, t, m, x, y): sum_score_t1m0 = np.mean(t * (1 - p_xm) / (p_xm * (1 - p_x))) sum_score_t0m1 = np.mean((1 - t) * p_xm / ((1 - p_xm) * p_x)) y1m1 = (t / p_x * (y - E_mu_t1_t1)) / sum_score_m1 + E_mu_t1_t1 - y0m0 = ((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / sum_score_m0 + E_mu_t0_t0 + y0m0 = ((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / \ + sum_score_m0 + E_mu_t0_t0 y1m0 = ( - (t * (1 - p_xm) / (p_xm * (1 - p_x)) * (y - mu_1mx)) / sum_score_t1m0 + (t * (1 - p_xm) / (p_xm * (1 - p_x)) + * (y - mu_1mx)) / sum_score_t1m0 + ((1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0)) / sum_score_m0 + E_mu_t1_t0 ) y0m1 = ( - ((1 - t) * p_xm / ((1 - p_xm) * p_x) * (y - mu_0mx)) / sum_score_t0m1 + ((1 - t) * p_xm / ((1 - p_xm) * p_x) + * (y - mu_0mx)) / sum_score_t0m1 + (t / p_x * (mu_0mx - E_mu_t0_t1)) / sum_score_m1 + E_mu_t0_t1 ) From 9da25c0ed833dd5782115a5923df6fe3566661c2 Mon Sep 17 00:00:00 2001 From: brash6 Date: Thu, 14 Nov 2024 12:30:41 +0100 Subject: [PATCH 54/84] get rid of estimators using cross fitting --- src/med_bench/get_estimation.py | 1017 ----------------------- src/med_bench/get_estimation_results.py | 160 +--- src/med_bench/mediation.py | 155 +--- src/med_bench/utils/constants.py | 15 - 4 files changed, 5 insertions(+), 1342 deletions(-) delete mode 100644 src/med_bench/get_estimation.py diff --git a/src/med_bench/get_estimation.py b/src/med_bench/get_estimation.py deleted file mode 100644 index c58e2a2..0000000 --- a/src/med_bench/get_estimation.py +++ /dev/null @@ -1,1017 +0,0 @@ -#!/usr/bin/env python -# -*- coding:utf-8 -*- - -import numpy as np - -from .mediation import ( - mediation_IPW, - mediation_coefficient_product, - mediation_g_formula, - mediation_multiply_robust, - mediation_dml, - r_mediation_g_estimator, - r_mediation_dml, - r_mediate, -) - -from med_bench.estimation.mediation_coefficient_product import CoefficientProduct -from med_bench.estimation.mediation_dml import DoubleMachineLearning -from med_bench.estimation.mediation_g_computation import GComputation -from med_bench.estimation.mediation_ipw import InversePropensityWeighting -from med_bench.estimation.mediation_mr import MultiplyRobust -from med_bench.nuisances.utils import _get_regularization_parameters -from med_bench.utils.constants import CV_FOLDS - -from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor -from sklearn.linear_model import LogisticRegressionCV, RidgeCV -from sklearn.calibration import CalibratedClassifierCV - - -def transform_outputs(causal_effects): - """Transforms outputs in the old format - - Args: - causal_effects (dict): dictionary of causal effects - - Returns: - list: list of causal effects - """ - total = causal_effects['total_effect'] - direct_treated = causal_effects['direct_effect_treated'] - direct_control = causal_effects['direct_effect_control'] - indirect_treated = causal_effects['indirect_effect_treated'] - indirect_control = causal_effects['indirect_effect_control'] - return [total, direct_treated, direct_control, indirect_treated, indirect_control, 0] - - -def get_estimation(x, t, m, y, estimator, config): - """Wrapper estimator fonction ; calls an estimator given mediation data - in order to estimate total, direct, and indirect effects. - - Parameters - ---------- - x : array-like, shape (n_samples, n_features_covariates) - Covariates value for each unit - t : array-like, shape (n_samples) - Treatment value for each unit - m : array-like, shape (n_samples, n_features_mediator) - Mediator value for each unit - y : array-like, shape (n_samples) - Outcome value for each unit - estimator : str - Label of the estimator - config : int - Indicates whether the estimator is suited to the data. - Should be 1 if dim_m=1 and type_m="binary", 5 otherwise. - This is a legacy parameter, will be removed in future updates. - - Returns - ------- - list - A list of estimated effects : - [total effect, - direct effect on the exposed, - direct effect on the unexposed, - indirect effect on the exposed, - indirect effect on the unexposed, - number of discarded samples OR non-discarded samples] - - Raises - ------ - UserWarning - If estimator name is misspelled. - """ - effects = None - if estimator == "mediation_IPW_R": - x_r, t_r, m_r, y_r = [_convert_array_to_R(uu) for uu in (x, t, m, y)] - output_w = causalweight.medweight( - y=y_r, d=t_r, m=m_r, x=x_r, trim=0.0, ATET="FALSE", logit="TRUE", boot=2 - ) - raw_res_R = np.array(output_w.rx2("results")) - effects = raw_res_R[0, :] - elif estimator == "coefficient_product": - effects = mediation_coefficient_product(y, t, m, x) - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - estimator = CoefficientProduct( - regressor=reg, classifier=clf, regularize=True) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - elif estimator == "mediation_ipw_noreg": - effects = mediation_IPW( - y, - t, - m, - x, - trim=0, - regularization=False, - forest=False, - crossfit=0, - clip=1e-6, - calibration=None, - ) - cs, alphas = _get_regularization_parameters(regularization=False) - clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) - reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) - estimator = InversePropensityWeighting( - clip=1e-6, trim=0, regressor=reg, classifier=clf - ) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - elif estimator == "mediation_ipw_noreg_cf": - effects = mediation_IPW( - y, - t, - m, - x, - trim=0, - regularization=False, - forest=False, - crossfit=2, - clip=1e-6, - calibration=None, - ) - elif estimator == "mediation_ipw_reg": - effects = mediation_IPW( - y, - t, - m, - x, - trim=0, - regularization=True, - forest=False, - crossfit=0, - clip=1e-6, - calibration=None, - ) - cs, alphas = _get_regularization_parameters(regularization=True) - clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) - reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) - estimator = InversePropensityWeighting( - clip=1e-6, trim=0, regressor=reg, classifier=clf - ) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - elif estimator == "mediation_ipw_reg_cf": - effects = mediation_IPW( - y, - t, - m, - x, - trim=0, - regularization=True, - forest=False, - crossfit=2, - clip=1e-6, - calibration=None, - ) - elif estimator == "mediation_ipw_reg_calibration": - effects = mediation_IPW( - y, - t, - m, - x, - trim=0, - regularization=True, - forest=False, - crossfit=0, - clip=1e-6, - calibration=None, - ) - cs, alphas = _get_regularization_parameters(regularization=True) - clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) - reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) - estimator = InversePropensityWeighting( - clip=1e-6, trim=0, regressor=reg, classifier=CalibratedClassifierCV(clf, method="sigmoid") - ) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - elif estimator == "mediation_ipw_reg_calibration_iso": - effects = mediation_IPW( - y, - t, - m, - x, - trim=0, - regularization=True, - forest=False, - crossfit=0, - clip=1e-6, - calibration="isotonic", - ) - cs, alphas = _get_regularization_parameters(regularization=True) - clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) - reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) - estimator = InversePropensityWeighting( - clip=1e-6, trim=0, regressor=reg, classifier=CalibratedClassifierCV(clf, method="isotonic") - ) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - elif estimator == "mediation_ipw_reg_calibration_cf": - effects = mediation_IPW( - y, - t, - m, - x, - trim=0, - regularization=True, - forest=False, - crossfit=2, - clip=1e-6, - calibration='sigmoid', - ) - elif estimator == "mediation_ipw_reg_calibration_iso_cf": - effects = mediation_IPW( - y, - t, - m, - x, - trim=0, - regularization=True, - forest=False, - crossfit=2, - clip=1e-6, - calibration="isotonic", - ) - elif estimator == "mediation_ipw_forest": - effects = mediation_IPW( - y, - t, - m, - x, - trim=0, - regularization=True, - forest=True, - crossfit=0, - clip=1e-6, - calibration=None, - ) - cs, alphas = _get_regularization_parameters(regularization=True) - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - estimator = InversePropensityWeighting( - clip=1e-6, trim=0, regressor=reg, classifier=clf - ) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - elif estimator == "mediation_ipw_forest_cf": - effects = mediation_IPW( - y, - t, - m, - x, - trim=0, - regularization=True, - forest=True, - crossfit=2, - clip=1e-6, - calibration=None, - ) - elif estimator == "mediation_ipw_forest_calibration": - effects = mediation_IPW( - y, - t, - m, - x, - trim=0, - regularization=True, - forest=True, - crossfit=0, - clip=1e-6, - calibration=None, - ) - cs, alphas = _get_regularization_parameters(regularization=True) - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - estimator = InversePropensityWeighting( - clip=1e-6, trim=0, regressor=reg, classifier=CalibratedClassifierCV(clf, method="sigmoid") - ) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - elif estimator == "mediation_ipw_forest_calibration_iso": - effects = mediation_IPW( - y, - t, - m, - x, - trim=0, - regularization=True, - forest=True, - crossfit=0, - clip=1e-6, - calibration="isotonic", - ) - cs, alphas = _get_regularization_parameters(regularization=True) - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - estimator = InversePropensityWeighting( - clip=1e-6, trim=0, regressor=reg, classifier=CalibratedClassifierCV(clf, method="isotonic") - ) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - elif estimator == "mediation_ipw_forest_calibration_cf": - effects = mediation_IPW( - y, - t, - m, - x, - trim=0, - regularization=True, - forest=True, - crossfit=2, - clip=1e-6, - calibration='sigmoid', - ) - elif estimator == "mediation_ipw_forest_calibration_iso_cf": - effects = mediation_IPW( - y, - t, - m, - x, - trim=0, - regularization=True, - forest=True, - crossfit=2, - clip=1e-6, - calibration="isotonic", - ) - elif estimator == "mediation_g_computation_noreg": - if config in (0, 1, 2): - effects = mediation_g_formula( - y, - t, - m, - x, - interaction=False, - forest=False, - crossfit=0, - regularization=False, - calibration=None, - ) - cs, alphas = _get_regularization_parameters(regularization=False) - clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) - reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) - estimator = GComputation(regressor=reg, classifier=clf) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - elif estimator == "mediation_g_computation_noreg_cf": - if config in (0, 1, 2): - effects = mediation_g_formula( - y, - t, - m, - x, - interaction=False, - forest=False, - crossfit=2, - regularization=False, - calibration=None, - ) - elif estimator == "mediation_g_computation_reg": - if config in (0, 1, 2): - effects = mediation_g_formula( - y, - t, - m, - x, - interaction=False, - forest=False, - crossfit=0, - regularization=True, - calibration=None, - ) - cs, alphas = _get_regularization_parameters(regularization=True) - clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) - reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) - estimator = GComputation(regressor=reg, classifier=clf) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - elif estimator == "mediation_g_computation_reg_cf": - if config in (0, 1, 2): - effects = mediation_g_formula( - y, - t, - m, - x, - interaction=False, - forest=False, - crossfit=2, - regularization=True, - calibration=None, - ) - elif estimator == "mediation_g_computation_reg_calibration": - if config in (0, 1, 2): - effects = mediation_g_formula( - y, - t, - m, - x, - interaction=False, - forest=False, - crossfit=0, - regularization=True, - calibration=None, - ) - cs, alphas = _get_regularization_parameters(regularization=True) - clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) - reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) - estimator = GComputation( - regressor=reg, classifier=CalibratedClassifierCV(clf, method="sigmoid")) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - elif estimator == "mediation_g_computation_reg_calibration_iso": - if config in (0, 1, 2): - effects = mediation_g_formula( - y, - t, - m, - x, - interaction=False, - forest=False, - crossfit=0, - regularization=True, - calibration="isotonic", - ) - cs, alphas = _get_regularization_parameters(regularization=True) - clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) - reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) - estimator = GComputation( - regressor=reg, classifier=CalibratedClassifierCV(clf, method="isotonic")) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - elif estimator == "mediation_g_computation_reg_calibration_cf": - if config in (0, 1, 2): - effects = mediation_g_formula( - y, - t, - m, - x, - interaction=False, - forest=False, - crossfit=2, - regularization=True, - calibration='sigmoid', - ) - elif estimator == "mediation_g_computation_reg_calibration_iso_cf": - if config in (0, 1, 2): - effects = mediation_g_formula( - y, - t, - m, - x, - interaction=False, - forest=False, - crossfit=2, - regularization=True, - calibration="isotonic", - ) - elif estimator == "mediation_g_computation_forest": - if config in (0, 1, 2): - effects = mediation_g_formula( - y, - t, - m, - x, - interaction=False, - forest=True, - crossfit=0, - regularization=True, - calibration=None, - ) - cs, alphas = _get_regularization_parameters(regularization=True) - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - estimator = GComputation(regressor=reg, classifier=clf) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - elif estimator == "mediation_g_computation_forest_cf": - if config in (0, 1, 2): - effects = mediation_g_formula( - y, - t, - m, - x, - interaction=False, - forest=True, - crossfit=2, - regularization=True, - calibration=None, - ) - elif estimator == "mediation_g_computation_forest_calibration": - if config in (0, 1, 2): - effects = mediation_g_formula( - y, - t, - m, - x, - interaction=False, - forest=True, - crossfit=0, - regularization=True, - calibration='sigmoid', - ) - cs, alphas = _get_regularization_parameters(regularization=True) - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - estimator = GComputation( - regressor=reg, classifier=CalibratedClassifierCV(clf, method="sigmoid")) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - elif estimator == "mediation_g_computation_forest_calibration_iso": - if config in (0, 1, 2): - effects = mediation_g_formula( - y, - t, - m, - x, - interaction=False, - forest=True, - crossfit=0, - regularization=True, - calibration="isotonic", - ) - cs, alphas = _get_regularization_parameters(regularization=True) - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - estimator = GComputation( - regressor=reg, classifier=CalibratedClassifierCV(clf, method="isotonic")) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - elif estimator == "mediation_g_computation_forest_calibration_cf": - if config in (0, 1, 2): - effects = mediation_g_formula( - y, - t, - m, - x, - interaction=False, - forest=True, - crossfit=2, - regularization=True, - calibration='sigmoid', - ) - elif estimator == "mediation_g_computation_forest_calibration_iso_cf": - if config in (0, 1, 2): - effects = mediation_g_formula( - y, - t, - m, - x, - interaction=False, - forest=True, - crossfit=2, - regularization=True, - calibration="isotonic", - ) - elif estimator == "mediation_multiply_robust_noreg": - if config in (0, 1, 2): - effects = mediation_multiply_robust( - y, - t, - m.astype(int), - x, - interaction=False, - forest=False, - crossfit=0, - clip=1e-6, - regularization=False, - calibration=None, - ) - cs, alphas = _get_regularization_parameters(regularization=False) - clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) - reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) - estimator = MultiplyRobust( - clip=1e-6, ratio="propensities", normalized=True, regressor=reg, - classifier=clf) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - elif estimator == "mediation_multiply_robust_noreg_cf": - if config in (0, 1, 2): - effects = mediation_multiply_robust( - y, - t, - m.astype(int), - x, - interaction=False, - forest=False, - crossfit=2, - clip=1e-6, - regularization=False, - calibration=None, - ) - elif estimator == "mediation_multiply_robust_reg": - if config in (0, 1, 2): - effects = mediation_multiply_robust( - y, - t, - m.astype(int), - x, - interaction=False, - forest=False, - crossfit=0, - clip=1e-6, - regularization=True, - calibration=None, - ) - cs, alphas = _get_regularization_parameters(regularization=True) - clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) - reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) - estimator = MultiplyRobust( - clip=1e-6, ratio="propensities", normalized=True, regressor=reg, - classifier=clf) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - elif estimator == "mediation_multiply_robust_reg_cf": - if config in (0, 1, 2): - effects = mediation_multiply_robust( - y, - t, - m.astype(int), - x, - interaction=False, - forest=False, - crossfit=2, - clip=1e-6, - regularization=True, - calibration=None, - ) - elif estimator == "mediation_multiply_robust_reg_calibration": - if config in (0, 1, 2): - effects = mediation_multiply_robust( - y, - t, - m.astype(int), - x, - interaction=False, - forest=False, - crossfit=0, - clip=1e-6, - regularization=True, - calibration='sigmoid', - ) - cs, alphas = _get_regularization_parameters(regularization=False) - clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) - reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) - estimator = MultiplyRobust( - clip=1e-6, ratio="propensities", normalized=True, regressor=reg, - classifier=CalibratedClassifierCV(clf, method="sigmoid")) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - elif estimator == "mediation_multiply_robust_reg_calibration_iso": - if config in (0, 1, 2): - effects = mediation_multiply_robust( - y, - t, - m.astype(int), - x, - interaction=False, - forest=False, - crossfit=0, - clip=1e-6, - regularization=True, - calibration="isotonic", - ) - cs, alphas = _get_regularization_parameters(regularization=False) - clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) - reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) - estimator = MultiplyRobust( - clip=1e-6, ratio="propensities", normalized=True, regressor=reg, - classifier=CalibratedClassifierCV(clf, method="isotonic")) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - elif estimator == "mediation_multiply_robust_reg_calibration_cf": - if config in (0, 1, 2): - effects = mediation_multiply_robust( - y, - t, - m.astype(int), - x, - interaction=False, - forest=False, - crossfit=2, - clip=1e-6, - regularization=True, - calibration='sigmoid', - ) - elif estimator == "mediation_multiply_robust_reg_calibration_iso_cf": - if config in (0, 1, 2): - effects = mediation_multiply_robust( - y, - t, - m.astype(int), - x, - interaction=False, - forest=False, - crossfit=2, - clip=1e-6, - regularization=True, - calibration="isotonic", - ) - elif estimator == "mediation_multiply_robust_forest": - if config in (0, 1, 2): - effects = mediation_multiply_robust( - y, - t, - m.astype(int), - x, - interaction=False, - forest=True, - crossfit=0, - clip=1e-6, - regularization=True, - calibration=None, - ) - cs, alphas = _get_regularization_parameters(regularization=False) - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - estimator = MultiplyRobust( - clip=1e-6, ratio="propensities", normalized=True, regressor=reg, - classifier=clf) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - elif estimator == "mediation_multiply_robust_forest_cf": - if config in (0, 1, 2): - effects = mediation_multiply_robust( - y, - t, - m.astype(int), - x, - interaction=False, - forest=True, - crossfit=2, - clip=1e-6, - regularization=True, - calibration=None, - ) - elif estimator == "mediation_multiply_robust_forest_calibration": - if config in (0, 1, 2): - effects = mediation_multiply_robust( - y, - t, - m.astype(int), - x, - interaction=False, - forest=True, - crossfit=0, - clip=1e-6, - regularization=True, - calibration='sigmoid', - ) - cs, alphas = _get_regularization_parameters(regularization=False) - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - estimator = MultiplyRobust( - clip=1e-6, ratio="propensities", normalized=True, regressor=reg, - classifier=CalibratedClassifierCV(clf, method="sigmoid")) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - elif estimator == "mediation_multiply_robust_forest_calibration_iso": - if config in (0, 1, 2): - effects = mediation_multiply_robust( - y, - t, - m.astype(int), - x, - interaction=False, - forest=True, - crossfit=0, - clip=1e-6, - regularization=True, - calibration="isotonic", - ) - cs, alphas = _get_regularization_parameters(regularization=False) - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - estimator = MultiplyRobust( - clip=1e-6, ratio="propensities", normalized=True, regressor=reg, - classifier=CalibratedClassifierCV(clf, method="isotonic")) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - elif estimator == "mediation_multiply_robust_forest_calibration_cf": - if config in (0, 1, 2): - effects = mediation_multiply_robust( - y, - t, - m.astype(int), - x, - interaction=False, - forest=True, - crossfit=2, - clip=1e-6, - regularization=True, - calibration='sigmoid', - ) - elif estimator == "mediation_multiply_robust_forest_calibration_iso_cf": - if config in (0, 1, 2): - effects = mediation_multiply_robust( - y, - t, - m.astype(int), - x, - interaction=False, - forest=True, - crossfit=2, - clip=1e-6, - regularization=True, - calibration="isotonic", - ) - elif estimator == "simulation_based": - if config in (0, 1, 2): - effects = r_mediate(y, t, m, x, interaction=False) - elif estimator == "mediation_dml": - if config > 0: - effects = r_mediation_dml(y, t, m, x, trim=0.0, order=1) - elif estimator == "mediation_dml_noreg": - effects = mediation_dml( - y, - t, - m, - x, - trim=0, - clip=1e-6, - regularization=False, - calibration=None) - cs, alphas = _get_regularization_parameters(regularization=False) - clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) - reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) - estimator = DoubleMachineLearning( - clip=1e-6, trim=0, normalized=True, regressor=reg, classifier=clf - ) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - elif estimator == "mediation_dml_reg": - effects = mediation_dml( - y, t, m, x, trim=0, clip=1e-6, calibration=None) - cs, alphas = _get_regularization_parameters(regularization=True) - clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) - reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) - estimator = DoubleMachineLearning( - clip=1e-6, trim=0, normalized=True, regressor=reg, classifier=clf - ) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - elif estimator == "mediation_dml_reg_fixed_seed": - effects = mediation_dml( - y, t, m, x, trim=0, clip=1e-6, random_state=321, calibration=None) - elif estimator == "mediation_dml_noreg_cf": - effects = mediation_dml( - y, - t, - m, - x, - trim=0, - clip=1e-6, - crossfit=2, - regularization=False, - calibration=None) - elif estimator == "mediation_dml_reg_cf": - effects = mediation_dml( - y, t, m, x, trim=0, clip=1e-6, crossfit=2, calibration=None) - elif estimator == "mediation_dml_reg_calibration": - effects = mediation_dml( - y, t, m, x, trim=0, clip=1e-6, crossfit=0, calibration='sigmoid') - cs, alphas = _get_regularization_parameters(regularization=True) - clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) - reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) - estimator = DoubleMachineLearning( - clip=1e-6, trim=0, normalized=True, regressor=reg, classifier=CalibratedClassifierCV(clf, method="sigmoid") - ) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - elif estimator == "mediation_dml_forest": - effects = mediation_dml( - y, - t, - m, - x, - trim=0, - clip=1e-6, - crossfit=0, - calibration=None, - forest=True) - cs, alphas = _get_regularization_parameters(regularization=True) - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - estimator = DoubleMachineLearning( - clip=1e-6, trim=0, normalized=True, regressor=reg, classifier=clf - ) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - elif estimator == "mediation_dml_forest_calibration": - effects = mediation_dml( - y, - t, - m, - x, - trim=0, - clip=1e-6, - crossfit=0, - calibration='sigmoid', - forest=True) - cs, alphas = _get_regularization_parameters(regularization=True) - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - estimator = DoubleMachineLearning( - clip=1e-6, trim=0, normalized=True, regressor=reg, classifier=CalibratedClassifierCV(clf, method="sigmoid") - ) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - elif estimator == "mediation_dml_reg_calibration_cf": - effects = mediation_dml( - y, - t, - m, - x, - trim=0, - clip=1e-6, - crossfit=2, - calibration='sigmoid', - forest=False) - elif estimator == "mediation_dml_forest_cf": - effects = mediation_dml( - y, - t, - m, - x, - trim=0, - clip=1e-6, - crossfit=2, - calibration=None, - forest=True) - elif estimator == "mediation_dml_forest_calibration_cf": - effects = mediation_dml( - y, - t, - m, - x, - trim=0, - clip=1e-6, - crossfit=2, - calibration='sigmoid', - forest=True) - elif estimator == "mediation_g_estimator": - if config in (0, 1, 2): - effects = r_mediation_g_estimator(y, t, m, x) - else: - raise ValueError("Unrecognized estimator label.") - if effects is None: - if config not in (0, 1, 2): - raise ValueError("Estimator only supports 1D binary mediator.") - raise ValueError("Estimator does not support 1D binary mediator.") - return effects diff --git a/src/med_bench/get_estimation_results.py b/src/med_bench/get_estimation_results.py index 5130433..717b9ea 100644 --- a/src/med_bench/get_estimation_results.py +++ b/src/med_bench/get_estimation_results.py @@ -4,9 +4,6 @@ import numpy as np from .mediation import ( - mediation_IPW, - mediation_g_formula, - mediation_multiply_robust, mediation_dml, r_mediation_g_estimator, r_mediation_dml, @@ -40,6 +37,7 @@ def transform_outputs(causal_effects): direct_control = causal_effects['direct_effect_control'] indirect_treated = causal_effects['indirect_effect_treated'] indirect_control = causal_effects['indirect_effect_control'] + return [total, direct_treated, direct_control, indirect_treated, indirect_control, 0] @@ -82,12 +80,6 @@ def get_regularized_regressor_and_classifier(regularize=True, calibration=None, causal_effects = estimator_obj.estimate(t, m, x, y) effects = transform_outputs(causal_effects) - elif estimator == "mediation_ipw_noreg_cf": - # Legacy function for crossfit with no regularization - effects = mediation_IPW( - y, t, m, x, trim=0, regularization=False, forest=False, crossfit=2, clip=1e-6, calibration=None - ) - elif estimator == "mediation_ipw_reg": # Class-based implementation with regularization clf, reg = get_regularized_regressor_and_classifier(regularize=True) @@ -97,12 +89,6 @@ def get_regularized_regressor_and_classifier(regularize=True, calibration=None, causal_effects = estimator_obj.estimate(t, m, x, y) effects = transform_outputs(causal_effects) - elif estimator == "mediation_ipw_reg_cf": - # Legacy function with crossfit and regularization - effects = mediation_IPW( - y, t, m, x, trim=0, regularization=True, forest=False, crossfit=2, clip=1e-6, calibration=None - ) - elif estimator == "mediation_ipw_reg_calibration": # Class-based implementation with regularization and calibration (sigmoid) clf, reg = get_regularized_regressor_and_classifier( @@ -123,18 +109,6 @@ def get_regularized_regressor_and_classifier(regularize=True, calibration=None, causal_effects = estimator_obj.estimate(t, m, x, y) effects = transform_outputs(causal_effects) - elif estimator == "mediation_ipw_reg_calibration_cf": - # Legacy function with crossfit and sigmoid calibration - effects = mediation_IPW( - y, t, m, x, trim=0, regularization=True, forest=False, crossfit=2, clip=1e-6, calibration="sigmoid" - ) - - elif estimator == "mediation_ipw_reg_calibration_iso_cf": - # Legacy function with crossfit and isotonic calibration - effects = mediation_IPW( - y, t, m, x, trim=0, regularization=True, forest=False, crossfit=2, clip=1e-6, calibration="isotonic" - ) - elif estimator == "mediation_ipw_forest": # Class-based implementation with forest models clf = RandomForestClassifier( @@ -147,12 +121,6 @@ def get_regularized_regressor_and_classifier(regularize=True, calibration=None, causal_effects = estimator_obj.estimate(t, m, x, y) effects = transform_outputs(causal_effects) - elif estimator == "mediation_ipw_forest_cf": - # Legacy function with forest and crossfit - effects = mediation_IPW( - y, t, m, x, trim=0, regularization=True, forest=True, crossfit=2, clip=1e-6, calibration=None - ) - elif estimator == "mediation_ipw_forest_calibration": # Class-based implementation with forest and calibrated sigmoid clf = RandomForestClassifier( @@ -187,12 +155,6 @@ def get_regularized_regressor_and_classifier(regularize=True, calibration=None, causal_effects = estimator_obj.estimate(t, m, x, y) effects = transform_outputs(causal_effects) - elif estimator == "mediation_g_computation_noreg_cf": - # Legacy function with crossfit and no regularization - effects = mediation_g_formula( - y, t, m, x, interaction=False, forest=False, crossfit=2, regularization=False, calibration=None - ) - elif estimator == "mediation_g_computation_reg": # Class-based implementation of GComputation with regularization clf, reg = get_regularized_regressor_and_classifier(regularize=True) @@ -201,26 +163,6 @@ def get_regularized_regressor_and_classifier(regularize=True, calibration=None, causal_effects = estimator_obj.estimate(t, m, x, y) effects = transform_outputs(causal_effects) - elif estimator == "mediation_g_computation_reg_cf": - # Legacy function with regularization and crossfit - effects = mediation_g_formula( - y, t, m, x, interaction=False, forest=False, crossfit=2, regularization=True, calibration=None - ) - - elif estimator == "mediation_g_computation_forest_cf": - if config in (0, 1, 2): - effects = mediation_g_formula( - y, - t, - m, - x, - interaction=False, - forest=True, - crossfit=2, - regularization=True, - calibration=None, - ) - elif estimator == "mediation_g_computation_reg_calibration": # Class-based implementation with regularization and calibrated sigmoid clf, reg = get_regularized_regressor_and_classifier( @@ -276,30 +218,6 @@ def get_regularized_regressor_and_classifier(regularize=True, calibration=None, causal_effects = estimator_obj.estimate(t, m, x, y) effects = transform_outputs(causal_effects) - # Regularized, crossfitting, calibration (isotonic) for InversePropensityWeighting - elif estimator == "mediation_ipw_reg_calibration_iso_cf": - effects = mediation_IPW( - y, t, m, x, trim=0, regularization=True, forest=False, crossfit=2, clip=1e-6, calibration="isotonic" - ) - - # Forest and crossfit with sigmoid calibration for InversePropensityWeighting - elif estimator == "mediation_ipw_forest_calibration_cf": - effects = mediation_IPW( - y, t, m, x, trim=0, regularization=True, forest=True, crossfit=2, clip=1e-6, calibration="sigmoid" - ) - - # Forest and crossfit with isotonic calibration for InversePropensityWeighting - elif estimator == "mediation_ipw_forest_calibration_iso_cf": - effects = mediation_IPW( - y, t, m, x, trim=0, regularization=True, forest=True, crossfit=2, clip=1e-6, calibration="isotonic" - ) - - # MultiplyRobust without regularization, with crossfitting - elif estimator == "mediation_multiply_robust_noreg_cf": - effects = mediation_multiply_robust( - y, t, m.astype(int), x, interaction=False, forest=False, crossfit=2, clip=1e-6, regularization=False, calibration=None - ) - # Regularized MultiplyRobust estimator elif estimator == "mediation_multiply_robust_reg": clf, reg = get_regularized_regressor_and_classifier(regularize=True) @@ -309,12 +227,6 @@ def get_regularized_regressor_and_classifier(regularize=True, calibration=None, causal_effects = estimator_obj.estimate(t, m, x, y) effects = transform_outputs(causal_effects) - # Regularized MultiplyRobust with crossfitting - elif estimator == "mediation_multiply_robust_reg_cf": - effects = mediation_multiply_robust( - y, t, m.astype(int), x, interaction=False, forest=False, crossfit=2, clip=1e-6, regularization=True, calibration=None - ) - # Regularized MultiplyRobust with sigmoid calibration elif estimator == "mediation_multiply_robust_reg_calibration": clf, reg = get_regularized_regressor_and_classifier( @@ -335,18 +247,6 @@ def get_regularized_regressor_and_classifier(regularize=True, calibration=None, causal_effects = estimator_obj.estimate(t, m, x, y) effects = transform_outputs(causal_effects) - # Regularized MultiplyRobust with sigmoid calibration and crossfitting - elif estimator == "mediation_multiply_robust_reg_calibration_cf": - effects = mediation_multiply_robust( - y, t, m.astype(int), x, interaction=False, forest=False, crossfit=2, clip=1e-6, regularization=True, calibration="sigmoid" - ) - - # Regularized MultiplyRobust with isotonic calibration and crossfitting - elif estimator == "mediation_multiply_robust_reg_calibration_iso_cf": - effects = mediation_multiply_robust( - y, t, m.astype(int), x, interaction=False, forest=False, crossfit=2, clip=1e-6, regularization=True, calibration="isotonic" - ) - elif estimator == "mediation_multiply_robust_forest": clf = RandomForestClassifier( random_state=42, n_estimators=100, min_samples_leaf=10) @@ -359,12 +259,6 @@ def get_regularized_regressor_and_classifier(regularize=True, calibration=None, causal_effects = estimator.estimate(t, m, x, y) effects = transform_outputs(causal_effects) - # MultiplyRobust with forest and crossfitting - elif estimator == "mediation_multiply_robust_forest_cf": - effects = mediation_multiply_robust( - y, t, m.astype(int), x, interaction=False, forest=True, crossfit=2, clip=1e-6, regularization=True, calibration=None - ) - # MultiplyRobust with forest and sigmoid calibration elif estimator == "mediation_multiply_robust_forest_calibration": clf = RandomForestClassifier( @@ -391,18 +285,6 @@ def get_regularized_regressor_and_classifier(regularize=True, calibration=None, causal_effects = estimator_obj.estimate(t, m, x, y) effects = transform_outputs(causal_effects) - # MultiplyRobust with forest, sigmoid calibration, and crossfitting - elif estimator == "mediation_multiply_robust_forest_calibration_cf": - effects = mediation_multiply_robust( - y, t, m.astype(int), x, interaction=False, forest=True, crossfit=2, clip=1e-6, regularization=True, calibration="sigmoid" - ) - - # MultiplyRobust with forest, isotonic calibration, and crossfitting - elif estimator == "mediation_multiply_robust_forest_calibration_iso_cf": - effects = mediation_multiply_robust( - y, t, m.astype(int), x, interaction=False, forest=True, crossfit=2, clip=1e-6, regularization=True, calibration="isotonic" - ) - # Regularized Double Machine Learning elif estimator == "mediation_dml_reg": clf, reg = get_regularized_regressor_and_classifier(regularize=True) @@ -417,16 +299,6 @@ def get_regularized_regressor_and_classifier(regularize=True, calibration=None, effects = mediation_dml( y, t, m, x, trim=0, clip=1e-6, random_state=321, calibration=None) - # Double Machine Learning without regularization, with crossfitting - elif estimator == "mediation_dml_noreg_cf": - effects = mediation_dml(y, t, m, x, trim=0, clip=1e-6, - crossfit=2, regularization=False, calibration=None) - - # Regularized Double Machine Learning with crossfitting - elif estimator == "mediation_dml_reg_cf": - effects = mediation_dml( - y, t, m, x, trim=0, clip=1e-6, crossfit=2, calibration=None) - # Regularized Double Machine Learning with sigmoid calibration elif estimator == "mediation_dml_reg_calibration": clf, reg = get_regularized_regressor_and_classifier( @@ -462,26 +334,6 @@ def get_regularized_regressor_and_classifier(regularize=True, calibration=None, causal_effects = estimator_obj.estimate(t, m, x, y) effects = transform_outputs(causal_effects) - # Double Machine Learning with forest, crossfitting, and sigmoid calibration - elif estimator == "mediation_dml_reg_calibration_cf": - effects = mediation_dml( - y, t, m, x, trim=0, clip=1e-6, crossfit=2, calibration="sigmoid", forest=False) - - # Double Machine Learning with forest and crossfitting - elif estimator == "mediation_dml_forest_cf": - effects = mediation_dml( - y, t, m, x, trim=0, clip=1e-6, crossfit=2, calibration=None, forest=True) - - # Double Machine Learning with forest, crossfitting, and calibrated sigmoid - elif estimator == "mediation_dml_forest_calibration_cf": - effects = mediation_dml( - y, t, m, x, trim=0, clip=1e-6, crossfit=2, calibration="sigmoid", forest=True) - - # GComputation with regularization, crossfitting, and sigmoid calibration - elif estimator == "mediation_g_computation_reg_calibration_cf": - effects = mediation_g_formula( - y, t, m, x, interaction=False, forest=False, crossfit=2, regularization=True, calibration="sigmoid") - # GComputation with forest and sigmoid calibration elif estimator == "mediation_g_computation_forest_calibration": clf = RandomForestClassifier( @@ -506,16 +358,6 @@ def get_regularized_regressor_and_classifier(regularize=True, calibration=None, causal_effects = estimator_obj.estimate(t, m, x, y) effects = transform_outputs(causal_effects) - # GComputation with forest, crossfitting, and sigmoid calibration - elif estimator == "mediation_g_computation_forest_calibration_cf": - effects = mediation_g_formula( - y, t, m, x, interaction=False, forest=True, crossfit=2, regularization=True, calibration="sigmoid") - - # GComputation with forest, crossfitting, and isotonic calibration - elif estimator == "mediation_g_computation_forest_calibration_iso_cf": - effects = mediation_g_formula( - y, t, m, x, interaction=False, forest=True, crossfit=2, regularization=True, calibration="isotonic") - elif estimator == "mediation_g_estimator": if config in (0, 1, 2): effects = r_mediation_g_estimator(y, t, m, x) diff --git a/src/med_bench/mediation.py b/src/med_bench/mediation.py index 80cf592..cc4f43d 100644 --- a/src/med_bench/mediation.py +++ b/src/med_bench/mediation.py @@ -143,86 +143,6 @@ def mediation_IPW( ) -def mediation_coefficient_product(y, t, m, x, interaction=False, regularization=True): - """ - found an R implementation https://cran.r-project.org/package=regmedint - - implements very simple model of mediation - Y ~ X + T + M - M ~ X + T - estimation method is product of coefficients - - Parameters - ---------- - y : array-like, shape (n_samples) - outcome value for each unit, continuous - - t : array-like, shape (n_samples) - treatment value for each unit, binary - - m : array-like, shape (n_samples) - mediator value for each unit, can be continuous or binary, and - is necessary in 1D - - x : array-like, shape (n_samples, n_features_covariates) - covariates (potential confounders) values - - interaction : boolean, default=False - whether to include interaction terms in the model - not implemented here, just for compatibility of signature - function - - regularization : boolean, default=True - whether to use regularized models (logistic or - linear regression). If True, cross-validation is used - to chose among 8 potential log-spaced values between - 1e-5 and 1e5 - - Returns - ------- - float - total effect - float - direct effect treated (\theta(1)) - float - direct effect nontreated (\theta(0)) - float - indirect effect treated (\delta(1)) - float - indirect effect untreated (\delta(0)) - int - number of used observations (non trimmed) - """ - if regularization: - alphas = ALPHAS - else: - alphas = [TINY] - - # check input - y, t, m, x = _check_input(y, t, m, x, setting="multidimensional") - - if len(t.shape) == 1: - t = t.reshape(-1, 1) - - coef_t_m = np.zeros(m.shape[1]) - for i in range(m.shape[1]): - m_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit(np.hstack((x, t)), m[:, i]) - coef_t_m[i] = m_reg.coef_[-1] - y_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit(np.hstack((x, t, m)), y.ravel()) - - # return total, direct and indirect effect - direct_effect = y_reg.coef_[x.shape[1]] - indirect_effect = sum(y_reg.coef_[x.shape[1] + 1 :] * coef_t_m) - return ( - direct_effect + indirect_effect, - direct_effect, - direct_effect, - indirect_effect, - indirect_effect, - None, - ) - - def mediation_g_formula( y, t, @@ -320,75 +240,6 @@ def mediation_g_formula( ) -def alternative_estimator(y, t, m, x, regularization=True): - """ - presented in - HUBER, Martin, LECHNER, Michael, et MELLACE, Giovanni. - The finite sample performance of estimators for mediation analysis under - sequential conditional independence. - Journal of Business & Economic Statistics, 2016, vol. 34, no 1, p. 139-160. - section 3.2.2 - - Parameters - ---------- - y : array-like, shape (n_samples) - outcome value for each unit, continuous - - t : array-like, shape (n_samples) - treatment value for each unit, binary - - m : array-like, shape (n_samples) - mediator value for each unit, here m is necessary binary - and unidimensional - - x : array-like, shape (n_samples, n_features_covariates) - covariates (potential confounders) values - - regularization : boolean, default=True - whether to use regularized models (logistic or - linear regression). If True, cross-validation is used - to chose among 8 potential log-spaced values between - 1e-5 and 1e5 - """ - if regularization: - alphas = ALPHAS - else: - alphas = [TINY] - - # check input - y, t, m, x = _check_input(y, t, m, x, setting="multidimensional") - treated = t == 1 - - # computation of direct effect - y_treated_reg_m = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit( - np.hstack((x[treated], m[treated])), y[treated] - ) - y_ctrl_reg_m = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit( - np.hstack((x[~treated], m[~treated])), y[~treated] - ) - xm = np.hstack((x, m)) - direct_effect = np.sum( - y_treated_reg_m.predict(xm) - y_ctrl_reg_m.predict(xm) - ) / len(y) - - # computation of total effect - y_treated_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit(x[treated], y[treated]) - y_ctrl_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit(x[~treated], y[~treated]) - total_effect = np.sum(y_treated_reg.predict(x) - y_ctrl_reg.predict(x)) / len(y) - - # computation of indirect effect - indirect_effect = total_effect - direct_effect - - return ( - total_effect, - direct_effect, - direct_effect, - indirect_effect, - indirect_effect, - None, - ) - - def mediation_multiply_robust( y, t, @@ -525,7 +376,8 @@ def mediation_multiply_robust( sum_score_t0m1 = np.mean((1 - t) / (1 - p_x) * (f_m1x / f_m0x)) y1m1 = (t / p_x * (y - E_mu_t1_t1)) / sum_score_m1 + E_mu_t1_t1 - y0m0 = ((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / sum_score_m0 + E_mu_t0_t0 + y0m0 = ((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / \ + sum_score_m0 + E_mu_t0_t0 y1m0 = ( ((t / p_x) * (f_m0x / f_m1x) * (y - mu_1mx)) / sum_score_t1m0 + ((1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0)) / sum_score_m0 @@ -904,7 +756,8 @@ def mediation_dml( sum_score_t1m0 = np.mean(t * (1 - p_xm) / (p_xm * (1 - p_x))) sum_score_t0m1 = np.mean((1 - t) * p_xm / ((1 - p_xm) * p_x)) y1m1 = (t / p_x * (y - E_mu_t1_t1)) / sum_score_m1 + E_mu_t1_t1 - y0m0 = ((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / sum_score_m0 + E_mu_t0_t0 + y0m0 = ((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / \ + sum_score_m0 + E_mu_t0_t0 y1m0 = ( (t * (1 - p_xm) / (p_xm * (1 - p_x)) * (y - mu_1mx)) / sum_score_t1m0 + ((1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0)) / sum_score_m0 diff --git a/src/med_bench/utils/constants.py b/src/med_bench/utils/constants.py index f0d5358..eb11572 100644 --- a/src/med_bench/utils/constants.py +++ b/src/med_bench/utils/constants.py @@ -81,21 +81,6 @@ def get_tolerance_array(tolerance_size: str) -> np.array: "mediation_dml": INFINITE_TOLERANCE, "mediation_dml_reg_fixed_seed": INFINITE_TOLERANCE, "mediation_g_estimator": LARGE_TOLERANCE, - "mediation_ipw_noreg_cf": INFINITE_TOLERANCE, - "mediation_ipw_reg_cf": INFINITE_TOLERANCE, - "mediation_ipw_reg_calibration_cf": INFINITE_TOLERANCE, - "mediation_ipw_forest_cf": INFINITE_TOLERANCE, - "mediation_ipw_forest_calibration_cf": INFINITE_TOLERANCE, - "mediation_g_computation_noreg_cf": SMALL_TOLERANCE, - "mediation_g_computation_reg_cf": LARGE_TOLERANCE, - "mediation_g_computation_reg_calibration_cf": LARGE_TOLERANCE, - "mediation_g_computation_forest_cf": INFINITE_TOLERANCE, - "mediation_g_computation_forest_calibration_cf": LARGE_TOLERANCE, - "mediation_multiply_robust_noreg_cf": MEDIUM_TOLERANCE, - "mediation_multiply_robust_reg_cf": LARGE_TOLERANCE, - "mediation_multiply_robust_reg_calibration_cf": MEDIUM_TOLERANCE, - "mediation_multiply_robust_forest_cf": INFINITE_TOLERANCE, - "mediation_multiply_robust_forest_calibration_cf": INFINITE_TOLERANCE, } ESTIMATORS = list(TOLERANCE_DICT.keys()) From ac77369d981f4ca2b57cb3d2c3fd5649948eb85f Mon Sep 17 00:00:00 2001 From: brash6 Date: Thu, 14 Nov 2024 13:32:31 +0100 Subject: [PATCH 55/84] fix tests --- src/med_bench/estimation/mediation_tmle.py | 6 +- src/med_bench/get_estimation_results.py | 2 +- src/med_bench/mediation.py | 1 - .../nuisances/conditional_outcome.py | 80 ----- .../nuisances/cross_conditional_outcome.py | 238 ------------- src/med_bench/nuisances/density.py | 314 ------------------ src/med_bench/nuisances/propensities.py | 78 ----- src/med_bench/nuisances/utils.py | 75 ----- src/med_bench/utils/scores.py | 43 --- src/med_bench/utils/utils.py | 162 ++++----- .../estimation/generate_tests_results.py | 4 +- 11 files changed, 75 insertions(+), 928 deletions(-) delete mode 100644 src/med_bench/nuisances/conditional_outcome.py delete mode 100644 src/med_bench/nuisances/cross_conditional_outcome.py delete mode 100644 src/med_bench/nuisances/density.py delete mode 100644 src/med_bench/nuisances/propensities.py delete mode 100644 src/med_bench/nuisances/utils.py delete mode 100644 src/med_bench/utils/scores.py diff --git a/src/med_bench/estimation/mediation_tmle.py b/src/med_bench/estimation/mediation_tmle.py index a0951ce..2f02cde 100644 --- a/src/med_bench/estimation/mediation_tmle.py +++ b/src/med_bench/estimation/mediation_tmle.py @@ -3,7 +3,6 @@ from sklearn.linear_model import LinearRegression from med_bench.estimation.base import Estimator -from med_bench.nuisances.utils import _get_regressor from med_bench.utils.decorators import fitted ALPHA = 10 @@ -85,7 +84,7 @@ def _one_step_correction_direct(self, t, m, x, y): mu_t0_mx_star = mu_t0_mx + epsilon_h * h_corrector_t0 mu_t1_mx_star = mu_t1_mx + epsilon_h * h_corrector_t1 - regressor_y = _get_regressor(self._regularize, self._use_forest) + regressor_y = self.regressor reg_cross = clone(regressor_y) reg_cross.fit( x[t == 0], (mu_t1_mx_star[t == 0] - @@ -143,8 +142,7 @@ def _one_step_correction_indirect(self, t, m, x, y): h_corrector_t1 = t1 / p_x - t1 * ratio mu_t1_mx_star = mu_t1_mx + epsilon_h * h_corrector_t1 - regressor_y = _get_regressor(self._regularize, - self._use_forest) + regressor_y = self.regressor reg_cross = clone(regressor_y) reg_cross.fit(x[t == 0], mu_t1_mx_star[t == 0]) diff --git a/src/med_bench/get_estimation_results.py b/src/med_bench/get_estimation_results.py index 717b9ea..8ca2c2e 100644 --- a/src/med_bench/get_estimation_results.py +++ b/src/med_bench/get_estimation_results.py @@ -15,7 +15,7 @@ from med_bench.estimation.mediation_g_computation import GComputation from med_bench.estimation.mediation_ipw import InversePropensityWeighting from med_bench.estimation.mediation_mr import MultiplyRobust -from med_bench.nuisances.utils import _get_regularization_parameters +from med_bench.utils.utils import _get_regularization_parameters from med_bench.utils.constants import CV_FOLDS from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor diff --git a/src/med_bench/mediation.py b/src/med_bench/mediation.py index cc4f43d..66b69fd 100644 --- a/src/med_bench/mediation.py +++ b/src/med_bench/mediation.py @@ -9,7 +9,6 @@ import numpy as np import pandas as pd from sklearn.base import clone -from sklearn.linear_model import RidgeCV from .utils.nuisances import ( diff --git a/src/med_bench/nuisances/conditional_outcome.py b/src/med_bench/nuisances/conditional_outcome.py deleted file mode 100644 index 72adc1a..0000000 --- a/src/med_bench/nuisances/conditional_outcome.py +++ /dev/null @@ -1,80 +0,0 @@ -""" -the objective of this script is to provide nuisance estimators -for mediation in causal inference -""" - -import numpy as np - -from med_bench.utils.utils import _get_train_test_lists, _get_interactions - - -def estimate_conditional_mean_outcome( - t, m, x, y, crossfit, reg_y, interaction, fit=False -): - """ - Estimate conditional mean outcome E[Y|T,M,X] - with train test lists from crossfitting - - Returns - ------- - mu_t0: list - contains array-like, shape (n_samples) conditional mean outcome estimates E[Y|T=0,M=m,X] - mu_t1, list - contains array-like, shape (n_samples) conditional mean outcome estimates E[Y|T=1,M=m,X] - mu_m0x, array-like, shape (n_samples) - conditional mean outcome estimates E[Y|T=0,M,X] - mu_m1x, array-like, shape (n_samples) - conditional mean outcome estimates E[Y|T=1,M,X] - """ - n = len(y) - if len(x.shape) == 1: - x = x.reshape(-1, 1) - if len(m.shape) == 1: - mr = m.reshape(-1, 1) - else: - mr = np.copy(m) - if len(t.shape) == 1: - t = t.reshape(-1, 1) - - t0 = np.zeros((n, 1)) - t1 = np.ones((n, 1)) - m1 = np.ones((n, 1)) - - train_test_list = _get_train_test_lists(crossfit, n, x) - - mu_1mx, mu_0mx = [np.zeros(n) for _ in range(2)] - mu_t1, mu_t0 = [], [] - - m1 = np.ones((n, 1)) - - x_t_mr = _get_interactions(interaction, x, t, mr) - - x_t1_m = _get_interactions(interaction, x, t1, m) - x_t0_m = _get_interactions(interaction, x, t0, m) - - for train_index, test_index in train_test_list: - - # mu_tm model fitting - if fit == True: - reg_y = reg_y.fit(x_t_mr[train_index, :], y[train_index]) - - # predict E[Y|T=t,M,X] - mu_0mx[test_index] = reg_y.predict(x_t0_m[test_index, :]).squeeze() - mu_1mx[test_index] = reg_y.predict(x_t1_m[test_index, :]).squeeze() - - for i, b in enumerate(np.unique(m)): - mu_1bx, mu_0bx = [np.zeros(n) for h in range(2)] - mb = m1 * b - - # predict E[Y|T=t,M=m,X] - mu_0bx[test_index] = reg_y.predict( - _get_interactions(interaction, x, t0, mb)[test_index, :] - ).squeeze() - mu_1bx[test_index] = reg_y.predict( - _get_interactions(interaction, x, t1, mb)[test_index, :] - ).squeeze() - - mu_t0.append(mu_0bx) - mu_t1.append(mu_1bx) - - return mu_t0, mu_t1, mu_0mx, mu_1mx diff --git a/src/med_bench/nuisances/cross_conditional_outcome.py b/src/med_bench/nuisances/cross_conditional_outcome.py deleted file mode 100644 index 1371f6e..0000000 --- a/src/med_bench/nuisances/cross_conditional_outcome.py +++ /dev/null @@ -1,238 +0,0 @@ -""" -the objective of this script is to provide nuisance estimators -for mediation in causal inference -""" - -import numpy as np - -from sklearn.base import clone - -from med_bench.utils.utils import _get_train_test_lists, _get_interactions - - -def estimate_cross_conditional_mean_outcome_discrete(m, x, y, f, regressors): - """ - Estimate the conditional mean outcome, - the cross conditional mean outcome - - Returns - ------- - mu_m0x, array-like, shape (n_samples) - conditional mean outcome estimates E[Y|T=0,M,X] - mu_m1x, array-like, shape (n_samples) - conditional mean outcome estimates E[Y|T=1,M,X] - E_mu_t0_t0, array-like, shape (n_samples) - cross conditional mean outcome estimates E[E[Y|T=0,M,X]|T=0,X] - E_mu_t0_t1, array-like, shape (n_samples) - cross conditional mean outcome estimates E[E[Y|T=0,M,X]|T=1,X] - E_mu_t1_t0, array-like, shape (n_samples) - cross conditional mean outcome estimates E[E[Y|T=1,M,X]|T=0,X] - E_mu_t1_t1, array-like, shape (n_samples) - cross conditional mean outcome estimates E[E[Y|T=1,M,X]|T=1,X] - """ - n = len(y) - - # Initialisation - ( - mu_1mx, # E[Y|T=1,M,X] - mu_0mx, # E[Y|T=0,M,X] - E_mu_t0_t0, # E[E[Y|T=0,M,X]|T=0,X] - E_mu_t0_t1, # E[E[Y|T=0,M,X]|T=1,X] - E_mu_t1_t0, # E[E[Y|T=1,M,X]|T=0,X] - E_mu_t1_t1, # E[E[Y|T=1,M,X]|T=1,X] - ) = [np.zeros(n) for _ in range(6)] - - t0, m0 = np.zeros((n, 1)), np.zeros((n, 1)) - t1, m1 = np.ones((n, 1)), np.ones((n, 1)) - - x_t1_m = _get_interactions(False, x, t1, m) - x_t0_m = _get_interactions(False, x, t0, m) - - f_t0, f_t1 = f - - # Index declaration - test_index = np.arange(n) - - # predict E[Y|T=t,M,X] - mu_1mx[test_index] = regressors["y_t_mx"].predict(x_t1_m[test_index, :]) - mu_0mx[test_index] = regressors["y_t_mx"].predict(x_t0_m[test_index, :]) - - for i, b in enumerate(np.unique(m)): - - # f(M=m|T=t,X) - f_0bx, f_1bx = f_t0[i], f_t1[i] - - # predict E[E[Y|T=1,M=m,X]|T=t,X] - E_mu_t1_t0[test_index] += ( - regressors["reg_y_t1m{}_t0".format(i)].predict(x[test_index, :]) - * f_0bx[test_index] - ) - E_mu_t1_t1[test_index] += ( - regressors["reg_y_t1m{}_t1".format(i)].predict(x[test_index, :]) - * f_1bx[test_index] - ) - - # predict E[E[Y|T=0,M=m,X]|T=t,X] - E_mu_t0_t0[test_index] += ( - regressors["reg_y_t0m{}_t0".format(i)].predict(x[test_index, :]) - * f_0bx[test_index] - ) - E_mu_t0_t1[test_index] += ( - regressors["reg_y_t0m{}_t1".format(i)].predict(x[test_index, :]) - * f_1bx[test_index] - ) - - return mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 - - -def estimate_cross_conditional_mean_outcome( - t, m, x, y, crossfit, reg_y, reg_cross_y, f, interaction -): - """ - Estimate the conditional mean outcome, - the cross conditional mean outcome - - Returns - ------- - mu_m0x, array-like, shape (n_samples) - conditional mean outcome estimates E[Y|T=0,M,X] - mu_m1x, array-like, shape (n_samples) - conditional mean outcome estimates E[Y|T=1,M,X] - E_mu_t0_t0, array-like, shape (n_samples) - cross conditional mean outcome estimates E[E[Y|T=0,M,X]|T=0,X] - E_mu_t0_t1, array-like, shape (n_samples) - cross conditional mean outcome estimates E[E[Y|T=0,M,X]|T=1,X] - E_mu_t1_t0, array-like, shape (n_samples) - cross conditional mean outcome estimates E[E[Y|T=1,M,X]|T=0,X] - E_mu_t1_t1, array-like, shape (n_samples) - cross conditional mean outcome estimates E[E[Y|T=1,M,X]|T=1,X] - """ - n = len(y) - - # Initialisation - ( - mu_1mx, # E[Y|T=1,M,X] - mu_0mx, # E[Y|T=0,M,X] - E_mu_t0_t0, # E[E[Y|T=0,M,X]|T=0,X] - E_mu_t0_t1, # E[E[Y|T=0,M,X]|T=1,X] - E_mu_t1_t0, # E[E[Y|T=1,M,X]|T=0,X] - E_mu_t1_t1, # E[E[Y|T=1,M,X]|T=1,X] - ) = [np.zeros(n) for _ in range(6)] - - t0, m0 = np.zeros((n, 1)), np.zeros((n, 1)) - t1, m1 = np.ones((n, 1)), np.ones((n, 1)) - - train_test_list = _get_train_test_lists(crossfit, n, x) - - x_t_m = _get_interactions(interaction, x, t, m) - x_t1_m = _get_interactions(interaction, x, t1, m) - x_t0_m = _get_interactions(interaction, x, t0, m) - - f_t0, f_t1 = f - - # Cross-fitting loop - for train_index, test_index in train_test_list: - # Index declaration - ind_t0 = t[test_index] == 0 - - # mu_tm model fitting - reg_y = reg_y.fit(x_t_m[train_index, :], y[train_index]) - - # predict E[Y|T=t,M,X] - mu_1mx[test_index] = reg_y.predict(x_t1_m[test_index, :]) - mu_0mx[test_index] = reg_y.predict(x_t0_m[test_index, :]) - - for i, b in enumerate(np.unique(m)): - mb = m1 * b - - mu_1bx, mu_0bx, f_0bx, f_1bx = [np.zeros(n) for h in range(4)] - - # f(M=m|T=t,X) - f_0bx, f_1bx = f_t0[i], f_t1[i] - - # predict E[Y|T=t,M=m,X] - mu_0bx[test_index] = reg_y.predict( - _get_interactions(interaction, x, t0, mb)[test_index, :] - ) - mu_1bx[test_index] = reg_y.predict( - _get_interactions(interaction, x, t1, mb)[test_index, :] - ) - - # E[E[Y|T=1,M=m,X]|T=t,X] model fitting - reg_y_t1mb_t0 = clone(reg_cross_y).fit( - x[test_index, :][ind_t0, :], mu_1bx[test_index][ind_t0] - ) - reg_y_t1mb_t1 = clone(reg_cross_y).fit( - x[test_index, :][~ind_t0, :], mu_1bx[test_index][~ind_t0] - ) - - # predict E[E[Y|T=1,M=m,X]|T=t,X] - E_mu_t1_t0[test_index] += ( - reg_y_t1mb_t0.predict(x[test_index, :]) * f_0bx[test_index] - ) - E_mu_t1_t1[test_index] += ( - reg_y_t1mb_t1.predict(x[test_index, :]) * f_1bx[test_index] - ) - - # E[E[Y|T=0,M=m,X]|T=t,X] model fitting - reg_y_t0mb_t0 = clone(reg_cross_y).fit( - x[test_index, :][ind_t0, :], mu_0bx[test_index][ind_t0] - ) - reg_y_t0mb_t1 = clone(reg_cross_y).fit( - x[test_index, :][~ind_t0, :], mu_0bx[test_index][~ind_t0] - ) - - # predict E[E[Y|T=0,M=m,X]|T=t,X] - E_mu_t0_t0[test_index] += ( - reg_y_t0mb_t0.predict(x[test_index, :]) * f_0bx[test_index] - ) - E_mu_t0_t1[test_index] += ( - reg_y_t0mb_t1.predict(x[test_index, :]) * f_1bx[test_index] - ) - - return mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 - - -def estimate_cross_conditional_mean_outcome_nesting(m, x, y, regressors): - """ - Estimate the conditional mean outcome, - the cross conditional mean outcome - - Returns - ------- - mu_m0x, array-like, shape (n_samples) - conditional mean outcome estimates E[Y|T=0,M,X] - mu_m1x, array-like, shape (n_samples) - conditional mean outcome estimates E[Y|T=1,M,X] - mu_0x, array-like, shape (n_samples) - cross conditional mean outcome estimates E[E[Y|T=0,M,X]|T=0,X] - E_mu_t0_t1, array-like, shape (n_samples) - cross conditional mean outcome estimates E[E[Y|T=0,M,X]|T=1,X] - E_mu_t1_t0, array-like, shape (n_samples) - cross conditional mean outcome estimates E[E[Y|T=1,M,X]|T=0,X] - mu_1x, array-like, shape (n_samples) - cross conditional mean outcome estimates E[E[Y|T=1,M,X]|T=1,X] - """ - n = len(y) - - xm = np.hstack((x, m)) - - # predict E[Y|T=1,M,X] - mu_1mx = regressors["y_t1_mx"].predict(xm) - - # predict E[Y|T=0,M,X] - mu_0mx = regressors["y_t0_mx"].predict(xm) - - # predict E[E[Y|T=1,M,X]|T=0,X] - E_mu_t1_t0 = regressors["y_t1_x_t0"].predict(x) - - # predict E[E[Y|T=0,M,X]|T=1,X] - E_mu_t0_t1 = regressors["y_t0_x_t1"].predict(x) - - # predict E[Y|T=1,X] - mu_1x = regressors["y_t1_x"].predict(x) - - # predict E[Y|T=0,X] - mu_0x = regressors["y_t0_x"].predict(x) - - return mu_0mx, mu_1mx, mu_0x, E_mu_t0_t1, E_mu_t1_t0, mu_1x diff --git a/src/med_bench/nuisances/density.py b/src/med_bench/nuisances/density.py deleted file mode 100644 index e8e92c2..0000000 --- a/src/med_bench/nuisances/density.py +++ /dev/null @@ -1,314 +0,0 @@ -""" -the objective of this script is to provide nuisance estimators -for mediation in causal inference -""" - -import numpy as np - -from sklearn.base import clone - -from med_bench.utils.utils import _get_train_test_lists, _get_interactions -from sklearn.neighbors import NearestNeighbors, KernelDensity -from sklearn.base import BaseEstimator -from joblib import Parallel, delayed - - -def estimate_mediator_density(t, m, x, y, crossfit, clf_m, interaction, fit=False): - """ - Estimate mediator density f(M|T,X) - with train test lists from crossfitting - - Returns - ------- - f_t0: list - contains array-like, shape (n_samples) probabilities f(M=m|T=0,X) - f_t1, list - contains array-like, shape (n_samples) probabilities f(M=m|T=1,X) - f_m0x, array-like, shape (n_samples) - probabilities f(M|T=0,X) - f_m1x, array-like, shape (n_samples) - probabilities f(M|T=1,X) - """ - # if not is_array_integer(m): - # return estimate_mediator_density_kde(t, m, x, y, crossfit, interaction) - # else: - return estimate_mediator_probability( - t, m, x, y, crossfit, clf_m, interaction, fit=False - ) - - -def estimate_mediators_probabilities( - t, m, x, y, crossfit, clf_m, interaction, fit=False -): - """ - Estimate mediator density f(M|T,X) - with train test lists from crossfitting - - Returns - ------- - f_t0: list - contains array-like, shape (n_samples) probabilities f(M=m|T=0,X) - f_t1, list - contains array-like, shape (n_samples) probabilities f(M=m|T=1,X) - """ - n = len(y) - if len(x.shape) == 1: - x = x.reshape(-1, 1) - - if len(t.shape) == 1: - t = t.reshape(-1, 1) - - t0 = np.zeros((n, 1)) - t1 = np.ones((n, 1)) - - m = m.ravel() - - train_test_list = _get_train_test_lists(crossfit, n, x) - - f_t1, f_t0 = [], [] - - t_x = _get_interactions(interaction, t, x) - t0_x = _get_interactions(interaction, t0, x) - t1_x = _get_interactions(interaction, t1, x) - - for train_index, test_index in train_test_list: - - # f_mtx model fitting - if fit == True: - clf_m = clf_m.fit(t_x[train_index, :], m[train_index]) - - fm_0 = clf_m.predict_proba(t0_x[test_index, :]) - fm_1 = clf_m.predict_proba(t1_x[test_index, :]) - - for i, b in enumerate(np.unique(m)): - f_0bx, f_1bx = [np.zeros(n) for h in range(2)] - - # predict f(M=m|T=t,X) - f_0bx[test_index] = fm_0[:, i] - f_1bx[test_index] = fm_1[:, i] - - f_t0.append(f_0bx) - f_t1.append(f_1bx) - - return f_t0, f_t1 - - -def estimate_mediator_probability(t, m, x, y, crossfit, clf_m, interaction, fit=False): - """ - Estimate mediator density f(M|T,X) - with train test lists from crossfitting - - Returns - ------- - f_m0x, array-like, shape (n_samples) - probabilities f(M|T=0,X) - f_m1x, array-like, shape (n_samples) - probabilities f(M|T=1,X) - """ - n = len(y) - if len(x.shape) == 1: - x = x.reshape(-1, 1) - - if len(t.shape) == 1: - t = t.reshape(-1, 1) - - t0 = np.zeros((n, 1)) - t1 = np.ones((n, 1)) - - m = m.ravel() - - train_test_list = _get_train_test_lists(crossfit, n, x) - - f_m0x, f_m1x = [np.zeros(n) for h in range(2)] - - t_x = _get_interactions(interaction, t, x) - t0_x = _get_interactions(interaction, t0, x) - t1_x = _get_interactions(interaction, t1, x) - - for train_index, test_index in train_test_list: - - test_ind = np.arange(len(test_index)) - - # f_mtx model fitting - if fit == True: - clf_m = clf_m.fit(t_x[train_index, :], m[train_index]) - - fm_0 = clf_m.predict_proba(t0_x[test_index, :]) - fm_1 = clf_m.predict_proba(t1_x[test_index, :]) - - # predict f(M|T=t,X) - f_m0x[test_index] = fm_0[test_ind, m[test_index]] - f_m1x[test_index] = fm_1[test_ind, m[test_index]] - - for i, b in enumerate(np.unique(m)): - f_0bx, f_1bx = [np.zeros(n) for h in range(2)] - - # predict f(M=m|T=t,X) - f_0bx[test_index] = fm_0[:, i] - f_1bx[test_index] = fm_1[:, i] - - return f_m0x, f_m1x - - -class ConditionalNearestNeighborsKDE(BaseEstimator): - """Conditional Kernel Density Estimation using nearest neighbors. - - This class implements a Conditional Kernel Density Estimation by applying - the Kernel Density Estimation algorithm after a nearest neighbors search. - - It allows the use of user-specified nearest neighbor and kernel density - estimators or, if not provided, defaults will be used. - - Parameters - ---------- - nn_estimator : NearestNeighbors instance, default=None - A pre-configured instance of a `~sklearn.neighbors.NearestNeighbors` class - to use for finding nearest neighbors. If not specified, a - `~sklearn.neighbors.NearestNeighbors` instance with `n_neighbors=100` - will be used. - - kde_estimator : KernelDensity instance, default=None - A pre-configured instance of a `~sklearn.neighbors.KernelDensity` class - to use for estimating the kernel density. If not specified, a - `~sklearn.neighbors.KernelDensity` instance with `bandwidth="scott"` - will be used. - """ - - def __init__(self, nn_estimator=None, kde_estimator=None): - self.nn_estimator = nn_estimator - self.kde_estimator = kde_estimator - - def fit(self, X, y=None): - if self.nn_estimator is None: - self.nn_estimator_ = NearestNeighbors(n_neighbors=100) - else: - self.nn_estimator_ = clone(self.nn_estimator) - self.nn_estimator_.fit(X, y) - self.y_train_ = y - return self - - def predict(self, X): - """Predict the conditional density estimation of new samples. - - The predicted density of the target for each sample in X is returned. - - Parameters - ---------- - X : array-like of shape (n_samples, n_features) - Vector to be estimated, where `n_samples` is the number of samples - and `n_features` is the number of features. - - Returns - ------- - kernel_density_list : list of len n_samples of KernelDensity instances - Estimated conditional density estimations in the form of - `~sklearn.neighbors.KernelDensity` instances. - """ - _, ind_X = self.nn_estimator_.kneighbors(X) - if self.kde_estimator is None: - kernel_density_list = [ - KernelDensity(bandwidth="scott").fit(self.y_train_[ind].reshape(-1, 1)) - for ind in ind_X - ] - else: - kernel_density_list = [ - clone(self.kde_estimator).fit(self.y_train_[ind].reshape(-1, 1)) - for ind in ind_X - ] - return kernel_density_list - - def pdf(self, y, x): - - ckde_preds = self.predict(x) - - def _evaluate_individual(y_, cde_pred): - # The score_samples and score methods returns stuff on log scale, - # so we have to exp it. - expected_value = np.exp(cde_pred.score(y_.reshape(-1, 1))) - return expected_value - - individual_predictions = Parallel(n_jobs=-1)( - delayed(_evaluate_individual)(y_, cde_pred) - for y_, cde_pred in zip(y, ckde_preds) - ) - - return individual_predictions - - -# def estimate_mediator_density_kde(t, m, x, y, crossfit, interaction): -# """ -# Estimate mediator density f(M|T,X) -# with train test lists from crossfitting - -# Returns -# ------- -# f_m0x, array-like, shape (n_samples) -# probabilities f(M|T=0,X) -# f_m1x, array-like, shape (n_samples) -# probabilities f(M|T=1,X) -# """ -# n = len(y) -# if len(x.shape) == 1: -# x = x.reshape(-1, 1) - -# if len(t.shape) == 1: -# t = t.reshape(-1, 1) - -# t0 = np.zeros((n, 1)) -# t1 = np.ones((n, 1)) - - -# train_test_list = _get_train_test_lists(crossfit, n, x) - -# f_m0x, f_m1x = [np.zeros(n) for _ in range(2)] - -# t_x = _get_interactions(interaction, t, x) -# t0_x = _get_interactions(interaction, t0, x) -# t1_x = _get_interactions(interaction, t1, x) - -# for train_index, test_index in train_test_list: - -# # f_mtx model fitting -# ckde_m = ConditionalNearestNeighborsKDE().fit(t_x[train_index, :], -# m[train_index, :]) - -# # predict f(M|T=t,X) -# f_m0x[test_index] = ckde_m.pdf(m[test_index, :], t0_x[test_index, :]) -# f_m1x[test_index] = ckde_m.pdf(m[test_index, :], t1_x[test_index, :]) - -# return f_m0x, f_m1x - - -def estimate_mediator_density_kde(t, m, x, y, crossfit, ckde_m, interaction): - """ - Estimate mediator density f(M|T,X) - with train test lists from crossfitting - - Returns - ------- - f_m0x, array-like, shape (n_samples) - probabilities f(M|T=0,X) - f_m1x, array-like, shape (n_samples) - probabilities f(M|T=1,X) - """ - n = len(y) - if len(x.shape) == 1: - x = x.reshape(-1, 1) - - if len(t.shape) == 1: - t = t.reshape(-1, 1) - - t0 = np.zeros((n, 1)) - t1 = np.ones((n, 1)) - - f_m0x, f_m1x = [np.zeros(n) for _ in range(2)] - - t_x = _get_interactions(interaction, t, x) - t0_x = _get_interactions(interaction, t0, x) - t1_x = _get_interactions(interaction, t1, x) - - # predict f(M|T=t,X) - f_m0x = ckde_m.pdf(m, t0_x) - f_m1x = ckde_m.pdf(m, t1_x) - - return f_m0x, f_m1x diff --git a/src/med_bench/nuisances/propensities.py b/src/med_bench/nuisances/propensities.py deleted file mode 100644 index 182d754..0000000 --- a/src/med_bench/nuisances/propensities.py +++ /dev/null @@ -1,78 +0,0 @@ -""" -the objective of this script is to provide nuisance estimators -for mediation in causal inference -""" - -import numpy as np - - -from med_bench.utils.utils import _get_train_test_lists - - -def estimate_treatment_propensity_x(t, m, x, crossfit, clf_t_x): - """ - Estimate treatment probabilities P(T=1|X) with train - test lists from crossfitting - - Returns - ------- - p_x : array-like, shape (n_samples) - probabilities P(T=1|X) - p_xm : array-like, shape (n_samples) - probabilities P(T=1|X, M) - """ - n = len(t) - - p_x, p_xm = [np.zeros(n) for h in range(2)] - # compute propensity scores - if len(x.shape) == 1: - x = x.reshape(-1, 1) - if len(m.shape) == 1: - m = m.reshape(-1, 1) - if len(t.shape) == 1: - t = t.reshape(-1, 1) - - train_test_list = _get_train_test_lists(crossfit, n, x) - - for train_index, test_index in train_test_list: - - # predict P(T=1|X), P(T=1|X, M) - p_x[test_index] = clf_t_x.predict_proba(x[test_index, :])[:, 1] - - return p_x - - -def estimate_treatment_probabilities(t, m, x, crossfit, clf_t_x, clf_t_xm, fit=False): - """ - Estimate treatment probabilities P(T=1|X) and P(T=1|X, M) with train - test lists from crossfitting - - Returns - ------- - p_x : array-like, shape (n_samples) - probabilities P(T=1|X) - p_xm : array-like, shape (n_samples) - probabilities P(T=1|X, M) - """ - n = len(t) - - p_x, p_xm = [np.zeros(n) for h in range(2)] - # compute propensity scores - if len(x.shape) == 1: - x = x.reshape(-1, 1) - if len(m.shape) == 1: - m = m.reshape(-1, 1) - if len(t.shape) == 1: - t = t.reshape(-1, 1) - - train_test_list = _get_train_test_lists(crossfit, n, x) - - xm = np.hstack((x, m)) - - for train_index, test_index in train_test_list: - - # predict P(T=1|X), P(T=1|X, M) - p_x[test_index] = clf_t_x.predict_proba(x[test_index, :])[:, 1] - p_xm[test_index] = clf_t_xm.predict_proba(xm[test_index, :])[:, 1] - - return p_x, p_xm diff --git a/src/med_bench/nuisances/utils.py b/src/med_bench/nuisances/utils.py deleted file mode 100644 index 38f1d58..0000000 --- a/src/med_bench/nuisances/utils.py +++ /dev/null @@ -1,75 +0,0 @@ -""" -the objective of this script is to provide nuisance estimators -for mediation in causal inference -""" - -import numpy as np - -from sklearn.calibration import CalibratedClassifierCV -from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor -from sklearn.linear_model import LogisticRegressionCV, RidgeCV - -from med_bench.utils.constants import ALPHAS, CV_FOLDS, TINY - - -def _get_regularization_parameters(regularization): - """ - Obtain regularization parameters - - Returns - ------- - cs : list - each of the values in Cs describes the inverse of regularization - strength for predictors - alphas : list - alpha values to try in ridge models - """ - if regularization: - alphas = ALPHAS - cs = ALPHAS - else: - alphas = [TINY] - cs = [np.inf] - - return cs, alphas - - -def _get_classifier(regularization, forest, calibration, random_state=42): - """ - Obtain context classifiers to estimate treatment probabilities. - - Returns - ------- - clf : classifier on contexts, etc. for predicting P(T=1|X), - P(T=1|X, M) or f(M|T,X) - """ - cs, _ = _get_regularization_parameters(regularization) - - if not forest: - clf = LogisticRegressionCV(random_state=random_state, Cs=cs, cv=CV_FOLDS) - else: - clf = RandomForestClassifier( - random_state=random_state, n_estimators=100, min_samples_leaf=10 - ) - if calibration in {"sigmoid", "isotonic"}: - clf = CalibratedClassifierCV(clf, method=calibration) - - return clf - - -def _get_regressor(regularization, forest, random_state=42): - """ - Obtain regressors to estimate conditional mean outcomes. - - Returns - ------- - reg : regressor on contexts, etc. for predicting E[Y|T,M,X], etc. - """ - _, alphas = _get_regularization_parameters(regularization) - - if not forest: - reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) - else: - reg = RandomForestRegressor(n_estimators=100, min_samples_leaf=10) - - return reg diff --git a/src/med_bench/utils/scores.py b/src/med_bench/utils/scores.py deleted file mode 100644 index b8e36bf..0000000 --- a/src/med_bench/utils/scores.py +++ /dev/null @@ -1,43 +0,0 @@ -import numpy as np - - -def ipw_risk(y, t, hat_y, hat_e, trimming=None): - if trimming is not None: - clipped_hat_e = np.clip(hat_e, trimming, 1 - trimming) - else: - clipped_hat_e = hat_e - ipw_weights = t / clipped_hat_e + (1 - t) / (1 - clipped_hat_e) - return np.sum(((y - hat_y) ** 2) * ipw_weights) / len(y) - - -def r_risk(y, t, hat_m, hat_e, hat_tau): - return np.mean(((y - hat_m) - (t - hat_e) * hat_tau) ** 2) - - -def u_risk(y, t, hat_m, hat_e, hat_tau): - return np.mean(((y - hat_m) / (t - hat_e) - hat_tau) ** 2) - - -def w_risk(y, t, hat_e, hat_tau, trimming=None): - if trimming is not None: - clipped_hat_e = np.clip(hat_e, trimming, 1 - trimming) - else: - clipped_hat_e = hat_e - pseudo_outcome = (y * (t - clipped_hat_e)) / (clipped_hat_e * (1 - clipped_hat_e)) - return np.mean((pseudo_outcome - hat_tau) ** 2) - - -def ipw_r_risk(y, t, hat_mu_0, hat_mu_1, hat_e, hat_m, trimming=None): - if trimming is not None: - clipped_hat_e = np.clip(hat_e, trimming, 1 - trimming) - else: - clipped_hat_e = hat_e - ipw_weights = t / clipped_hat_e + (1 - t) / (1 - clipped_hat_e) - hat_tau = hat_mu_1 - hat_mu_0 - - return np.sum((((y - hat_m) - (t - hat_e) * (hat_tau)) ** 2) * ipw_weights) / len(y) - - -def ipw_r_risk_oracle(y, t, hat_mu_0, hat_mu_1, e, mu_1, mu_0): - m = mu_0 * (1 - e) + mu_1 * e - return ipw_r_risk(y=y, t=t, hat_mu_0=hat_mu_0, hat_mu_1=hat_mu_1, hat_e=e, hat_m=m) diff --git a/src/med_bench/utils/utils.py b/src/med_bench/utils/utils.py index 2805d13..017f145 100644 --- a/src/med_bench/utils/utils.py +++ b/src/med_bench/utils/utils.py @@ -7,6 +7,8 @@ import subprocess +from med_bench.utils.constants import ALPHAS, TINY + def check_r_dependencies(): try: @@ -37,6 +39,58 @@ def check_r_dependencies(): return False +def _get_interactions(interaction, *args): + """ + this function provides interaction terms between different groups of + variables (confounders, treatment, mediators) + + Parameters + ---------- + interaction : boolean + whether to compute interaction terms + + *args : flexible, one or several arrays + blocks of variables between which interactions should be + computed + + + Returns + -------- + array_like + interaction terms + + Examples + -------- + >>> x = np.arange(6).reshape(3, 2) + >>> t = np.ones((3, 1)) + >>> m = 2 * np.ones((3, 1)) + >>> get_interactions(False, x, t, m) + array([[0., 1., 1., 2.], + [2., 3., 1., 2.], + [4., 5., 1., 2.]]) + >>> get_interactions(True, x, t, m) + array([[ 0., 1., 1., 2., 0., 1., 0., 2., 2.], + [ 2., 3., 1., 2., 2., 3., 4., 6., 2.], + [ 4., 5., 1., 2., 4., 5., 8., 10., 2.]]) + """ + variables = list(args) + for index, var in enumerate(variables): + if len(var.shape) == 1: + variables[index] = var.reshape(-1, 1) + pre_inter_variables = np.hstack(variables) + if not interaction: + return pre_inter_variables + new_cols = list() + for i, var in enumerate(variables[:]): + for j, var2 in enumerate(variables[i + 1:]): + for ii in range(var.shape[1]): + for jj in range(var2.shape[1]): + new_cols.append((var[:, ii] * var2[:, jj]).reshape(-1, 1)) + new_vars = np.hstack(new_cols) + result = np.hstack((pre_inter_variables, new_vars)) + return result + + def is_r_installed(): try: subprocess.check_output(["R", "--version"]) @@ -106,58 +160,6 @@ def wrapper(*args, **kwargs): import rpy2.robjects as robjects -def _get_interactions(interaction, *args): - """ - this function provides interaction terms between different groups of - variables (confounders, treatment, mediators) - - Parameters - ---------- - interaction : boolean - whether to compute interaction terms - - *args : flexible, one or several arrays - blocks of variables between which interactions should be - computed - - - Returns - -------- - array_like - interaction terms - - Examples - -------- - >>> x = np.arange(6).reshape(3, 2) - >>> t = np.ones((3, 1)) - >>> m = 2 * np.ones((3, 1)) - >>> get_interactions(False, x, t, m) - array([[0., 1., 1., 2.], - [2., 3., 1., 2.], - [4., 5., 1., 2.]]) - >>> get_interactions(True, x, t, m) - array([[ 0., 1., 1., 2., 0., 1., 0., 2., 2.], - [ 2., 3., 1., 2., 2., 3., 4., 6., 2.], - [ 4., 5., 1., 2., 4., 5., 8., 10., 2.]]) - """ - variables = list(args) - for index, var in enumerate(variables): - if len(var.shape) == 1: - variables[index] = var.reshape(-1, 1) - pre_inter_variables = np.hstack(variables) - if not interaction: - return pre_inter_variables - new_cols = list() - for i, var in enumerate(variables[:]): - for j, var2 in enumerate(variables[i + 1 :]): - for ii in range(var.shape[1]): - for jj in range(var2.shape[1]): - new_cols.append((var[:, ii] * var2[:, jj]).reshape(-1, 1)) - new_vars = np.hstack(new_cols) - result = np.hstack((pre_inter_variables, new_vars)) - return result - - def _convert_array_to_R(x): """ converts a numpy array to a R matrix or vector @@ -244,7 +246,8 @@ def _check_input(y, t, m, x, setting): raise ValueError("Multidimensional m (mediator) is not supported") if (setting == "binary") and (len(np.unique(m)) != 2): - raise ValueError("Only a binary one-dimensional m (mediator) is supported") + raise ValueError( + "Only a binary one-dimensional m (mediator) is supported") return y_converted, t_converted, m_converted, x_converted @@ -255,48 +258,23 @@ def is_array_integer(array): return all(list((array == array.astype(int)).squeeze())) -def str_to_bool(string): - if bool(string) == string: - return string - elif string == "True": - return True - elif string == "False": - return False - else: - raise ValueError # evil ValueError that doesn't tell you what the wrong value was - - -def bucketize_mediators(m, n_buckets=10, random_state=42): - kmeans = KMeans(n_clusters=n_buckets, random_state=random_state, n_init="auto").fit( - m - ) - return kmeans.predict(m) - - -def train_test_split_data(causal_data, test_size=0.33, random_state=42): - x, t, m, y = causal_data - x_train, x_test, t_train, t_test, m_train, m_test, y_train, y_test = ( - train_test_split(x, t, m, y, test_size=test_size, random_state=random_state) - ) - causal_data_train = x_train, t_train, m_train, y_train - causal_data_test = x_test, t_test, m_test, y_test - return causal_data_train, causal_data_test - - -def _get_train_test_lists(crossfit, n, x): +def _get_regularization_parameters(regularization): """ - Obtain train and test folds + Obtain regularization parameters Returns ------- - train_test_list : list - indexes with train and test indexes + cs : list + each of the values in Cs describes the inverse of regularization + strength for predictors + alphas : list + alpha values to try in ridge models """ - if crossfit < 2: - train_test_list = [[np.arange(n), np.arange(n)]] + if regularization: + alphas = ALPHAS + cs = ALPHAS else: - kf = KFold(n_splits=crossfit) - train_test_list = list() - for train_index, test_index in kf.split(x): - train_test_list.append([train_index, test_index]) - return train_test_list + alphas = [TINY] + cs = [np.inf] + + return cs, alphas diff --git a/src/tests/estimation/generate_tests_results.py b/src/tests/estimation/generate_tests_results.py index b698a05..4943674 100644 --- a/src/tests/estimation/generate_tests_results.py +++ b/src/tests/estimation/generate_tests_results.py @@ -1,7 +1,7 @@ import numpy as np from med_bench.get_simulated_data import simulate_data -from med_bench.get_estimation import get_estimation +from med_bench.get_estimation_results import get_estimation_results from med_bench.utils.constants import ESTIMATORS, PARAMETER_LIST, PARAMETER_NAME @@ -32,7 +32,7 @@ def _get_estimators_results(x, t, m, y, config, estimator): """ try: - res = get_estimation(x, t, m, y, estimator, config)[0:5] + res = get_estimation_results(x, t, m, y, estimator, config)[0:5] return res except Exception as e: From 825bb125541f1baa57f3f9408b6fa3276805b426 Mon Sep 17 00:00:00 2001 From: brash6 Date: Thu, 14 Nov 2024 15:22:45 +0100 Subject: [PATCH 56/84] tests refactored --- .../estimation/generate_tests_results.py | 4 +- .../estimation/get_estimation_results.py | 342 ++++++++++++++++++ src/tests/estimation/test_get_estimation.py | 15 +- src/tests/estimation/tests_results.npy | Bin 378850 -> 362785 bytes 4 files changed, 351 insertions(+), 10 deletions(-) create mode 100644 src/tests/estimation/get_estimation_results.py diff --git a/src/tests/estimation/generate_tests_results.py b/src/tests/estimation/generate_tests_results.py index 4943674..a559964 100644 --- a/src/tests/estimation/generate_tests_results.py +++ b/src/tests/estimation/generate_tests_results.py @@ -1,7 +1,7 @@ import numpy as np from med_bench.get_simulated_data import simulate_data -from med_bench.get_estimation_results import get_estimation_results +from tests.estimation.get_estimation_results import _get_estimation_results from med_bench.utils.constants import ESTIMATORS, PARAMETER_LIST, PARAMETER_NAME @@ -32,7 +32,7 @@ def _get_estimators_results(x, t, m, y, config, estimator): """ try: - res = get_estimation_results(x, t, m, y, estimator, config)[0:5] + res = _get_estimation_results(x, t, m, y, estimator, config)[0:5] return res except Exception as e: diff --git a/src/tests/estimation/get_estimation_results.py b/src/tests/estimation/get_estimation_results.py new file mode 100644 index 0000000..3c2f1bf --- /dev/null +++ b/src/tests/estimation/get_estimation_results.py @@ -0,0 +1,342 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import numpy as np + +from med_bench.r_mediation import ( + r_mediation_g_estimator, + r_mediation_dml, + r_mediate, +) + +from med_bench.estimation.mediation_coefficient_product import CoefficientProduct +from med_bench.estimation.mediation_dml import DoubleMachineLearning +from med_bench.estimation.mediation_g_computation import GComputation +from med_bench.estimation.mediation_ipw import InversePropensityWeighting +from med_bench.estimation.mediation_mr import MultiplyRobust +from med_bench.utils.utils import _get_regularization_parameters +from med_bench.utils.constants import CV_FOLDS + +from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor +from sklearn.linear_model import LogisticRegressionCV, RidgeCV +from sklearn.calibration import CalibratedClassifierCV + + +def _transform_outputs(causal_effects): + """Transforms outputs in the old format + + Args: + causal_effects (dict): dictionary of causal effects + + Returns: + list: list of causal effects + """ + total = causal_effects['total_effect'] + direct_treated = causal_effects['direct_effect_treated'] + direct_control = causal_effects['direct_effect_control'] + indirect_treated = causal_effects['indirect_effect_treated'] + indirect_control = causal_effects['indirect_effect_control'] + + return np.array(total, direct_treated, direct_control, indirect_treated, indirect_control, 0) + + +def _get_estimation_results(x, t, m, y, estimator, config): + """Dynamically selects and calls an estimator (class-based or legacy function) to estimate total, direct, and indirect effects.""" + + effects = None # Initialize variable to store the effects + + # Helper function for regularized regressor and classifier initialization + def _get_regularized_regressor_and_classifier(regularize=True, calibration=None, method="sigmoid"): + cs, alphas = _get_regularization_parameters(regularization=regularize) + clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) + reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) + if calibration: + clf = CalibratedClassifierCV(clf, method=method) + return clf, reg + + if estimator == "mediation_IPW_R": + # Use R-based mediation estimator with direct output extraction + x_r, t_r, m_r, y_r = [_convert_array_to_R(uu) for uu in (x, t, m, y)] + output_w = causalweight.medweight( + y=y_r, d=t_r, m=m_r, x=x_r, trim=0.0, ATET="FALSE", logit="TRUE", boot=2 + ) + raw_res_R = np.array(output_w.rx2("results")) + effects = raw_res_R[0, :] + + elif estimator == "coefficient_product": + # Class-based implementation for CoefficientProduct + estimator_obj = CoefficientProduct(regularize=True) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) + + elif estimator == "mediation_ipw_noreg": + # Class-based implementation for InversePropensityWeighting without regularization + clf, reg = _get_regularized_regressor_and_classifier(regularize=False) + estimator_obj = InversePropensityWeighting( + clip=1e-6, trim=0, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) + + elif estimator == "mediation_ipw_reg": + # Class-based implementation with regularization + clf, reg = _get_regularized_regressor_and_classifier(regularize=True) + estimator_obj = InversePropensityWeighting( + clip=1e-6, trim=0, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) + + elif estimator == "mediation_ipw_reg_calibration": + # Class-based implementation with regularization and calibration (sigmoid) + clf, reg = _get_regularized_regressor_and_classifier( + regularize=True, calibration=True, method="sigmoid") + estimator_obj = InversePropensityWeighting( + clip=1e-6, trim=0, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) + + elif estimator == "mediation_ipw_reg_calibration_iso": + # Class-based implementation with isotonic calibration + clf, reg = _get_regularized_regressor_and_classifier( + regularize=True, calibration=True, method="isotonic") + estimator_obj = InversePropensityWeighting( + clip=1e-6, trim=0, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) + + elif estimator == "mediation_ipw_forest": + # Class-based implementation with forest models + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + estimator_obj = InversePropensityWeighting( + clip=1e-6, trim=0, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) + + elif estimator == "mediation_ipw_forest_calibration": + # Class-based implementation with forest and calibrated sigmoid + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + calibrated_clf = CalibratedClassifierCV(clf, method="sigmoid") + estimator_obj = InversePropensityWeighting( + clip=1e-6, trim=0, classifier=calibrated_clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) + + elif estimator == "mediation_ipw_forest_calibration_iso": + # Class-based implementation with isotonic calibration + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + calibrated_clf = CalibratedClassifierCV(clf, method="isotonic") + estimator_obj = InversePropensityWeighting( + clip=1e-6, trim=0, classifier=calibrated_clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) + + elif estimator == "mediation_g_computation_noreg": + # Class-based implementation of GComputation without regularization + clf, reg = _get_regularized_regressor_and_classifier(regularize=False) + estimator_obj = GComputation(regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) + + elif estimator == "mediation_g_computation_reg": + # Class-based implementation of GComputation with regularization + clf, reg = _get_regularized_regressor_and_classifier(regularize=True) + estimator_obj = GComputation(regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) + + elif estimator == "mediation_g_computation_reg_calibration": + # Class-based implementation with regularization and calibrated sigmoid + clf, reg = _get_regularized_regressor_and_classifier( + regularize=True, calibration=True, method="sigmoid") + estimator_obj = GComputation(regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) + + elif estimator == "mediation_g_computation_reg_calibration_iso": + # Class-based implementation with isotonic calibration + clf, reg = _get_regularized_regressor_and_classifier( + regularize=True, calibration=True, method="isotonic") + estimator_obj = GComputation(regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) + + elif estimator == "mediation_g_computation_forest": + # Class-based implementation with forest models + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + estimator_obj = GComputation(regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) + + elif estimator == "mediation_multiply_robust_noreg": + # Class-based implementation for MultiplyRobust without regularization + clf, reg = _get_regularized_regressor_and_classifier(regularize=False) + estimator_obj = MultiplyRobust( + ratio="propensities", normalized=True, regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) + + elif estimator == "simulation_based": + # R-based function for simulation + effects = r_mediate(y, t, m, x, interaction=False) + + elif estimator == "mediation_dml": + # R-based function for Double Machine Learning with legacy config + effects = r_mediation_dml(y, t, m, x, trim=0.0, order=1) + + elif estimator == "mediation_dml_noreg": + # Class-based implementation for DoubleMachineLearning without regularization + clf, reg = _get_regularized_regressor_and_classifier(regularize=False) + estimator_obj = DoubleMachineLearning( + normalized=True, regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) + + # Regularized MultiplyRobust estimator + elif estimator == "mediation_multiply_robust_reg": + clf, reg = _get_regularized_regressor_and_classifier(regularize=True) + estimator_obj = MultiplyRobust( + ratio="propensities", normalized=True, regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) + + # Regularized MultiplyRobust with sigmoid calibration + elif estimator == "mediation_multiply_robust_reg_calibration": + clf, reg = _get_regularized_regressor_and_classifier( + regularize=True, calibration=True, method="sigmoid") + estimator_obj = MultiplyRobust( + ratio="propensities", normalized=True, regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) + + # Regularized MultiplyRobust with isotonic calibration + elif estimator == "mediation_multiply_robust_reg_calibration_iso": + clf, reg = _get_regularized_regressor_and_classifier( + regularize=True, calibration=True, method="isotonic") + estimator_obj = MultiplyRobust( + ratio="propensities", normalized=True, regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) + + elif estimator == "mediation_multiply_robust_forest": + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + estimator = MultiplyRobust( + ratio="propensities", normalized=True, regressor=reg, + classifier=clf) + estimator.fit(t, m, x, y) + causal_effects = estimator.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) + + # MultiplyRobust with forest and sigmoid calibration + elif estimator == "mediation_multiply_robust_forest_calibration": + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + calibrated_clf = CalibratedClassifierCV(clf, method="sigmoid") + estimator_obj = MultiplyRobust( + ratio="propensities", normalized=True, regressor=reg, classifier=calibrated_clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) + + # MultiplyRobust with forest and isotonic calibration + elif estimator == "mediation_multiply_robust_forest_calibration_iso": + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + calibrated_clf = CalibratedClassifierCV(clf, method="isotonic") + estimator_obj = MultiplyRobust( + ratio="propensities", normalized=True, regressor=reg, classifier=calibrated_clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) + + # Regularized Double Machine Learning + elif estimator == "mediation_dml_reg": + clf, reg = _get_regularized_regressor_and_classifier(regularize=True) + estimator_obj = DoubleMachineLearning( + normalized=True, regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) + + # Regularized Double Machine Learning with forest models + elif estimator == "mediation_dml_forest": + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + estimator_obj = DoubleMachineLearning( + normalized=True, regressor=reg, classifier=clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) + + # GComputation with forest and sigmoid calibration + elif estimator == "mediation_g_computation_forest_calibration": + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + calibrated_clf = CalibratedClassifierCV(clf, method="sigmoid") + estimator_obj = GComputation(regressor=reg, classifier=calibrated_clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) + + # GComputation with forest and isotonic calibration + elif estimator == "mediation_g_computation_forest_calibration_iso": + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42) + calibrated_clf = CalibratedClassifierCV(clf, method="isotonic") + estimator_obj = GComputation(regressor=reg, classifier=calibrated_clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) + + elif estimator == "mediation_g_estimator": + if config in (0, 1, 2): + effects = r_mediation_g_estimator(y, t, m, x) + else: + raise ValueError("Unrecognized estimator label.") + + # Catch unsupported estimators and raise an error + if effects is None: + raise ValueError( + f"Estimation failed for {estimator}. Check inputs or configuration.") + return effects diff --git a/src/tests/estimation/test_get_estimation.py b/src/tests/estimation/test_get_estimation.py index 04d57c8..1826d81 100644 --- a/src/tests/estimation/test_get_estimation.py +++ b/src/tests/estimation/test_get_estimation.py @@ -16,7 +16,7 @@ import numpy as np import os -from med_bench.get_estimation_results import get_estimation_results +from tests.estimation.get_estimation_results import _get_estimation_results from med_bench.get_simulated_data import simulate_data from med_bench.utils.utils import DependencyNotInstalledError, check_r_dependencies from med_bench.utils.constants import PARAMETER_LIST, PARAMETER_NAME, R_DEPENDENT_ESTIMATORS, TOLERANCE_DICT @@ -83,9 +83,8 @@ def config(dict_param): @pytest.fixture def effects_chap(x, t, m, y, estimator, config): # try whether estimator is implemented or not - try: - res = get_estimation_results(x, t, m, y, estimator, config)[0:5] + res = _get_estimation_results(x, t, m, y, estimator, config)[0:5] except Exception as e: if str(e) in ( "Estimator only supports 1D binary mediator.", @@ -127,12 +126,12 @@ def test_total_is_direct_plus_indirect(effects_chap): effects_chap[2] + effects_chap[3]) -def test_robustness_to_ravel_format(data, estimator, config, effects_chap): +def test_robustness_to_ravel_format(data_simulated, estimator, config, effects_chap): if "forest" in estimator: pytest.skip("Forest estimator skipped") assert np.all( - get_estimation_results(data[0], data[1], data[2], - data[3], estimator, config)[0:5] + _get_estimation_results(data_simulated[0], data_simulated[1], data_simulated[2], + data_simulated[3], estimator, config)[0:5] == pytest.approx( effects_chap, nan_ok=True ) # effects_chap is obtained with data[1].ravel() and data[3].ravel() @@ -190,8 +189,8 @@ def effects_chap_true(x_true, t_true, m_true, y_true, estimator_true, config_tru # try whether estimator is implemented or not try: - res = get_estimation_results(x_true, t_true, m_true, - y_true, estimator_true, config_true)[0:5] + res = _get_estimation_results(x_true, t_true, m_true, + y_true, estimator_true, config_true)[0:5] # NaN situations if np.all(np.isnan(res)): diff --git a/src/tests/estimation/tests_results.npy b/src/tests/estimation/tests_results.npy index b468ed39e6b32f01cec4b70482a6c8510faf8b8c..d04c49c5590dbe2db9ddfc8e442c0e4806db0129 100644 GIT binary patch delta 12388 zcmcgyd0bRS@`nMu(8#Jm#VF%FUN~-k9x)mwqKJYz?yewS3=9Lq$mK99M$J<^5HcEc zMxF;jbX8nQ1Y-Bf{L!INpuO(Ph2%BXgu(WzpCyzUgP7jAM*R{{L!B`)!p^2 zs_w2=^{TIZ+#b1;>3yLb+6zz9-Cl)lQk-1rd45Xt4-3y#KdXi zbcv>jWMfh^qUvRO55&+nwINKn=@#q?5G~EJ7>4l(!q~~z#bn*L$aSpmNGkw{u>q#Q zBu>CY-w9=7S+wdp*0)Q2EQlmM`E%d9dGlo^nV#3olqq?6qD;XnHL_v6JQAL2bTSR^ zHA~ikuQ1AjutUkK!=OW@ld1SDEsRqcWpZ8_4o@{kXsTwzki1ZMBGbIIz*(+^8AS%! zu3N5*sDuVy-Spgb@H<|ae0Djrw? zwvw;8=l&i)D_S-RXQ+6!7HCAqGE^ul0p>1AK&B{JRV>a$k+V$Dp-zMb7!2d{W`Ll1 zDKO3}8EBd~nHrx!ms!vx$Kc@E08SvGQShLe5+Q+U1T^wFFa&g#Q^f%Yben;u!oeu6 zC9h8hUKI}iz>W%>rOr+OmIOwQCIb;wbOea4M1)~{MG`c?L&YbDAq^J;_}b(wi-0FE zx02V)0#-FdDHIG?fz1-(scb4vL!}6|CK8!WhiNcG%~#>NW`UeUI`vHG%tDQeLa6~1 z6qYDKteQ0)I+V7R3*w7(WLedGnN9x=4nVL;5-=yT^3Z@4DZm𝔴>Mauh0Wk_7=Y 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 Ge*X)=1=eo> delta 28520 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¥b3L;gHF$ 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 IkB%k&4{JPoy#N3J From 9bff44b88d021d74501cfe2a27b84bdbeda5ab9f Mon Sep 17 00:00:00 2001 From: brash6 Date: Thu, 14 Nov 2024 15:22:57 +0100 Subject: [PATCH 57/84] files cleaning --- src/med_bench/estimation/base.py | 10 +- .../estimation/mediation_g_computation.py | 10 +- src/med_bench/example.py | 118 --- src/med_bench/get_estimation_results.py | 371 -------- src/med_bench/mediation.py | 796 ------------------ src/med_bench/r_mediation.py | 205 +++++ src/med_bench/utils/constants.py | 4 +- src/med_bench/utils/nuisances.py | 476 ----------- src/med_bench/utils/utils.py | 13 +- 9 files changed, 226 insertions(+), 1777 deletions(-) delete mode 100644 src/med_bench/example.py delete mode 100644 src/med_bench/get_estimation_results.py delete mode 100644 src/med_bench/mediation.py create mode 100644 src/med_bench/r_mediation.py delete mode 100644 src/med_bench/utils/nuisances.py diff --git a/src/med_bench/estimation/base.py b/src/med_bench/estimation/base.py index 6bfa501..9df9491 100644 --- a/src/med_bench/estimation/base.py +++ b/src/med_bench/estimation/base.py @@ -325,9 +325,9 @@ def _estimate_mediator_probability(self, t, m, x, y): Returns ------- - f_m0, array-like, shape (n_samples) + f_m0x, array-like, shape (n_samples) probabilities f(M|T=0,X) - f_m1, array-like, shape (n_samples) + f_m1x, array-like, shape (n_samples) probabilities f(M|T=1,X) """ n = len(y) @@ -340,10 +340,10 @@ def _estimate_mediator_probability(self, t, m, x, y): t0_x = np.hstack([t0.reshape(-1, 1), x]) t1_x = np.hstack([t1.reshape(-1, 1), x]) - fm_0 = self._classifier_m.predict_proba(t0_x)[:, 1] - fm_1 = self._classifier_m.predict_proba(t1_x)[:, 1] + f_m0x = self._classifier_m.predict_proba(t0_x)[:, m] + f_m1x = self._classifier_m.predict_proba(t1_x)[:, m] - return fm_0, fm_1 + return f_m0x, f_m1x def _estimate_mediators_probabilities(self, t, m, x, y): """ diff --git a/src/med_bench/estimation/mediation_g_computation.py b/src/med_bench/estimation/mediation_g_computation.py index a813b41..abf6f86 100644 --- a/src/med_bench/estimation/mediation_g_computation.py +++ b/src/med_bench/estimation/mediation_g_computation.py @@ -2,7 +2,7 @@ from med_bench.estimation.base import Estimator from med_bench.utils.decorators import fitted -from med_bench.utils.utils import is_array_integer +from med_bench.utils.utils import is_array_binary class GComputation(Estimator): @@ -35,7 +35,7 @@ def fit(self, t, m, x, y): """Fits nuisance parameters to data""" t, m, x, y = self._resize(t, m, x, y) - if is_array_integer(m): + if is_array_binary(m): self._fit_mediator_nuisance(t, m, x, y) self._fit_conditional_mean_outcome_nuisance(t, m, x, y) else: @@ -55,10 +55,10 @@ def estimate(self, t, m, x, y): """ t, m, x, y = self._resize(t, m, x, y) - if is_array_integer(m): - mu_00x, mu_01x, mu_10x, mu_11x = self._estimate_mediators_probabilities( + if is_array_binary(m): + f_00x, f_01x, f_10x, f_11x = self._estimate_mediators_probabilities( t, m, x, y) - f_00x, f_01x, f_10x, f_11x = self._estimate_conditional_mean_outcome( + mu_00x, mu_01x, mu_10x, mu_11x = self._estimate_conditional_mean_outcome( t, m, x, y) direct_effect_i1 = mu_11x - mu_01x diff --git a/src/med_bench/example.py b/src/med_bench/example.py deleted file mode 100644 index 7768760..0000000 --- a/src/med_bench/example.py +++ /dev/null @@ -1,118 +0,0 @@ -from numpy.random import default_rng -import pandas as pd -from sklearn.calibration import CalibratedClassifierCV -from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor -from sklearn.linear_model import LogisticRegressionCV, RidgeCV -from sklearn.model_selection import train_test_split - -from med_bench.mediation import (mediation_IPW, mediation_coefficient_product, mediation_dml, - mediation_g_formula, mediation_multiply_robust) -from med_bench.estimation.mediation_coefficient_product import CoefficientProduct -from med_bench.estimation.mediation_dml import DoubleMachineLearning -from med_bench.estimation.mediation_g_computation import GComputation -from med_bench.estimation.mediation_ipw import ImportanceWeighting -from med_bench.estimation.mediation_mr import MultiplyRobust -from med_bench.get_simulated_data import simulate_data -from med_bench.nuisances.utils import _get_regularization_parameters -from med_bench.utils.constants import CV_FOLDS - - -print("get simulated data") -(x, t, m, y, - theta_1_delta_0, theta_1, theta_0, delta_1, delta_0, - p_t, th_p_t_mx) = simulate_data(n=1000, rg=default_rng(321), dim_x=5) - -(x_train, x_test, t_train, t_test, - m_train, m_test, y_train, y_test) = train_test_split(x, t, m, y, test_size=0.33, random_state=42) - -cs, alphas = _get_regularization_parameters(regularization=True) - -clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) - -clf2 = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) - -reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - -reg2 = RidgeCV(alphas=alphas, cv=CV_FOLDS) - -# Step 4: Define estimators (modularized and non-modularized) -estimators = { - "CoefficientProduct": { - "modular": CoefficientProduct( - regressor=reg, classifier=clf, regularize=True - ), - "non_modular": mediation_coefficient_product - }, - "DoubleMachineLearning": { - "modular": DoubleMachineLearning( - clip=1e-6, trim=0.05, normalized=True, regressor=reg2, classifier=clf2 - ), - "non_modular": mediation_dml - }, - "GComputation": { - "modular": GComputation( - regressor=reg2, classifier=CalibratedClassifierCV( - clf2, method="sigmoid") - ), - "non_modular": mediation_g_formula - }, - "ImportanceWeighting": { - "modular": ImportanceWeighting( - clip=1e-6, trim=0.01, regressor=reg2, classifier=CalibratedClassifierCV(clf2, method="sigmoid") - ), - "non_modular": mediation_IPW - }, - "MultiplyRobust": { - "modular": MultiplyRobust( - clip=1e-6, ratio="propensities", normalized=True, regressor=reg2, - classifier=CalibratedClassifierCV(clf2, method="sigmoid") - ), - "non_modular": mediation_multiply_robust - } -} - -# Step 5: Initialize results DataFrame -results = [] - -# Step 6: Iterate over each estimator -for estimator_name, estimator_dict in estimators.items(): - # Non-Modularized Estimation - # Check if non-modular is a function - if callable(estimator_dict["non_modular"]): - (total_effect, direct_effect1, direct_effect2, indirect_effect1, indirect_effect2, _) = estimator_dict["non_modular"]( - y, t, m, x) - - results.append({ - "Estimator": estimator_name, - "Method": "Non-Modularized", - "Total Effect": total_effect, - "Direct Effect (Treated)": direct_effect1, - "Direct Effect (Control)": direct_effect2, - "Indirect Effect (Treated)": indirect_effect1, - "Indirect Effect (Control)": indirect_effect2, - }) - - # Modularized Estimation - modular_estimator = estimator_dict["modular"] - modular_estimator.fit(t_train, m_train, x_train, y_train) - causal_effects = modular_estimator.estimate( - t_test, m_test, x_test, y_test) - - # Append modularized results - results.append({ - "Estimator": estimator_name, - "Method": "Modularized", - "Total Effect": causal_effects['total_effect'], - "Direct Effect (Treated)": causal_effects['direct_effect_treated'], - "Direct Effect (Control)": causal_effects['direct_effect_control'], - "Indirect Effect (Treated)": causal_effects['indirect_effect_treated'], - "Indirect Effect (Control)": causal_effects['indirect_effect_control'], - }) - -# Convert results to DataFrame -results_df = pd.DataFrame(results) - -# Display or save the DataFrame -print(results_df) diff --git a/src/med_bench/get_estimation_results.py b/src/med_bench/get_estimation_results.py deleted file mode 100644 index 8ca2c2e..0000000 --- a/src/med_bench/get_estimation_results.py +++ /dev/null @@ -1,371 +0,0 @@ -#!/usr/bin/env python -# -*- coding:utf-8 -*- - -import numpy as np - -from .mediation import ( - mediation_dml, - r_mediation_g_estimator, - r_mediation_dml, - r_mediate, -) - -from med_bench.estimation.mediation_coefficient_product import CoefficientProduct -from med_bench.estimation.mediation_dml import DoubleMachineLearning -from med_bench.estimation.mediation_g_computation import GComputation -from med_bench.estimation.mediation_ipw import InversePropensityWeighting -from med_bench.estimation.mediation_mr import MultiplyRobust -from med_bench.utils.utils import _get_regularization_parameters -from med_bench.utils.constants import CV_FOLDS - -from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor -from sklearn.linear_model import LogisticRegressionCV, RidgeCV -from sklearn.calibration import CalibratedClassifierCV - - -def transform_outputs(causal_effects): - """Transforms outputs in the old format - - Args: - causal_effects (dict): dictionary of causal effects - - Returns: - list: list of causal effects - """ - total = causal_effects['total_effect'] - direct_treated = causal_effects['direct_effect_treated'] - direct_control = causal_effects['direct_effect_control'] - indirect_treated = causal_effects['indirect_effect_treated'] - indirect_control = causal_effects['indirect_effect_control'] - - return [total, direct_treated, direct_control, indirect_treated, indirect_control, 0] - - -def get_estimation_results(x, t, m, y, estimator, config): - """Dynamically selects and calls an estimator (class-based or legacy function) to estimate total, direct, and indirect effects.""" - - effects = None # Initialize variable to store the effects - - # Helper function for regularized regressor and classifier initialization - def get_regularized_regressor_and_classifier(regularize=True, calibration=None, method="sigmoid"): - cs, alphas = _get_regularization_parameters(regularization=regularize) - clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) - reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) - if calibration: - clf = CalibratedClassifierCV(clf, method=method) - return clf, reg - - if estimator == "mediation_IPW_R": - # Use R-based mediation estimator with direct output extraction - x_r, t_r, m_r, y_r = [_convert_array_to_R(uu) for uu in (x, t, m, y)] - output_w = causalweight.medweight( - y=y_r, d=t_r, m=m_r, x=x_r, trim=0.0, ATET="FALSE", logit="TRUE", boot=2 - ) - raw_res_R = np.array(output_w.rx2("results")) - effects = raw_res_R[0, :] - - elif estimator == "coefficient_product": - # Class-based implementation for CoefficientProduct - estimator_obj = CoefficientProduct(regularize=True) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - elif estimator == "mediation_ipw_noreg": - # Class-based implementation for InversePropensityWeighting without regularization - clf, reg = get_regularized_regressor_and_classifier(regularize=False) - estimator_obj = InversePropensityWeighting( - clip=1e-6, trim=0, classifier=clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - elif estimator == "mediation_ipw_reg": - # Class-based implementation with regularization - clf, reg = get_regularized_regressor_and_classifier(regularize=True) - estimator_obj = InversePropensityWeighting( - clip=1e-6, trim=0, classifier=clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - elif estimator == "mediation_ipw_reg_calibration": - # Class-based implementation with regularization and calibration (sigmoid) - clf, reg = get_regularized_regressor_and_classifier( - regularize=True, calibration=True, method="sigmoid") - estimator_obj = InversePropensityWeighting( - clip=1e-6, trim=0, classifier=clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - elif estimator == "mediation_ipw_reg_calibration_iso": - # Class-based implementation with isotonic calibration - clf, reg = get_regularized_regressor_and_classifier( - regularize=True, calibration=True, method="isotonic") - estimator_obj = InversePropensityWeighting( - clip=1e-6, trim=0, classifier=clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - elif estimator == "mediation_ipw_forest": - # Class-based implementation with forest models - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - estimator_obj = InversePropensityWeighting( - clip=1e-6, trim=0, classifier=clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - elif estimator == "mediation_ipw_forest_calibration": - # Class-based implementation with forest and calibrated sigmoid - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - calibrated_clf = CalibratedClassifierCV(clf, method="sigmoid") - estimator_obj = InversePropensityWeighting( - clip=1e-6, trim=0, classifier=calibrated_clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - elif estimator == "mediation_ipw_forest_calibration_iso": - # Class-based implementation with isotonic calibration - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - calibrated_clf = CalibratedClassifierCV(clf, method="isotonic") - estimator_obj = InversePropensityWeighting( - clip=1e-6, trim=0, classifier=calibrated_clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - elif estimator == "mediation_g_computation_noreg": - # Class-based implementation of GComputation without regularization - clf, reg = get_regularized_regressor_and_classifier(regularize=False) - estimator_obj = GComputation(regressor=reg, classifier=clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - elif estimator == "mediation_g_computation_reg": - # Class-based implementation of GComputation with regularization - clf, reg = get_regularized_regressor_and_classifier(regularize=True) - estimator_obj = GComputation(regressor=reg, classifier=clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - elif estimator == "mediation_g_computation_reg_calibration": - # Class-based implementation with regularization and calibrated sigmoid - clf, reg = get_regularized_regressor_and_classifier( - regularize=True, calibration=True, method="sigmoid") - estimator_obj = GComputation(regressor=reg, classifier=clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - elif estimator == "mediation_g_computation_reg_calibration_iso": - # Class-based implementation with isotonic calibration - clf, reg = get_regularized_regressor_and_classifier( - regularize=True, calibration=True, method="isotonic") - estimator_obj = GComputation(regressor=reg, classifier=clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - elif estimator == "mediation_g_computation_forest": - # Class-based implementation with forest models - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - estimator_obj = GComputation(regressor=reg, classifier=clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - elif estimator == "mediation_multiply_robust_noreg": - # Class-based implementation for MultiplyRobust without regularization - clf, reg = get_regularized_regressor_and_classifier(regularize=False) - estimator_obj = MultiplyRobust( - ratio="propensities", normalized=True, regressor=reg, classifier=clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - elif estimator == "simulation_based": - # R-based function for simulation - effects = r_mediate(y, t, m, x, interaction=False) - - elif estimator == "mediation_dml": - # R-based function for Double Machine Learning with legacy config - effects = r_mediation_dml(y, t, m, x, trim=0.0, order=1) - - elif estimator == "mediation_dml_noreg": - # Class-based implementation for DoubleMachineLearning without regularization - clf, reg = get_regularized_regressor_and_classifier(regularize=False) - estimator_obj = DoubleMachineLearning( - clip=1e-6, trim=0, normalized=True, regressor=reg, classifier=clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - # Regularized MultiplyRobust estimator - elif estimator == "mediation_multiply_robust_reg": - clf, reg = get_regularized_regressor_and_classifier(regularize=True) - estimator_obj = MultiplyRobust( - ratio="propensities", normalized=True, regressor=reg, classifier=clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - # Regularized MultiplyRobust with sigmoid calibration - elif estimator == "mediation_multiply_robust_reg_calibration": - clf, reg = get_regularized_regressor_and_classifier( - regularize=True, calibration=True, method="sigmoid") - estimator_obj = MultiplyRobust( - ratio="propensities", normalized=True, regressor=reg, classifier=clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - # Regularized MultiplyRobust with isotonic calibration - elif estimator == "mediation_multiply_robust_reg_calibration_iso": - clf, reg = get_regularized_regressor_and_classifier( - regularize=True, calibration=True, method="isotonic") - estimator_obj = MultiplyRobust( - ratio="propensities", normalized=True, regressor=reg, classifier=clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - elif estimator == "mediation_multiply_robust_forest": - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - estimator = MultiplyRobust( - ratio="propensities", normalized=True, regressor=reg, - classifier=clf) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - # MultiplyRobust with forest and sigmoid calibration - elif estimator == "mediation_multiply_robust_forest_calibration": - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - calibrated_clf = CalibratedClassifierCV(clf, method="sigmoid") - estimator_obj = MultiplyRobust( - ratio="propensities", normalized=True, regressor=reg, classifier=calibrated_clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - # MultiplyRobust with forest and isotonic calibration - elif estimator == "mediation_multiply_robust_forest_calibration_iso": - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - calibrated_clf = CalibratedClassifierCV(clf, method="isotonic") - estimator_obj = MultiplyRobust( - ratio="propensities", normalized=True, regressor=reg, classifier=calibrated_clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - # Regularized Double Machine Learning - elif estimator == "mediation_dml_reg": - clf, reg = get_regularized_regressor_and_classifier(regularize=True) - estimator_obj = DoubleMachineLearning( - clip=1e-6, trim=0, normalized=True, regressor=reg, classifier=clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - # Double Machine Learning with fixed seed - elif estimator == "mediation_dml_reg_fixed_seed": - effects = mediation_dml( - y, t, m, x, trim=0, clip=1e-6, random_state=321, calibration=None) - - # Regularized Double Machine Learning with sigmoid calibration - elif estimator == "mediation_dml_reg_calibration": - clf, reg = get_regularized_regressor_and_classifier( - regularize=True, calibration=True, method="sigmoid") - estimator_obj = DoubleMachineLearning( - clip=1e-6, trim=0, normalized=True, regressor=reg, classifier=clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - # Regularized Double Machine Learning with forest models - elif estimator == "mediation_dml_forest": - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - estimator_obj = DoubleMachineLearning( - clip=1e-6, trim=0, normalized=True, regressor=reg, classifier=clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - # Double Machine Learning with forest and calibrated sigmoid - elif estimator == "mediation_dml_forest_calibration": - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - calibrated_clf = CalibratedClassifierCV(clf, method="sigmoid") - estimator_obj = DoubleMachineLearning( - clip=1e-6, trim=0, normalized=True, regressor=reg, classifier=calibrated_clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - # GComputation with forest and sigmoid calibration - elif estimator == "mediation_g_computation_forest_calibration": - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - calibrated_clf = CalibratedClassifierCV(clf, method="sigmoid") - estimator_obj = GComputation(regressor=reg, classifier=calibrated_clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - # GComputation with forest and isotonic calibration - elif estimator == "mediation_g_computation_forest_calibration_iso": - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - calibrated_clf = CalibratedClassifierCV(clf, method="isotonic") - estimator_obj = GComputation(regressor=reg, classifier=calibrated_clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = transform_outputs(causal_effects) - - elif estimator == "mediation_g_estimator": - if config in (0, 1, 2): - effects = r_mediation_g_estimator(y, t, m, x) - else: - raise ValueError("Unrecognized estimator label.") - - # Catch unsupported estimators and raise an error - if effects is None: - raise ValueError( - f"Estimation failed for {estimator}. Check inputs or configuration.") - return effects diff --git a/src/med_bench/mediation.py b/src/med_bench/mediation.py deleted file mode 100644 index 66b69fd..0000000 --- a/src/med_bench/mediation.py +++ /dev/null @@ -1,796 +0,0 @@ -""" -the objective of this script is to implement estimators for mediation in -causal inference, simulate data, and evaluate and compare estimators -""" - -# first step, run r code to have the original implementation by Huber -# using rpy2 to have the same data in R and python... - -import numpy as np -import pandas as pd -from sklearn.base import clone - - -from .utils.nuisances import ( - _estimate_conditional_mean_outcome, - _estimate_cross_conditional_mean_outcome, - _estimate_cross_conditional_mean_outcome_nesting, - _estimate_mediator_density, - _estimate_treatment_probabilities, - _get_classifier, - _get_regressor, -) -from .utils.utils import r_dependency_required, _check_input - -ALPHAS = np.logspace(-5, 5, 8) -CV_FOLDS = 5 -TINY = 1.0e-12 - - -def mediation_IPW( - y, - t, - m, - x, - trim=0.05, - regularization=True, - forest=False, - crossfit=0, - clip=1e-6, - calibration="sigmoid", -): - """ - IPW estimator presented in - HUBER, Martin. Identifying causal mechanisms (primarily) based on inverse - probability weighting. Journal of Applied Econometrics, 2014, - vol. 29, no 6, p. 920-943. - - Parameters - ---------- - y : array-like, shape (n_samples) - outcome value for each unit, continuous - - t : array-like, shape (n_samples) - treatment value for each unit, binary - - m : array-like, shape (n_samples, n_features_mediator) - mediator value for each unit, can be continuous or binary, and - multidimensional - - x : array-like, shape (n_samples, n_features_covariates) - covariates (potential confounders) values - - trim : float - Trimming rule for discarding observations with extreme propensity - scores. In the absence of post-treatment confounders (w=NULL), - observations with Pr(D=1|M,X)(1-trim) are - dropped. In the presence of post-treatment confounders - (w is defined), observations with Pr(D=1|M,W,X)(1-trim) are dropped. - - regularization : boolean, default=True - whether to use regularized models (logistic or - linear regression). If True, cross-validation is used - to chose among 8 potential log-spaced values between - 1e-5 and 1e5 - - forest : boolean, default=False - whether to use a random forest model to estimate the propensity - scores instead of logistic regression - - crossfit : integer, default=0 - number of folds for cross-fitting - - clip : float, default=1e-6 - limit to clip for numerical stability (min=clip, max=1-clip) - - calibration : str, default=sigmoid - calibration mode; for example using a sigmoid function - - Returns - ------- - float - total effect - float - direct effect treated (\theta(1)) - float - direct effect nontreated (\theta(0)) - float - indirect effect treated (\delta(1)) - float - indirect effect untreated (\delta(0)) - int - number of used observations (non trimmed) - """ - # check input - y, t, m, x = _check_input(y, t, m, x, setting="multidimensional") - - # estimate propensities - classifier_t_x = _get_classifier(regularization, forest, calibration) - classifier_t_xm = _get_classifier(regularization, forest, calibration) - p_x, p_xm = _estimate_treatment_probabilities( - t, m, x, crossfit, classifier_t_x, classifier_t_xm - ) - - # trimming. Following causal weight code, not sure I understand - # why we trim only on p_xm and not on p_x - ind = (p_xm > trim) & (p_xm < (1 - trim)) - y, t, p_x, p_xm = y[ind], t[ind], p_x[ind], p_xm[ind] - - # note on the names, ytmt' = Y(t, M(t')), the treatment needs to be - # binary but not the mediator - p_x = np.clip(p_x, clip, 1 - clip) - p_xm = np.clip(p_xm, clip, 1 - clip) - - # importance weighting - y1m1 = np.sum(y * t / p_x) / np.sum(t / p_x) - y1m0 = np.sum(y * t * (1 - p_xm) / (p_xm * (1 - p_x))) / np.sum( - t * (1 - p_xm) / (p_xm * (1 - p_x)) - ) - y0m0 = np.sum(y * (1 - t) / (1 - p_x)) / np.sum((1 - t) / (1 - p_x)) - y0m1 = np.sum(y * (1 - t) * p_xm / ((1 - p_xm) * p_x)) / np.sum( - (1 - t) * p_xm / ((1 - p_xm) * p_x) - ) - - return ( - y1m1 - y0m0, - y1m1 - y0m1, - y1m0 - y0m0, - y1m1 - y1m0, - y0m1 - y0m0, - np.sum(ind), - ) - - -def mediation_g_formula( - y, - t, - m, - x, - interaction=False, - forest=False, - crossfit=0, - regularization=True, - calibration="sigmoid", -): - """ - Warning : m needs to be binary - - implementation of the g formula for mediation - - Parameters - ---------- - y : array-like, shape (n_samples) - outcome value for each unit, continuous - - t : array-like, shape (n_samples) - treatment value for each unit, binary - - m : array-like, shape (n_samples) - mediator value for each unit, here m is necessary binary and uni- - dimensional - - x : array-like, shape (n_samples, n_features_covariates) - covariates (potential confounders) values - - interaction : boolean, default=False - whether to include interaction terms in the model - interactions are terms XT, TM, MX - - forest : boolean, default=False - whether to use a random forest model to estimate the propensity - scores instead of logistic regression, and outcome model instead - of linear regression - - crossfit : integer, default=0 - number of folds for cross-fitting - - regularization : boolean, default=True - whether to use regularized models (logistic or - linear regression). If True, cross-validation is used - to chose among 8 potential log-spaced values between - 1e-5 and 1e5 - - calibration : str, default=sigmoid - calibration mode; for example using a sigmoid function - """ - # check input - y, t, m, x = _check_input(y, t, m, x, setting="binary") - - # estimate mediator densities - classifier_m = _get_classifier(regularization, forest, calibration) - f_00x, f_01x, f_10x, f_11x, _, _ = _estimate_mediator_density( - y, t, m, x, crossfit, classifier_m, interaction - ) - - # estimate conditional mean outcomes - regressor_y = _get_regressor(regularization, forest) - mu_00x, mu_01x, mu_10x, mu_11x, _, _ = _estimate_conditional_mean_outcome( - y, t, m, x, crossfit, regressor_y, interaction - ) - - # G computation - direct_effect_i1 = mu_11x - mu_01x - direct_effect_i0 = mu_10x - mu_00x - n = len(y) - direct_effect_treated = ( - direct_effect_i1 * f_11x + direct_effect_i0 * f_10x - ).sum() / n - direct_effect_control = ( - direct_effect_i1 * f_01x + direct_effect_i0 * f_00x - ).sum() / n - indirect_effect_i1 = f_11x - f_01x - indirect_effect_i0 = f_10x - f_00x - indirect_effect_treated = ( - indirect_effect_i1 * mu_11x + indirect_effect_i0 * mu_10x - ).sum() / n - indirect_effect_control = ( - indirect_effect_i1 * mu_01x + indirect_effect_i0 * mu_00x - ).sum() / n - total_effect = direct_effect_control + indirect_effect_treated - - return ( - total_effect, - direct_effect_treated, - direct_effect_control, - indirect_effect_treated, - indirect_effect_control, - None, - ) - - -def mediation_multiply_robust( - y, - t, - m, - x, - interaction=False, - forest=False, - crossfit=0, - clip=1e-6, - normalized=True, - regularization=True, - calibration="sigmoid", -): - """ - Presented in Eric J. Tchetgen Tchetgen. Ilya Shpitser. - "Semiparametric theory for causal mediation analysis: Efficiency bounds, - multiple robustness and sensitivity analysis." - Ann. Statist. 40 (3) 1816 - 1845, June 2012. - https://doi.org/10.1214/12-AOS990 - - Parameters - ---------- - y : array-like, shape (n_samples) - Outcome value for each unit, continuous - - t : array-like, shape (n_samples) - Treatment value for each unit, binary - - m : array-like, shape (n_samples) - Mediator value for each unit, binary and unidimensional - - x : array-like, shape (n_samples, n_features_covariates) - Covariates value for each unit, continuous - - interaction : boolean, default=False - Whether to include interaction terms in the model - interactions are terms XT, TM, MX - - forest : boolean, default=False - Whether to use a random forest model to estimate the propensity - scores instead of logistic regression, and outcome model instead - of linear regression - - crossfit : integer, default=0 - Number of folds for cross-fitting. If crossfit<2, no cross-fitting is - applied - - clip : float, default=1e-6 - Limit to clip p_x and f_mtx for numerical stability (min=clip, - max=1-clip) - - normalized : boolean, default=True - Normalizes the inverse probability-based weights so they add up to 1, - as described in "Identifying causal mechanisms (primarily) based on - inverse probability weighting", Huber (2014), - https://doi.org/10.1002/jae.2341 - - regularization : boolean, default=True - Whether to use regularized models (logistic or linear regression). - If True, cross-validation is used to chose among 8 potential - log-spaced values between 1e-5 and 1e5 - - calibration : str, default="sigmoid" - Which calibration method to use. - Implemented calibration methods are "sigmoid" and "isotonic". - - - Returns - ------- - total : float - Average total effect. - direct1 : float - Direct effect on the exposed. - direct0 : float - Direct effect on the unexposed, - indirect1 : float - Indirect effect on the exposed. - indirect0 : float - Indirect effect on the unexposed. - n_discarded : int - Number of discarded samples due to trimming. - - - Raises - ------ - ValueError - - If t or y are multidimensional. - - If x, t, m, or y don't have the same length. - - If m is not binary. - """ - # check input - y, t, m, x = _check_input(y, t, m, x, setting="binary") - - # estimate propensities - classifier_t_x = _get_classifier(regularization, forest, calibration) - p_x, _ = _estimate_treatment_probabilities( - t, m, x, crossfit, classifier_t_x, clone(classifier_t_x) - ) - - # estimate mediator densities - classifier_m = _get_classifier(regularization, forest, calibration) - f_00x, f_01x, f_10x, f_11x, f_m0x, f_m1x = _estimate_mediator_density( - y, t, m, x, crossfit, classifier_m, interaction - ) - f = f_00x, f_01x, f_10x, f_11x - - # estimate conditional mean outcomes - regressor_y = _get_regressor(regularization, forest) - regressor_cross_y = _get_regressor(regularization, forest) - mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 = ( - _estimate_cross_conditional_mean_outcome( - y, t, m, x, crossfit, regressor_y, regressor_cross_y, f, interaction - ) - ) - - # clipping - p_x_clip = p_x != np.clip(p_x, clip, 1 - clip) - f_m0x_clip = f_m0x != np.clip(f_m0x, clip, 1 - clip) - f_m1x_clip = f_m1x != np.clip(f_m1x, clip, 1 - clip) - clipped = p_x_clip + f_m0x_clip + f_m1x_clip - - var_name = ["t", "y", "p_x", "f_m0x", "f_m1x", "mu_1mx", "mu_0mx"] - var_name += ["E_mu_t1_t1", "E_mu_t0_t0", "E_mu_t1_t0", "E_mu_t0_t1"] - n_discarded = 0 - for var in var_name: - exec(f"{var} = {var}[~clipped]") - n_discarded += np.sum(clipped) - - # score computing - if normalized: - sum_score_m1 = np.mean(t / p_x) - sum_score_m0 = np.mean((1 - t) / (1 - p_x)) - sum_score_t1m0 = np.mean((t / p_x) * (f_m0x / f_m1x)) - sum_score_t0m1 = np.mean((1 - t) / (1 - p_x) * (f_m1x / f_m0x)) - - y1m1 = (t / p_x * (y - E_mu_t1_t1)) / sum_score_m1 + E_mu_t1_t1 - y0m0 = ((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / \ - sum_score_m0 + E_mu_t0_t0 - y1m0 = ( - ((t / p_x) * (f_m0x / f_m1x) * (y - mu_1mx)) / sum_score_t1m0 - + ((1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0)) / sum_score_m0 - + E_mu_t1_t0 - ) - y0m1 = ( - ((1 - t) / (1 - p_x) * (f_m1x / f_m0x) * (y - mu_0mx)) / sum_score_t0m1 - + t / p_x * (mu_0mx - E_mu_t0_t1) / sum_score_m1 - + E_mu_t0_t1 - ) - else: - y1m1 = t / p_x * (y - E_mu_t1_t1) + E_mu_t1_t1 - y0m0 = (1 - t) / (1 - p_x) * (y - E_mu_t0_t0) + E_mu_t0_t0 - y1m0 = ( - (t / p_x) * (f_m0x / f_m1x) * (y - mu_1mx) - + (1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0) - + E_mu_t1_t0 - ) - y0m1 = ( - (1 - t) / (1 - p_x) * (f_m1x / f_m0x) * (y - mu_0mx) - + t / p_x * (mu_0mx - E_mu_t0_t1) - + E_mu_t0_t1 - ) - - # effects computing - total = np.mean(y1m1 - y0m0) - direct1 = np.mean(y1m1 - y0m1) - direct0 = np.mean(y1m0 - y0m0) - indirect1 = np.mean(y1m1 - y1m0) - indirect0 = np.mean(y0m1 - y0m0) - - return total, direct1, direct0, indirect1, indirect0, n_discarded - - -@r_dependency_required(["mediation", "stats", "base"]) -def r_mediate(y, t, m, x, interaction=False): - """ - This function calls the R function mediate from the package mediation - (https://cran.r-project.org/package=mediation) - - Parameters - ---------- - y : array-like, shape (n_samples) - outcome value for each unit, continuous - - t : array-like, shape (n_samples) - treatment value for each unit, binary - - m : array-like, shape (n_samples) - mediator value for each unit, here m is necessary binary and - unidimensional - - x : array-like, shape (n_samples, n_features_covariates) - covariates (potential confounders) values - - interaction : boolean, default=False - whether to include interaction terms in the model - interactions are terms XT, TM, MX - """ - - import rpy2.robjects as robjects - import rpy2.robjects.packages as rpackages - from rpy2.robjects import numpy2ri, pandas2ri - - pandas2ri.activate() - numpy2ri.activate() - - mediation = rpackages.importr("mediation") - Rstats = rpackages.importr("stats") - base = rpackages.importr("base") - - # check input - y, t, m, x = _check_input(y, t, m, x, setting="binary") - m = m.ravel() - - var_names = [[y, "y"], [t, "t"], [m, "m"], [x, "x"]] - df_list = list() - for var, name in var_names: - if len(var.shape) > 1: - var_dim = var.shape[1] - col_names = ["{}_{}".format(name, i) for i in range(var_dim)] - sub_df = pd.DataFrame(var, columns=col_names) - else: - sub_df = pd.DataFrame(var, columns=[name]) - df_list.append(sub_df) - df = pd.concat(df_list, axis=1) - m_features = [c for c in df.columns if ("y" not in c) and ("m" not in c)] - y_features = [c for c in df.columns if ("y" not in c)] - if not interaction: - m_formula = "m ~ " + " + ".join(m_features) - y_formula = "y ~ " + " + ".join(y_features) - else: - m_formula = "m ~ " + " + ".join( - m_features + [":".join(p) for p in combinations(m_features, 2)] - ) - y_formula = "y ~ " + " + ".join( - y_features + [":".join(p) for p in combinations(y_features, 2)] - ) - robjects.globalenv["df"] = df - mediator_model = Rstats.lm(m_formula, data=base.as_symbol("df")) - outcome_model = Rstats.lm(y_formula, data=base.as_symbol("df")) - res = mediation.mediate( - mediator_model, outcome_model, treat="t", mediator="m", boot=True, sims=1 - ) - - relevant_variables = ["tau.coef", "z1", "z0", "d1", "d0"] - to_return = [np.array(res.rx2(v))[0] for v in relevant_variables] - return to_return + [None] - - -@r_dependency_required(["plmed", "base"]) -def r_mediation_g_estimator(y, t, m, x): - """ - This function calls the R G-estimator from the package plmed - (https://github.com/ohines/plmed) - """ - - import rpy2.robjects as robjects - import rpy2.robjects.packages as rpackages - from rpy2.robjects import numpy2ri, pandas2ri - - pandas2ri.activate() - numpy2ri.activate() - - plmed = rpackages.importr("plmed") - base = rpackages.importr("base") - - # check input - y, t, m, x = _check_input(y, t, m, x, setting="binary") - m = m.ravel() - - var_names = [[y, "y"], [t, "t"], [m, "m"], [x, "x"]] - df_list = list() - for var, name in var_names: - if len(var.shape) > 1: - var_dim = var.shape[1] - col_names = ["{}_{}".format(name, i) for i in range(var_dim)] - sub_df = pd.DataFrame(var, columns=col_names) - else: - sub_df = pd.DataFrame(var, columns=[name]) - df_list.append(sub_df) - df = pd.concat(df_list, axis=1) - m_features = [c for c in df.columns if ("x" in c)] - y_features = [c for c in df.columns if ("x" in c)] - t_features = [c for c in df.columns if ("x" in c)] - m_formula = "m ~ " + " + ".join(m_features) - y_formula = "y ~ " + " + ".join(y_features) - t_formula = "t ~ " + " + ".join(t_features) - robjects.globalenv["df"] = df - res = plmed.G_estimation( - t_formula, - m_formula, - y_formula, - exposure_family="binomial", - data=base.as_symbol("df"), - ) - direct_effect = res.rx2("coef")[0] - indirect_effect = res.rx2("coef")[1] - return ( - direct_effect + indirect_effect, - direct_effect, - direct_effect, - indirect_effect, - indirect_effect, - None, - ) - - -@r_dependency_required(["causalweight", "base"]) -def r_mediation_dml(y, t, m, x, trim=0.05, order=1): - """ - This function calls the R Double Machine Learning estimator from the - package causalweight (https://cran.r-project.org/web/packages/causalweight) - - Parameters - ---------- - y : array-like, shape (n_samples) - outcome value for each unit, continuous - - t : array-like, shape (n_samples) - treatment value for each unit, binary - - m : array-like, shape (n_samples, n_features_mediator) - mediator value for each unit, can be continuous or binary, and - multi-dimensional - - x : array-like, shape (n_samples, n_features_covariates) - covariates (potential confounders) values - - trim : float, default=0.05 - Trimming rule for discarding observations with extreme - conditional treatment or mediator probabilities - (or products thereof). Observations with (products of) - conditional probabilities that are smaller than trim in any - denominator of the potential outcomes are dropped. - - order : integer, default=1 - If set to an integer larger than 1, then polynomials of that - order and interactions using the power series) rather than the - original control variables are used in the estimation of any - conditional probability or conditional mean outcome. - Polynomials/interactions are created using the Generate. - Powers command of the LARF package. - """ - - import rpy2.robjects.packages as rpackages - from rpy2.robjects import numpy2ri, pandas2ri - from .utils.utils import _convert_array_to_R - - pandas2ri.activate() - numpy2ri.activate() - - causalweight = rpackages.importr("causalweight") - base = rpackages.importr("base") - - # check input - y, t, m, x = _check_input(y, t, m, x, setting="multidimensional") - - x_r, t_r, m_r, y_r = [ - base.as_matrix(_convert_array_to_R(uu)) for uu in (x, t, m, y) - ] - res = causalweight.medDML(y_r, t_r, m_r, x_r, trim=trim, order=order) - raw_res_R = np.array(res.rx2("results")) - ntrimmed = res.rx2("ntrimmed")[0] - return list(raw_res_R[0, :5]) + [ntrimmed] - - -def mediation_dml( - y, - t, - m, - x, - forest=False, - crossfit=0, - trim=0.05, - clip=1e-6, - normalized=True, - regularization=True, - random_state=None, - calibration=None, -): - """ - Python implementation of Double Machine Learning procedure, as described - in : - Helmut Farbmacher and others, Causal mediation analysis with double - machine learning, - The Econometrics Journal, Volume 25, Issue 2, May 2022, Pages 277–300, - https://doi.org/10.1093/ectj/utac003 - - Parameters - ---------- - - y : array-like, shape (n_samples) - Outcome value for each unit. - - t : array-like, shape (n_samples) - Treatment value for each unit. - - m : array-like, shape (n_samples, n_features_mediator) - Mediator value for each unit, multidimensional or continuous. - - x : array-like, shape (n_samples, n_features_covariates) - Covariates value for each unit, multidimensional or continuous. - - forest : boolean, default=False - Whether to use a random forest model to estimate the propensity - scores instead of logistic regression, and outcome model instead - of linear regression. - - crossfit : int, default=0 - Number of folds for cross-fitting. - - trim : float, default=0.05 - Trimming treshold for discarding observations with extreme probability. - - clip : float, default=1e-6 - limit to clip for numerical stability (min=clip, max=1-clip) - - normalized : boolean, default=True - Normalizes the inverse probability-based weights so they add up to 1, - as described in "Identifying causal mechanisms (primarily) based on - inverse probability weighting", - Huber (2014), https://doi.org/10.1002/jae.2341 - - regularization : boolean, default=True - Whether to use regularized models (logistic or linear regression). - If True, cross-validation is used to chose among 8 potential - log-spaced values between 1e-5 and 1e5. - - random_state : int, default=None - LogisticRegression random state instance. - - calibration : {None, "sigmoid", "isotonic"}, default=None - Whether to add a calibration step for the classifier used to estimate - the treatment propensity score and P(T|M,X). "None" means no - calibration. - Calibration ensures the output of the [predict_proba] - (https://scikit-learn.org/stable/glossary.html#term-predict_proba) - method can be directly interpreted as a confidence level. - Implemented calibration methods are "sigmoid" and "isotonic". - - Returns - ------- - total : float - Average total effect. - direct1 : float - Direct effect on the exposed. - direct0 : float - Direct effect on the unexposed, - indirect1 : float - Indirect effect on the exposed. - indirect0 : float - Indirect effect on the unexposed. - n_discarded : int - Number of discarded samples due to trimming. - - Raises - ------ - ValueError - - If t or y are multidimensional. - - If x, t, m, or y don't have the same length. - """ - # check input - y, t, m, x = _check_input(y, t, m, x, setting="multidimensional") - n = len(y) - - nobs = 0 - - var_name = [ - "p_x", - "p_xm", - "mu_1mx", - "mu_0mx", - "E_mu_t1_t0", - "E_mu_t0_t1", - "E_mu_t1_t1", - "E_mu_t0_t0", - ] - - # estimate propensities - classifier_t_x = _get_classifier(regularization, forest, calibration) - classifier_t_xm = _get_classifier(regularization, forest, calibration) - p_x, p_xm = _estimate_treatment_probabilities( - t, m, x, crossfit, classifier_t_x, classifier_t_xm - ) - - # estimate conditional mean outcomes - regressor_y = _get_regressor(regularization, forest) - regressor_cross_y = _get_regressor(regularization, forest) - - mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 = ( - _estimate_cross_conditional_mean_outcome_nesting( - y, t, m, x, crossfit, regressor_y, regressor_cross_y - ) - ) - - # trimming - not_trimmed = ( - (((1 - p_xm) * p_x) >= trim) - * ((1 - p_x) >= trim) - * (p_x >= trim) - * ((p_xm * (1 - p_x)) >= trim) - ) - for var in var_name: - exec(f"{var} = {var}[not_trimmed]") - nobs = np.sum(not_trimmed) - - # clipping - p_x = np.clip(p_x, clip, 1 - clip) - p_xm = np.clip(p_xm, clip, 1 - clip) - - # score computing - if normalized: - sum_score_m1 = np.mean(t / p_x) - sum_score_m0 = np.mean((1 - t) / (1 - p_x)) - sum_score_t1m0 = np.mean(t * (1 - p_xm) / (p_xm * (1 - p_x))) - sum_score_t0m1 = np.mean((1 - t) * p_xm / ((1 - p_xm) * p_x)) - y1m1 = (t / p_x * (y - E_mu_t1_t1)) / sum_score_m1 + E_mu_t1_t1 - y0m0 = ((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / \ - sum_score_m0 + E_mu_t0_t0 - y1m0 = ( - (t * (1 - p_xm) / (p_xm * (1 - p_x)) * (y - mu_1mx)) / sum_score_t1m0 - + ((1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0)) / sum_score_m0 - + E_mu_t1_t0 - ) - y0m1 = ( - ((1 - t) * p_xm / ((1 - p_xm) * p_x) * (y - mu_0mx)) / sum_score_t0m1 - + (t / p_x * (mu_0mx - E_mu_t0_t1)) / sum_score_m1 - + E_mu_t0_t1 - ) - else: - y1m1 = t / p_x * (y - E_mu_t1_t1) + E_mu_t1_t1 - y0m0 = (1 - t) / (1 - p_x) * (y - E_mu_t0_t0) + E_mu_t0_t0 - y1m0 = ( - t * (1 - p_xm) / (p_xm * (1 - p_x)) * (y - mu_1mx) - + (1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0) - + E_mu_t1_t0 - ) - y0m1 = ( - (1 - t) * p_xm / ((1 - p_xm) * p_x) * (y - mu_0mx) - + t / p_x * (mu_0mx - E_mu_t0_t1) - + E_mu_t0_t1 - ) - - # mean score computing - my1m1 = np.mean(y1m1) - my0m0 = np.mean(y0m0) - my1m0 = np.mean(y1m0) - my0m1 = np.mean(y0m1) - - # effects computing - total = my1m1 - my0m0 - direct1 = my1m1 - my0m1 - direct0 = my1m0 - my0m0 - indirect1 = my1m1 - my1m0 - indirect0 = my0m1 - my0m0 - return total, direct1, direct0, indirect1, indirect0, n - nobs diff --git a/src/med_bench/r_mediation.py b/src/med_bench/r_mediation.py new file mode 100644 index 0000000..1afc8ef --- /dev/null +++ b/src/med_bench/r_mediation.py @@ -0,0 +1,205 @@ +""" +the objective of this script is to implement estimators for mediation in +causal inference, simulate data, and evaluate and compare estimators +""" + +# first step, run r code to have the original implementation by Huber +# using rpy2 to have the same data in R and python... + +import numpy as np +import pandas as pd + +from .utils.utils import r_dependency_required, _check_input + + +@r_dependency_required(["mediation", "stats", "base"]) +def r_mediate(y, t, m, x, interaction=False): + """ + This function calls the R function mediate from the package mediation + (https://cran.r-project.org/package=mediation) + + Parameters + ---------- + y : array-like, shape (n_samples) + outcome value for each unit, continuous + + t : array-like, shape (n_samples) + treatment value for each unit, binary + + m : array-like, shape (n_samples) + mediator value for each unit, here m is necessary binary and + unidimensional + + x : array-like, shape (n_samples, n_features_covariates) + covariates (potential confounders) values + + interaction : boolean, default=False + whether to include interaction terms in the model + interactions are terms XT, TM, MX + """ + + import rpy2.robjects as robjects + import rpy2.robjects.packages as rpackages + from rpy2.robjects import numpy2ri, pandas2ri + + pandas2ri.activate() + numpy2ri.activate() + + mediation = rpackages.importr("mediation") + Rstats = rpackages.importr("stats") + base = rpackages.importr("base") + + # check input + y, t, m, x = _check_input(y, t, m, x, setting="binary") + m = m.ravel() + + var_names = [[y, "y"], [t, "t"], [m, "m"], [x, "x"]] + df_list = list() + for var, name in var_names: + if len(var.shape) > 1: + var_dim = var.shape[1] + col_names = ["{}_{}".format(name, i) for i in range(var_dim)] + sub_df = pd.DataFrame(var, columns=col_names) + else: + sub_df = pd.DataFrame(var, columns=[name]) + df_list.append(sub_df) + df = pd.concat(df_list, axis=1) + m_features = [c for c in df.columns if ("y" not in c) and ("m" not in c)] + y_features = [c for c in df.columns if ("y" not in c)] + if not interaction: + m_formula = "m ~ " + " + ".join(m_features) + y_formula = "y ~ " + " + ".join(y_features) + else: + m_formula = "m ~ " + " + ".join( + m_features + [":".join(p) for p in combinations(m_features, 2)] + ) + y_formula = "y ~ " + " + ".join( + y_features + [":".join(p) for p in combinations(y_features, 2)] + ) + robjects.globalenv["df"] = df + mediator_model = Rstats.lm(m_formula, data=base.as_symbol("df")) + outcome_model = Rstats.lm(y_formula, data=base.as_symbol("df")) + res = mediation.mediate( + mediator_model, outcome_model, treat="t", mediator="m", boot=True, sims=1 + ) + + relevant_variables = ["tau.coef", "z1", "z0", "d1", "d0"] + to_return = [np.array(res.rx2(v))[0] for v in relevant_variables] + return to_return + [None] + + +@r_dependency_required(["plmed", "base"]) +def r_mediation_g_estimator(y, t, m, x): + """ + This function calls the R G-estimator from the package plmed + (https://github.com/ohines/plmed) + """ + + import rpy2.robjects as robjects + import rpy2.robjects.packages as rpackages + from rpy2.robjects import numpy2ri, pandas2ri + + pandas2ri.activate() + numpy2ri.activate() + + plmed = rpackages.importr("plmed") + base = rpackages.importr("base") + + # check input + y, t, m, x = _check_input(y, t, m, x, setting="binary") + m = m.ravel() + + var_names = [[y, "y"], [t, "t"], [m, "m"], [x, "x"]] + df_list = list() + for var, name in var_names: + if len(var.shape) > 1: + var_dim = var.shape[1] + col_names = ["{}_{}".format(name, i) for i in range(var_dim)] + sub_df = pd.DataFrame(var, columns=col_names) + else: + sub_df = pd.DataFrame(var, columns=[name]) + df_list.append(sub_df) + df = pd.concat(df_list, axis=1) + m_features = [c for c in df.columns if ("x" in c)] + y_features = [c for c in df.columns if ("x" in c)] + t_features = [c for c in df.columns if ("x" in c)] + m_formula = "m ~ " + " + ".join(m_features) + y_formula = "y ~ " + " + ".join(y_features) + t_formula = "t ~ " + " + ".join(t_features) + robjects.globalenv["df"] = df + res = plmed.G_estimation( + t_formula, + m_formula, + y_formula, + exposure_family="binomial", + data=base.as_symbol("df"), + ) + direct_effect = res.rx2("coef")[0] + indirect_effect = res.rx2("coef")[1] + return ( + direct_effect + indirect_effect, + direct_effect, + direct_effect, + indirect_effect, + indirect_effect, + None, + ) + + +@r_dependency_required(["causalweight", "base"]) +def r_mediation_dml(y, t, m, x, trim=0.05, order=1): + """ + This function calls the R Double Machine Learning estimator from the + package causalweight (https://cran.r-project.org/web/packages/causalweight) + + Parameters + ---------- + y : array-like, shape (n_samples) + outcome value for each unit, continuous + + t : array-like, shape (n_samples) + treatment value for each unit, binary + + m : array-like, shape (n_samples, n_features_mediator) + mediator value for each unit, can be continuous or binary, and + multi-dimensional + + x : array-like, shape (n_samples, n_features_covariates) + covariates (potential confounders) values + + trim : float, default=0.05 + Trimming rule for discarding observations with extreme + conditional treatment or mediator probabilities + (or products thereof). Observations with (products of) + conditional probabilities that are smaller than trim in any + denominator of the potential outcomes are dropped. + + order : integer, default=1 + If set to an integer larger than 1, then polynomials of that + order and interactions using the power series) rather than the + original control variables are used in the estimation of any + conditional probability or conditional mean outcome. + Polynomials/interactions are created using the Generate. + Powers command of the LARF package. + """ + + import rpy2.robjects.packages as rpackages + from rpy2.robjects import numpy2ri, pandas2ri + from .utils.utils import _convert_array_to_R + + pandas2ri.activate() + numpy2ri.activate() + + causalweight = rpackages.importr("causalweight") + base = rpackages.importr("base") + + # check input + y, t, m, x = _check_input(y, t, m, x, setting="multidimensional") + + x_r, t_r, m_r, y_r = [ + base.as_matrix(_convert_array_to_R(uu)) for uu in (x, t, m, y) + ] + res = causalweight.medDML(y_r, t_r, m_r, x_r, trim=trim, order=order) + raw_res_R = np.array(res.rx2("results")) + ntrimmed = res.rx2("ntrimmed")[0] + return list(raw_res_R[0, :5]) + [ntrimmed] diff --git a/src/med_bench/utils/constants.py b/src/med_bench/utils/constants.py index eb11572..706b84b 100644 --- a/src/med_bench/utils/constants.py +++ b/src/med_bench/utils/constants.py @@ -79,7 +79,9 @@ def get_tolerance_array(tolerance_size: str) -> np.array: "mediation_multiply_robust_forest_calibration": LARGE_TOLERANCE, "simulation_based": LARGE_TOLERANCE, "mediation_dml": INFINITE_TOLERANCE, - "mediation_dml_reg_fixed_seed": INFINITE_TOLERANCE, + "mediation_dml_noreg": INFINITE_TOLERANCE, + "mediation_dml_reg": INFINITE_TOLERANCE, + "mediation_dml_forest": INFINITE_TOLERANCE, "mediation_g_estimator": LARGE_TOLERANCE, } diff --git a/src/med_bench/utils/nuisances.py b/src/med_bench/utils/nuisances.py deleted file mode 100644 index bb60e08..0000000 --- a/src/med_bench/utils/nuisances.py +++ /dev/null @@ -1,476 +0,0 @@ -""" -the objective of this script is to implement nuisances functions -used in mediation estimators in causal inference -""" - -import numpy as np -from sklearn.base import clone -from sklearn.calibration import CalibratedClassifierCV -from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor -from sklearn.linear_model import LogisticRegressionCV, RidgeCV -from sklearn.model_selection import KFold - -from .utils import check_r_dependencies, _get_interactions - -if check_r_dependencies(): - pass - - -ALPHAS = np.logspace(-5, 5, 8) -CV_FOLDS = 5 -TINY = 1.0e-12 - - -def _get_train_test_lists(crossfit, n, x): - """ - Obtain train and test folds - - Returns - ------- - train_test_list : list - indexes with train and test indexes - """ - if crossfit < 2: - train_test_list = [[np.arange(n), np.arange(n)]] - else: - kf = KFold(n_splits=crossfit) - train_test_list = list() - for train_index, test_index in kf.split(x): - train_test_list.append([train_index, test_index]) - return train_test_list - - -def _get_regularization_parameters(regularization): - """ - Obtain regularization parameters - - Returns - ------- - cs : list - each of the values in Cs describes the inverse of regularization - strength for predictors - alphas : list - alpha values to try in ridge models - """ - if regularization: - alphas = ALPHAS - cs = ALPHAS - else: - alphas = [TINY] - cs = [np.inf] - - return cs, alphas - - -def _get_classifier(regularization, forest, calibration, random_state=42): - """ - Obtain context classifiers to estimate treatment probabilities. - - Returns - ------- - clf : classifier on contexts, etc. for predicting P(T=1|X), - P(T=1|X, M) or f(M|T,X) - """ - cs, _ = _get_regularization_parameters(regularization) - - if not forest: - clf = LogisticRegressionCV(random_state=random_state, Cs=cs, cv=CV_FOLDS) - else: - clf = RandomForestClassifier( - random_state=random_state, n_estimators=100, min_samples_leaf=10 - ) - if calibration in {"sigmoid", "isotonic"}: - clf = CalibratedClassifierCV(clf, method=calibration) - - return clf - - -def _get_regressor(regularization, forest, random_state=42): - """ - Obtain regressors to estimate conditional mean outcomes. - - Returns - ------- - reg : regressor on contexts, etc. for predicting E[Y|T,M,X], etc. - """ - _, alphas = _get_regularization_parameters(regularization) - - if not forest: - reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) - else: - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=random_state - ) - - return reg - - -def _estimate_treatment_probabilities(t, m, x, crossfit, clf_t_x, clf_t_xm): - """ - Estimate treatment probabilities P(T=1|X) and P(T=1|X, M) with train - test lists from crossfitting - - Returns - ------- - p_x : array-like, shape (n_samples) - probabilities P(T=1|X) - p_xm : array-like, shape (n_samples) - probabilities P(T=1|X, M) - """ - n = len(t) - - p_x, p_xm = [np.zeros(n) for h in range(2)] - # compute propensity scores - if len(t.shape) == 1: - t = t.reshape(-1, 1) - - train_test_list = _get_train_test_lists(crossfit, n, x) - - xm = np.hstack((x, m)) - - for train_index, test_index in train_test_list: - - # p_x, p_xm model fitting - clf_t_x = clf_t_x.fit(x[train_index, :], t[train_index]) - clf_t_xm = clf_t_xm.fit(xm[train_index, :], t[train_index]) - - # predict P(T=1|X), P(T=1|X, M) - p_x[test_index] = clf_t_x.predict_proba(x[test_index, :])[:, 1] - p_xm[test_index] = clf_t_xm.predict_proba(xm[test_index, :])[:, 1] - - return p_x, p_xm - - -def _estimate_mediator_density(y, t, m, x, crossfit, clf_m, interaction): - """ - Estimate mediator density f(M|T,X) - with train test lists from crossfitting - - Returns - ------- - f_00x: array-like, shape (n_samples) - probabilities f(M=0|T=0,X) - f_01x, array-like, shape (n_samples) - probabilities f(M=0|T=1,X) - f_10x, array-like, shape (n_samples) - probabilities f(M=1|T=0,X) - f_11x, array-like, shape (n_samples) - probabilities f(M=1|T=1,X) - f_m0x, array-like, shape (n_samples) - probabilities f(M|T=0,X) - f_m1x, array-like, shape (n_samples) - probabilities f(M|T=1,X) - """ - n = len(y) - - if len(t.shape) == 1: - t = t.reshape(-1, 1) - - t0 = np.zeros((n, 1)) - t1 = np.ones((n, 1)) - - m = m.ravel() - - train_test_list = _get_train_test_lists(crossfit, n, x) - - f_00x, f_01x, f_10x, f_11x, f_m0x, f_m1x = [np.zeros(n) for _ in range(6)] - - t_x = _get_interactions(interaction, t, x) - - t0_x = _get_interactions(interaction, t0, x) - t1_x = _get_interactions(interaction, t1, x) - - for train_index, test_index in train_test_list: - - test_ind = np.arange(len(test_index)) - - # f_mtx model fitting - clf_m = clf_m.fit(t_x[train_index, :], m[train_index]) - - # predict f(M=m|T=t,X) - fm_0 = clf_m.predict_proba(t0_x[test_index, :]) - f_00x[test_index] = fm_0[:, 0] - f_01x[test_index] = fm_0[:, 1] - fm_1 = clf_m.predict_proba(t1_x[test_index, :]) - f_10x[test_index] = fm_1[:, 0] - f_11x[test_index] = fm_1[:, 1] - - # predict f(M|T=t,X) - f_m0x[test_index] = fm_0[test_ind, m[test_index].astype(int)] - f_m1x[test_index] = fm_1[test_ind, m[test_index].astype(int)] - - return f_00x, f_01x, f_10x, f_11x, f_m0x, f_m1x - - -def _estimate_conditional_mean_outcome(y, t, m, x, crossfit, reg_y, interaction): - """ - Estimate conditional mean outcome E[Y|T,M,X] - with train test lists from crossfitting - - Returns - ------- - mu_00x: array-like, shape (n_samples) - conditional mean outcome estimates E[Y|T=0,M=0,X] - mu_01x, array-like, shape (n_samples) - conditional mean outcome estimates E[Y|T=0,M=1,X] - mu_10x, array-like, shape (n_samples) - conditional mean outcome estimates E[Y|T=1,M=0,X] - mu_11x, array-like, shape (n_samples) - conditional mean outcome estimates E[Y|T=1,M=1,X] - mu_m0x, array-like, shape (n_samples) - conditional mean outcome estimates E[Y|T=0,M,X] - mu_m1x, array-like, shape (n_samples) - conditional mean outcome estimates E[Y|T=1,M,X] - """ - n = len(y) - mr = np.copy(m) - if len(t.shape) == 1: - t = t.reshape(-1, 1) - - t0 = np.zeros((n, 1)) - t1 = np.ones((n, 1)) - m0 = np.zeros((n, 1)) - m1 = np.ones((n, 1)) - - train_test_list = _get_train_test_lists(crossfit, n, x) - - mu_11x, mu_10x, mu_01x, mu_00x, mu_1mx, mu_0mx = [np.zeros(n) for _ in range(6)] - - x_t_mr = _get_interactions(interaction, x, t, mr) - - x_t1_m1 = _get_interactions(interaction, x, t1, m1) - x_t1_m0 = _get_interactions(interaction, x, t1, m0) - x_t0_m1 = _get_interactions(interaction, x, t0, m1) - x_t0_m0 = _get_interactions(interaction, x, t0, m0) - - x_t1_m = _get_interactions(interaction, x, t1, m) - x_t0_m = _get_interactions(interaction, x, t0, m) - - for train_index, test_index in train_test_list: - - # mu_tm model fitting - reg_y = reg_y.fit(x_t_mr[train_index, :], y[train_index]) - - # predict E[Y|T=t,M=m,X] - mu_00x[test_index] = reg_y.predict(x_t0_m0[test_index, :]) - mu_01x[test_index] = reg_y.predict(x_t0_m1[test_index, :]) - mu_10x[test_index] = reg_y.predict(x_t1_m0[test_index, :]) - mu_11x[test_index] = reg_y.predict(x_t1_m1[test_index, :]) - - # predict E[Y|T=t,M,X] - mu_0mx[test_index] = reg_y.predict(x_t0_m[test_index, :]) - mu_1mx[test_index] = reg_y.predict(x_t1_m[test_index, :]) - - return mu_00x, mu_01x, mu_10x, mu_11x, mu_0mx, mu_1mx - - -def _estimate_cross_conditional_mean_outcome( - y, t, m, x, crossfit, reg_y, reg_cross_y, f, interaction -): - """ - Estimate the conditional mean outcome, - the cross conditional mean outcome - - Returns - ------- - mu_m0x, array-like, shape (n_samples) - conditional mean outcome estimates E[Y|T=0,M,X] - mu_m1x, array-like, shape (n_samples) - conditional mean outcome estimates E[Y|T=1,M,X] - E_mu_t0_t0, array-like, shape (n_samples) - cross conditional mean outcome estimates E[E[Y|T=0,M,X]|T=0,X] - E_mu_t0_t1, array-like, shape (n_samples) - cross conditional mean outcome estimates E[E[Y|T=0,M,X]|T=1,X] - E_mu_t1_t0, array-like, shape (n_samples) - cross conditional mean outcome estimates E[E[Y|T=1,M,X]|T=0,X] - E_mu_t1_t1, array-like, shape (n_samples) - cross conditional mean outcome estimates E[E[Y|T=1,M,X]|T=1,X] - """ - n = len(y) - - # Initialisation - ( - mu_1mx, # E[Y|T=1,M,X] - mu_0mx, # E[Y|T=0,M,X] - mu_11x, # E[Y|T=1,M=1,X] - mu_10x, # E[Y|T=1,M=0,X] - mu_01x, # E[Y|T=0,M=1,X] - mu_00x, # E[Y|T=0,M=0,X] - E_mu_t0_t0, # E[E[Y|T=0,M,X]|T=0,X] - E_mu_t0_t1, # E[E[Y|T=0,M,X]|T=1,X] - E_mu_t1_t0, # E[E[Y|T=1,M,X]|T=0,X] - E_mu_t1_t1, # E[E[Y|T=1,M,X]|T=1,X] - ) = [np.zeros(n) for _ in range(10)] - - t0, m0 = np.zeros((n, 1)), np.zeros((n, 1)) - t1, m1 = np.ones((n, 1)), np.ones((n, 1)) - - train_test_list = _get_train_test_lists(crossfit, n, x) - - x_t_m = _get_interactions(interaction, x, t, m) - x_t1_m = _get_interactions(interaction, x, t1, m) - x_t0_m = _get_interactions(interaction, x, t0, m) - - x_t0_m0 = _get_interactions(interaction, x, t0, m0) - x_t0_m1 = _get_interactions(interaction, x, t0, m1) - x_t1_m0 = _get_interactions(interaction, x, t1, m0) - x_t1_m1 = _get_interactions(interaction, x, t1, m1) - - f_00x, f_01x, f_10x, f_11x = f - - # Cross-fitting loop - for train_index, test_index in train_test_list: - # Index declaration - ind_t0 = t[test_index] == 0 - - # mu_tm model fitting - reg_y = reg_y.fit(x_t_m[train_index, :], y[train_index]) - - # predict E[Y|T=t,M,X] - mu_1mx[test_index] = reg_y.predict(x_t1_m[test_index, :]) - mu_0mx[test_index] = reg_y.predict(x_t0_m[test_index, :]) - - # predict E[Y|T=t,M=m,X] - mu_00x[test_index] = reg_y.predict(x_t0_m0[test_index, :]) - mu_01x[test_index] = reg_y.predict(x_t0_m1[test_index, :]) - mu_11x[test_index] = reg_y.predict(x_t1_m1[test_index, :]) - mu_10x[test_index] = reg_y.predict(x_t1_m0[test_index, :]) - - # E[E[Y|T=1,M=m,X]|T=t,X] model fitting - reg_y_t1m1_t0 = clone(reg_cross_y).fit( - x[test_index, :][ind_t0, :], mu_11x[test_index][ind_t0] - ) - reg_y_t1m0_t0 = clone(reg_cross_y).fit( - x[test_index, :][ind_t0, :], mu_10x[test_index][ind_t0] - ) - reg_y_t1m1_t1 = clone(reg_cross_y).fit( - x[test_index, :][~ind_t0, :], mu_11x[test_index][~ind_t0] - ) - reg_y_t1m0_t1 = clone(reg_cross_y).fit( - x[test_index, :][~ind_t0, :], mu_10x[test_index][~ind_t0] - ) - - # predict E[E[Y|T=1,M=m,X]|T=t,X] - E_mu_t1_t0[test_index] = ( - reg_y_t1m0_t0.predict(x[test_index, :]) * f_00x[test_index] - + reg_y_t1m1_t0.predict(x[test_index, :]) * f_01x[test_index] - ) - E_mu_t1_t1[test_index] = ( - reg_y_t1m0_t1.predict(x[test_index, :]) * f_10x[test_index] - + reg_y_t1m1_t1.predict(x[test_index, :]) * f_11x[test_index] - ) - - # E[E[Y|T=0,M=m,X]|T=t,X] model fitting - reg_y_t0m1_t0 = clone(reg_cross_y).fit( - x[test_index, :][ind_t0, :], mu_01x[test_index][ind_t0] - ) - reg_y_t0m0_t0 = clone(reg_cross_y).fit( - x[test_index, :][ind_t0, :], mu_00x[test_index][ind_t0] - ) - reg_y_t0m1_t1 = clone(reg_cross_y).fit( - x[test_index, :][~ind_t0, :], mu_01x[test_index][~ind_t0] - ) - reg_y_t0m0_t1 = clone(reg_cross_y).fit( - x[test_index, :][~ind_t0, :], mu_00x[test_index][~ind_t0] - ) - - # predict E[E[Y|T=0,M=m,X]|T=t,X] - E_mu_t0_t0[test_index] = ( - reg_y_t0m0_t0.predict(x[test_index, :]) * f_00x[test_index] - + reg_y_t0m1_t0.predict(x[test_index, :]) * f_01x[test_index] - ) - E_mu_t0_t1[test_index] = ( - reg_y_t0m0_t1.predict(x[test_index, :]) * f_10x[test_index] - + reg_y_t0m1_t1.predict(x[test_index, :]) * f_11x[test_index] - ) - - return mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 - - -def _estimate_cross_conditional_mean_outcome_nesting( - y, t, m, x, crossfit, reg_y, reg_cross_y -): - """ - Estimate treatment probabilities and the conditional mean outcome, - cross conditional mean outcome - - Estimate the conditional mean outcome, - the cross conditional mean outcome - - Returns - ------- - mu_m0x, array-like, shape (n_samples) - conditional mean outcome estimates E[Y|T=0,M,X] - mu_m1x, array-like, shape (n_samples) - conditional mean outcome estimates E[Y|T=1,M,X] - mu_0x, array-like, shape (n_samples) - cross conditional mean outcome estimates E[E[Y|T=0,M,X]|T=0,X] - E_mu_t0_t1, array-like, shape (n_samples) - cross conditional mean outcome estimates E[E[Y|T=0,M,X]|T=1,X] - E_mu_t1_t0, array-like, shape (n_samples) - cross conditional mean outcome estimates E[E[Y|T=1,M,X]|T=0,X] - mu_1x, array-like, shape (n_samples) - cross conditional mean outcome estimates E[E[Y|T=1,M,X]|T=1,X] - """ - n = len(y) - - # initialisation - ( - mu_1mx, # E[Y|T=1,M,X] - mu_1mx_nested, # E[Y|T=1,M,X] predicted on train_nested set - mu_0mx, # E[Y|T=0,M,X] - mu_0mx_nested, # E[Y|T=0,M,X] predicted on train_nested set - E_mu_t1_t0, # E[E[Y|T=1,M,X]|T=0,X] - E_mu_t0_t1, # E[E[Y|T=0,M,X]|T=1,X] - mu_1x, # E[Y|T=1,X] - mu_0x, # E[Y|T=0,X] - ) = [np.zeros(n) for _ in range(8)] - - xm = np.hstack((x, m)) - - train_test_list = _get_train_test_lists(crossfit, n, x) - - for train, test in train_test_list: - # define test set - train1 = train[t[train] == 1] - train0 = train[t[train] == 0] - - train_mean, train_nested = np.array_split(train, 2) - train_mean1 = train_mean[t[train_mean] == 1] - train_mean0 = train_mean[t[train_mean] == 0] - train_nested1 = train_nested[t[train_nested] == 1] - train_nested0 = train_nested[t[train_nested] == 0] - - # predict E[Y|T=1,M,X] - reg_y1m = clone(reg_y) - reg_y1m.fit(xm[train_mean1], y[train_mean1]) - mu_1mx[test] = reg_y1m.predict(xm[test]) - mu_1mx_nested[train_nested] = reg_y1m.predict(xm[train_nested]) - - # predict E[Y|T=0,M,X] - reg_y0m = clone(reg_y) - reg_y0m.fit(xm[train_mean0], y[train_mean0]) - mu_0mx[test] = reg_y0m.predict(xm[test]) - mu_0mx_nested[train_nested] = reg_y0m.predict(xm[train_nested]) - - # predict E[E[Y|T=1,M,X]|T=0,X] - reg_cross_y1 = clone(reg_cross_y) - reg_cross_y1.fit(x[train_nested0], mu_1mx_nested[train_nested0]) - E_mu_t1_t0[test] = reg_cross_y1.predict(x[test]) - - # predict E[E[Y|T=0,M,X]|T=1,X] - reg_cross_y0 = clone(reg_cross_y) - reg_cross_y0.fit(x[train_nested1], mu_0mx_nested[train_nested1]) - E_mu_t0_t1[test] = reg_cross_y0.predict(x[test]) - - # predict E[Y|T=1,X] - reg_y1 = clone(reg_y) - reg_y1.fit(x[train1], y[train1]) - mu_1x[test] = reg_y1.predict(x[test]) - - # predict E[Y|T=0,X] - reg_y0 = clone(reg_y) - reg_y0.fit(x[train0], y[train0]) - mu_0x[test] = reg_y0.predict(x[test]) - - return mu_0mx, mu_1mx, mu_0x, E_mu_t0_t1, E_mu_t1_t0, mu_1x diff --git a/src/med_bench/utils/utils.py b/src/med_bench/utils/utils.py index 017f145..2310c2d 100644 --- a/src/med_bench/utils/utils.py +++ b/src/med_bench/utils/utils.py @@ -1,12 +1,9 @@ +from numpy.random import default_rng import numpy as np import pandas as pd - -from sklearn.cluster import KMeans -from sklearn.model_selection import train_test_split -from sklearn.model_selection import KFold - import subprocess +from med_bench.get_simulated_data import simulate_data from med_bench.utils.constants import ALPHAS, TINY @@ -258,6 +255,12 @@ def is_array_integer(array): return all(list((array == array.astype(int)).squeeze())) +def is_array_binary(array): + if len(np.unique(array)) == 2: + return True + return False + + def _get_regularization_parameters(regularization): """ Obtain regularization parameters From b344910d1c4c3b3bfd455cb55a8958a893a94b62 Mon Sep 17 00:00:00 2001 From: brash6 Date: Thu, 14 Nov 2024 15:33:17 +0100 Subject: [PATCH 58/84] fix tests --- src/tests/estimation/get_estimation_results.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/estimation/get_estimation_results.py b/src/tests/estimation/get_estimation_results.py index 3c2f1bf..fe98338 100644 --- a/src/tests/estimation/get_estimation_results.py +++ b/src/tests/estimation/get_estimation_results.py @@ -37,7 +37,7 @@ def _transform_outputs(causal_effects): indirect_treated = causal_effects['indirect_effect_treated'] indirect_control = causal_effects['indirect_effect_control'] - return np.array(total, direct_treated, direct_control, indirect_treated, indirect_control, 0) + return [total, direct_treated, direct_control, indirect_treated, indirect_control, 0] def _get_estimation_results(x, t, m, y, estimator, config): From cd93d77149a38322ac30d5f3471f887c7237fd12 Mon Sep 17 00:00:00 2001 From: Bertrand Thirion Date: Fri, 6 Dec 2024 15:55:40 +0100 Subject: [PATCH 59/84] started to remove R dependencies --- README.md | 20 -- setup.py | 1 - src/med_bench/r_mediation.py | 205 ------------------ src/med_bench/utils/constants.py | 9 - src/med_bench/utils/utils.py | 108 --------- .../estimation/get_estimation_results.py | 17 -- src/tests/estimation/test_get_estimation.py | 20 +- 7 files changed, 2 insertions(+), 378 deletions(-) delete mode 100644 src/med_bench/r_mediation.py diff --git a/README.md b/README.md index b95d123..6bba25b 100644 --- a/README.md +++ b/README.md @@ -21,26 +21,6 @@ pip install git+git://github.com/judithabk6/med_bench.git Installation time is a few minutes on a standard personal computer. -Some estimators rely on their R implementation which requires the installation of the corresponding R packages. This can be done using `rpy2` - -````python -import rpy2 -import rpy2.robjects.packages as rpackages -utils = rpackages.importr('utils') -utils.chooseCRANmirror(ind=33) - -utils.install_packages('grf') - -utils.install_packages('causalweight') - -utils.install_packages('mediation') - - -utils.install_packages('devtools') -devtools = rpackages.importr('devtools') -devtools.install_github('ohines/plmed') -plmed = rpackages.importr('plmed') -```` ## Content The `src` folder contains the main module with the implementation of the different estimators, the `script` folder contains the function used to simulate data and run the experiments, and the `results` folder contains all available results and code to reproduce the figures. diff --git a/setup.py b/setup.py index 618e661..b96338e 100644 --- a/setup.py +++ b/setup.py @@ -20,7 +20,6 @@ 'pandas>=1.2.1', 'scikit-learn>=0.22.1', 'numpy>=1.19.2', - 'rpy2>=2.9.4', 'scipy>=1.5.2', 'seaborn>=0.11.1', 'matplotlib>=3.3.2', diff --git a/src/med_bench/r_mediation.py b/src/med_bench/r_mediation.py deleted file mode 100644 index 1afc8ef..0000000 --- a/src/med_bench/r_mediation.py +++ /dev/null @@ -1,205 +0,0 @@ -""" -the objective of this script is to implement estimators for mediation in -causal inference, simulate data, and evaluate and compare estimators -""" - -# first step, run r code to have the original implementation by Huber -# using rpy2 to have the same data in R and python... - -import numpy as np -import pandas as pd - -from .utils.utils import r_dependency_required, _check_input - - -@r_dependency_required(["mediation", "stats", "base"]) -def r_mediate(y, t, m, x, interaction=False): - """ - This function calls the R function mediate from the package mediation - (https://cran.r-project.org/package=mediation) - - Parameters - ---------- - y : array-like, shape (n_samples) - outcome value for each unit, continuous - - t : array-like, shape (n_samples) - treatment value for each unit, binary - - m : array-like, shape (n_samples) - mediator value for each unit, here m is necessary binary and - unidimensional - - x : array-like, shape (n_samples, n_features_covariates) - covariates (potential confounders) values - - interaction : boolean, default=False - whether to include interaction terms in the model - interactions are terms XT, TM, MX - """ - - import rpy2.robjects as robjects - import rpy2.robjects.packages as rpackages - from rpy2.robjects import numpy2ri, pandas2ri - - pandas2ri.activate() - numpy2ri.activate() - - mediation = rpackages.importr("mediation") - Rstats = rpackages.importr("stats") - base = rpackages.importr("base") - - # check input - y, t, m, x = _check_input(y, t, m, x, setting="binary") - m = m.ravel() - - var_names = [[y, "y"], [t, "t"], [m, "m"], [x, "x"]] - df_list = list() - for var, name in var_names: - if len(var.shape) > 1: - var_dim = var.shape[1] - col_names = ["{}_{}".format(name, i) for i in range(var_dim)] - sub_df = pd.DataFrame(var, columns=col_names) - else: - sub_df = pd.DataFrame(var, columns=[name]) - df_list.append(sub_df) - df = pd.concat(df_list, axis=1) - m_features = [c for c in df.columns if ("y" not in c) and ("m" not in c)] - y_features = [c for c in df.columns if ("y" not in c)] - if not interaction: - m_formula = "m ~ " + " + ".join(m_features) - y_formula = "y ~ " + " + ".join(y_features) - else: - m_formula = "m ~ " + " + ".join( - m_features + [":".join(p) for p in combinations(m_features, 2)] - ) - y_formula = "y ~ " + " + ".join( - y_features + [":".join(p) for p in combinations(y_features, 2)] - ) - robjects.globalenv["df"] = df - mediator_model = Rstats.lm(m_formula, data=base.as_symbol("df")) - outcome_model = Rstats.lm(y_formula, data=base.as_symbol("df")) - res = mediation.mediate( - mediator_model, outcome_model, treat="t", mediator="m", boot=True, sims=1 - ) - - relevant_variables = ["tau.coef", "z1", "z0", "d1", "d0"] - to_return = [np.array(res.rx2(v))[0] for v in relevant_variables] - return to_return + [None] - - -@r_dependency_required(["plmed", "base"]) -def r_mediation_g_estimator(y, t, m, x): - """ - This function calls the R G-estimator from the package plmed - (https://github.com/ohines/plmed) - """ - - import rpy2.robjects as robjects - import rpy2.robjects.packages as rpackages - from rpy2.robjects import numpy2ri, pandas2ri - - pandas2ri.activate() - numpy2ri.activate() - - plmed = rpackages.importr("plmed") - base = rpackages.importr("base") - - # check input - y, t, m, x = _check_input(y, t, m, x, setting="binary") - m = m.ravel() - - var_names = [[y, "y"], [t, "t"], [m, "m"], [x, "x"]] - df_list = list() - for var, name in var_names: - if len(var.shape) > 1: - var_dim = var.shape[1] - col_names = ["{}_{}".format(name, i) for i in range(var_dim)] - sub_df = pd.DataFrame(var, columns=col_names) - else: - sub_df = pd.DataFrame(var, columns=[name]) - df_list.append(sub_df) - df = pd.concat(df_list, axis=1) - m_features = [c for c in df.columns if ("x" in c)] - y_features = [c for c in df.columns if ("x" in c)] - t_features = [c for c in df.columns if ("x" in c)] - m_formula = "m ~ " + " + ".join(m_features) - y_formula = "y ~ " + " + ".join(y_features) - t_formula = "t ~ " + " + ".join(t_features) - robjects.globalenv["df"] = df - res = plmed.G_estimation( - t_formula, - m_formula, - y_formula, - exposure_family="binomial", - data=base.as_symbol("df"), - ) - direct_effect = res.rx2("coef")[0] - indirect_effect = res.rx2("coef")[1] - return ( - direct_effect + indirect_effect, - direct_effect, - direct_effect, - indirect_effect, - indirect_effect, - None, - ) - - -@r_dependency_required(["causalweight", "base"]) -def r_mediation_dml(y, t, m, x, trim=0.05, order=1): - """ - This function calls the R Double Machine Learning estimator from the - package causalweight (https://cran.r-project.org/web/packages/causalweight) - - Parameters - ---------- - y : array-like, shape (n_samples) - outcome value for each unit, continuous - - t : array-like, shape (n_samples) - treatment value for each unit, binary - - m : array-like, shape (n_samples, n_features_mediator) - mediator value for each unit, can be continuous or binary, and - multi-dimensional - - x : array-like, shape (n_samples, n_features_covariates) - covariates (potential confounders) values - - trim : float, default=0.05 - Trimming rule for discarding observations with extreme - conditional treatment or mediator probabilities - (or products thereof). Observations with (products of) - conditional probabilities that are smaller than trim in any - denominator of the potential outcomes are dropped. - - order : integer, default=1 - If set to an integer larger than 1, then polynomials of that - order and interactions using the power series) rather than the - original control variables are used in the estimation of any - conditional probability or conditional mean outcome. - Polynomials/interactions are created using the Generate. - Powers command of the LARF package. - """ - - import rpy2.robjects.packages as rpackages - from rpy2.robjects import numpy2ri, pandas2ri - from .utils.utils import _convert_array_to_R - - pandas2ri.activate() - numpy2ri.activate() - - causalweight = rpackages.importr("causalweight") - base = rpackages.importr("base") - - # check input - y, t, m, x = _check_input(y, t, m, x, setting="multidimensional") - - x_r, t_r, m_r, y_r = [ - base.as_matrix(_convert_array_to_R(uu)) for uu in (x, t, m, y) - ] - res = causalweight.medDML(y_r, t_r, m_r, x_r, trim=trim, order=order) - raw_res_R = np.array(res.rx2("results")) - ntrimmed = res.rx2("ntrimmed")[0] - return list(raw_res_R[0, :5]) + [ntrimmed] diff --git a/src/med_bench/utils/constants.py b/src/med_bench/utils/constants.py index 706b84b..5b16fe7 100644 --- a/src/med_bench/utils/constants.py +++ b/src/med_bench/utils/constants.py @@ -77,22 +77,13 @@ def get_tolerance_array(tolerance_size: str) -> np.array: "mediation_multiply_robust_reg_calibration": LARGE_TOLERANCE, "mediation_multiply_robust_forest": INFINITE_TOLERANCE, "mediation_multiply_robust_forest_calibration": LARGE_TOLERANCE, - "simulation_based": LARGE_TOLERANCE, - "mediation_dml": INFINITE_TOLERANCE, "mediation_dml_noreg": INFINITE_TOLERANCE, "mediation_dml_reg": INFINITE_TOLERANCE, "mediation_dml_forest": INFINITE_TOLERANCE, - "mediation_g_estimator": LARGE_TOLERANCE, } ESTIMATORS = list(TOLERANCE_DICT.keys()) -R_DEPENDENT_ESTIMATORS = [ - "mediation_IPW_R", - "simulation_based", - "mediation_dml", - "mediation_g_estimator", -] # PARAMETERS VALUES FOR DATA GENERATION diff --git a/src/med_bench/utils/utils.py b/src/med_bench/utils/utils.py index 2310c2d..0f2b16c 100644 --- a/src/med_bench/utils/utils.py +++ b/src/med_bench/utils/utils.py @@ -7,34 +7,6 @@ from med_bench.utils.constants import ALPHAS, TINY -def check_r_dependencies(): - try: - # Check if R is accessible by trying to get its version - subprocess.check_output(["R", "--version"]) - - # If the above command fails, it will raise a subprocess.CalledProcessError and won't reach here - - # Assuming reaching here means R is accessible, now try importing rpy2 packages - import rpy2.robjects.packages as rpackages - - required_packages = [ - "causalweight", - "mediation", - "stats", - "base", - "grf", - "plmed", - ] - - for package in required_packages: - rpackages.importr(package) - - return True # All checks passed, R and required packages are available - - except: - # Handle the case where R is not found or rpy2 is not installed - return False - def _get_interactions(interaction, *args): """ @@ -88,90 +60,10 @@ def _get_interactions(interaction, *args): return result -def is_r_installed(): - try: - subprocess.check_output(["R", "--version"]) - return True - except: - return False - - -def check_r_package(package_name): - try: - import rpy2.robjects.packages as rpackages - - rpackages.importr(package_name) - return True - except: - return False - - class DependencyNotInstalledError(Exception): pass -def r_dependency_required(required_packages): - def decorator(func): - def wrapper(*args, **kwargs): - if not is_r_installed(): - raise DependencyNotInstalledError( - "R is not installed or not found. " - "Please install R and set it up correctly in your system." - ) - - # To get rid of the 'DataFrame' object has no attribute 'iteritems' error due to pandas version mismatch in rpy2 - # https://stackoverflow.com/a/76404841 - pd.DataFrame.iteritems = pd.DataFrame.items - - for package in required_packages: - if not check_r_package(package): - if package != "plmed": - raise DependencyNotInstalledError( - f"The '{package}' R package is not installed. " - "Please install it using R by running:\n" - "import rpy2.robjects.packages as rpackages\n" - "utils = rpackages.importr('utils')\n" - "utils.chooseCRANmirror(ind=33)\n" - f"utils.install_packages('{package}')" - ) - else: - raise DependencyNotInstalledError( - "The 'plmed' R package is not installed. " - "Please install it using R by running:\n" - "import rpy2.robjects.packages as rpackages\n" - "utils = rpackages.importr('utils')\n" - "utils.chooseCRANmirror(ind=33)\n" - "utils.install_packages('devtools')\n" - "devtools = rpackages.importr('devtools')\n" - "devtools.install_github('ohines/plmed')" - ) - return None - return func(*args, **kwargs) - - return wrapper - - return decorator - - -if is_r_installed(): - import rpy2.robjects as robjects - - -def _convert_array_to_R(x): - """ - converts a numpy array to a R matrix or vector - >>> a = np.array([[1, 2, 3], [4, 5, 6]]) - >>> np.sum(a == np.array(_convert_array_to_R(a))) - 6 - """ - if len(x.shape) == 1: - return robjects.FloatVector(x) - elif len(x.shape) == 2: - return robjects.r.matrix( - robjects.FloatVector(x.ravel()), nrow=x.shape[0], byrow="TRUE" - ) - - def _check_input(y, t, m, x, setting): """ internal function to check inputs. `_check_input` adjusts the dimension diff --git a/src/tests/estimation/get_estimation_results.py b/src/tests/estimation/get_estimation_results.py index fe98338..fb8c48b 100644 --- a/src/tests/estimation/get_estimation_results.py +++ b/src/tests/estimation/get_estimation_results.py @@ -3,12 +3,6 @@ import numpy as np -from med_bench.r_mediation import ( - r_mediation_g_estimator, - r_mediation_dml, - r_mediate, -) - from med_bench.estimation.mediation_coefficient_product import CoefficientProduct from med_bench.estimation.mediation_dml import DoubleMachineLearning from med_bench.estimation.mediation_g_computation import GComputation @@ -200,14 +194,6 @@ def _get_regularized_regressor_and_classifier(regularize=True, calibration=None, causal_effects = estimator_obj.estimate(t, m, x, y) effects = _transform_outputs(causal_effects) - elif estimator == "simulation_based": - # R-based function for simulation - effects = r_mediate(y, t, m, x, interaction=False) - - elif estimator == "mediation_dml": - # R-based function for Double Machine Learning with legacy config - effects = r_mediation_dml(y, t, m, x, trim=0.0, order=1) - elif estimator == "mediation_dml_noreg": # Class-based implementation for DoubleMachineLearning without regularization clf, reg = _get_regularized_regressor_and_classifier(regularize=False) @@ -329,9 +315,6 @@ def _get_regularized_regressor_and_classifier(regularize=True, calibration=None, causal_effects = estimator_obj.estimate(t, m, x, y) effects = _transform_outputs(causal_effects) - elif estimator == "mediation_g_estimator": - if config in (0, 1, 2): - effects = r_mediation_g_estimator(y, t, m, x) else: raise ValueError("Unrecognized estimator label.") diff --git a/src/tests/estimation/test_get_estimation.py b/src/tests/estimation/test_get_estimation.py index 1826d81..9411d67 100644 --- a/src/tests/estimation/test_get_estimation.py +++ b/src/tests/estimation/test_get_estimation.py @@ -18,8 +18,8 @@ from tests.estimation.get_estimation_results import _get_estimation_results from med_bench.get_simulated_data import simulate_data -from med_bench.utils.utils import DependencyNotInstalledError, check_r_dependencies -from med_bench.utils.constants import PARAMETER_LIST, PARAMETER_NAME, R_DEPENDENT_ESTIMATORS, TOLERANCE_DICT +from med_bench.utils.utils import DependencyNotInstalledError +from med_bench.utils.constants import PARAMETER_LIST, PARAMETER_NAME, TOLERANCE_DICT current_dir = os.path.dirname(__file__) true_estimations_file_path = os.path.join(current_dir, 'tests_results.npy') @@ -92,14 +92,6 @@ def effects_chap(x, t, m, y, estimator, config): ): pytest.skip(f"{e}") - # We skip the test if an error with function from glmet rpy2 package occurs - elif "glmnet::glmnet" in str(e): - pytest.skip(f"{e}") - - elif estimator in R_DEPENDENT_ESTIMATORS and not check_r_dependencies(): - assert isinstance(e, DependencyNotInstalledError) == True - pytest.skip(f"{e}") - else: pytest.fail(f"{e}") @@ -205,14 +197,6 @@ def effects_chap_true(x_true, t_true, m_true, y_true, estimator_true, config_tru ): pytest.skip(f"{e}") - # We skip the test if an error with function from glmet rpy2 package occurs - elif "glmnet::glmnet" in str(e): - pytest.skip(f"{e}") - - elif estimator in R_DEPENDENT_ESTIMATORS and not check_r_dependencies(): - assert isinstance(e, DependencyNotInstalledError) == True - pytest.skip(f"{e}") - else: pytest.fail(f"{e}") From 6290ddb9aa1428d8b63566f8b1b390f6e9da0533 Mon Sep 17 00:00:00 2001 From: judithabk6 Date: Fri, 6 Dec 2024 17:20:38 +0100 Subject: [PATCH 60/84] rename methods, clean inputs --- src/med_bench/estimation/base.py | 188 +++--------------- .../mediation_coefficient_product.py | 8 +- src/med_bench/estimation/mediation_dml.py | 11 +- .../estimation/mediation_g_computation.py | 52 ++++- src/med_bench/estimation/mediation_ipw.py | 7 +- src/med_bench/estimation/mediation_mr.py | 19 +- src/med_bench/estimation/mediation_tmle.py | 22 +- 7 files changed, 104 insertions(+), 203 deletions(-) diff --git a/src/med_bench/estimation/base.py b/src/med_bench/estimation/base.py index 9df9491..4bfe57a 100644 --- a/src/med_bench/estimation/base.py +++ b/src/med_bench/estimation/base.py @@ -130,68 +130,43 @@ def _resize(self, t, m, x, y): return t, m, x, y - def _input_reshape(self, t, m, x): - """Reshape data for the right shape""" - if len(t.shape) == 1: - t = t.reshape(-1, 1) - if len(m.shape) == 1: - m = m.reshape(-1, 1) - if len(x.shape) == 1: - x = x.reshape(-1, 1) - return t, m, x - - def _fit_treatment_propensity_x_nuisance(self, t, x): + def _fit_treatment_propensity_x(self, t, x): """Fits the nuisance parameter for the propensity P(T=1|X)""" - classifier = clone(self.classifier) - self._classifier_t_x = classifier.fit(x, t) + self._classifier_t_x = clone(self.classifier).fit(x, t) return self - def _fit_treatment_propensity_xm_nuisance(self, t, m, x): + def _fit_treatment_propensity_xm(self, t, m, x): """Fits the nuisance parameter for the propensity P(T=1|X, M)""" xm = np.hstack((x, m)) - self._classifier_t_xm = self.classifier.fit(xm, t) + self._classifier_t_xm = clone(self.classifier).fit(xm, t) return self # TODO : Enable any sklearn object as classifier or regressor - def _fit_mediator_nuisance(self, t, m, x, y): + def _fit_binary_mediator_probability(self, t, m, x): """Fits the nuisance parameter for the density f(M=m|T, X)""" # estimate mediator densities - clf_param_grid = {} - classifier_m = GridSearchCV(self.classifier, clf_param_grid) - t_x = np.hstack([t.reshape(-1, 1), x]) # Fit classifier - self._classifier_m = classifier_m.fit(t_x, m.ravel()) + self._classifier_m = clone(self.classifier).fit(t_x, m.ravel()) return self - def _fit_conditional_mean_outcome_nuisance(self, t, m, x, y): + def _fit_conditional_mean_outcome(self, t, m, x, y): """Fits the nuisance for the conditional mean outcome for the density f(M=m|T, X)""" x_t_m = np.hstack([x, t.reshape(-1, 1), m]) - - reg_param_grid = {} - - # estimate conditional mean outcomes - regressor_y = GridSearchCV(self.regressor, reg_param_grid) - - self._regressor_y = regressor_y.fit(x_t_m, y) + self._regressor_y = clone(self.regressor).fit(x_t_m, y) return self - def _fit_cross_conditional_mean_outcome_nuisance(self, t, m, x, y): + def _fit_cross_conditional_mean_outcome(self, t, m, x, y): """Fits the cross conditional mean outcome E[E[Y|T=t,M,X]|T=t',X]""" xm = np.hstack((x, m)) - reg_param_grid = {} - - # estimate conditional mean outcomes - regressor_y = GridSearchCV(self.regressor, reg_param_grid) - n = t.shape[0] train = np.arange(n) ( @@ -213,115 +188,43 @@ def _fit_cross_conditional_mean_outcome_nuisance(self, t, m, x, y): self.regressors = {} # predict E[Y|T=1,M,X] - self.regressors["y_t1_mx"] = clone(regressor_y) + self.regressors["y_t1_mx"] = clone(self.regressor) self.regressors["y_t1_mx"].fit(xm[train_mean1], y[train_mean1]) mu_1mx_nested[train_nested] = self.regressors["y_t1_mx"].predict( xm[train_nested] ) # predict E[Y|T=0,M,X] - self.regressors["y_t0_mx"] = clone(regressor_y) + self.regressors["y_t0_mx"] = clone(self.regressor) self.regressors["y_t0_mx"].fit(xm[train_mean0], y[train_mean0]) mu_0mx_nested[train_nested] = self.regressors["y_t0_mx"].predict( xm[train_nested] ) # predict E[E[Y|T=1,M,X]|T=0,X] - self.regressors["y_t1_x_t0"] = clone(regressor_y) + self.regressors["y_t1_x_t0"] = clone(self.regressor) self.regressors["y_t1_x_t0"].fit( x[train_nested0], mu_1mx_nested[train_nested0]) # predict E[E[Y|T=0,M,X]|T=1,X] - self.regressors["y_t0_x_t1"] = clone(regressor_y) + self.regressors["y_t0_x_t1"] = clone(self.regressor) self.regressors["y_t0_x_t1"].fit( x[train_nested1], mu_0mx_nested[train_nested1]) # predict E[Y|T=1,X] - self.regressors["y_t1_x"] = clone(regressor_y) + self.regressors["y_t1_x"] = clone(self.regressor) self.regressors["y_t1_x"].fit(x[train1], y[train1]) # predict E[Y|T=0,X] - self.regressors["y_t0_x"] = clone(regressor_y) + self.regressors["y_t0_x"] = clone(self.regressor) self.regressors["y_t0_x"].fit(x[train0], y[train0]) return self - def _fit_cross_conditional_mean_outcome_nuisance_discrete(self, t, m, x, y): - """ - Fits the cross conditional mean outcome E[E[Y|T=t,M,X]|T=t',X] discrete - """ - n = len(y) - - # Initialisation - ( - mu_1mx, # E[Y|T=1,M,X] - mu_0mx, # E[Y|T=0,M,X] - ) = [np.zeros(n) for _ in range(2)] - - t0, m0 = np.zeros((n, 1)), np.zeros((n, 1)) - t1, m1 = np.ones((n, 1)), np.ones((n, 1)) - - x_t_m = np.hstack([x, t.reshape(-1, 1), m]) - x_t1_m = np.hstack([x, t1.reshape(-1, 1), m]) - x_t0_m = np.hstack([x, t0.reshape(-1, 1), m]) - - test_index = np.arange(n) - ind_t0 = t[test_index] == 0 - - reg_param_grid = {} - - # estimate conditional mean outcomes - regressor_y = GridSearchCV(self.regressor, reg_param_grid) - - self.regressors = {} - - # mu_tm model fitting - self.regressors["y_t_mx"] = clone(regressor_y).fit(x_t_m, y) - - # predict E[Y|T=t,M,X] - mu_1mx[test_index] = self.regressors["y_t_mx"].predict( - x_t1_m[test_index, :]) - mu_0mx[test_index] = self.regressors["y_t_mx"].predict( - x_t0_m[test_index, :]) - - for i, b in enumerate(np.unique(m)): - mb = m1 * b - - mu_1bx, mu_0bx = [np.zeros(n) for h in range(2)] - - # predict E[Y|T=t,M=m,X] - - x_t1_mb = np.hstack([x, t1.reshape(-1, 1), mb]) - x_t0_mb = np.hstack([x, t0.reshape(-1, 1), mb]) - - mu_0bx[test_index] = self.regressors["y_t_mx"].predict( - x_t0_mb[test_index, :] - ) - mu_1bx[test_index] = self.regressors["y_t_mx"].predict( - x_t1_mb[test_index, :] - ) - - # E[E[Y|T=1,M=m,X]|T=t,X] model fitting - self.regressors["reg_y_t1m{}_t0".format(i)] = clone(regressor_y).fit( - x[test_index, :][ind_t0, :], mu_1bx[test_index][ind_t0] - ) - self.regressors["reg_y_t1m{}_t1".format(i)] = clone(regressor_y).fit( - x[test_index, :][~ind_t0, :], mu_1bx[test_index][~ind_t0] - ) - - # E[E[Y|T=0,M=m,X]|T=t,X] model fitting - self.regressors["reg_y_t0m{}_t0".format(i)] = clone(regressor_y).fit( - x[test_index, :][ind_t0, :], mu_0bx[test_index][ind_t0] - ) - self.regressors["reg_y_t0m{}_t1".format(i)] = clone(regressor_y).fit( - x[test_index, :][~ind_t0, :], mu_0bx[test_index][~ind_t0] - ) - return self - - def _estimate_mediator_probability(self, t, m, x, y): + def _estimate_binary_mediator_probability(self, x): """ - Estimate mediator density f(M|T,X) + Estimate mediator density P(M=m|T,X) for a binary M Returns ------- @@ -330,7 +233,7 @@ def _estimate_mediator_probability(self, t, m, x, y): f_m1x, array-like, shape (n_samples) probabilities f(M|T=1,X) """ - n = len(y) + n = x.shape[0] t0 = np.zeros((n, 1)) t1 = np.ones((n, 1)) @@ -345,7 +248,7 @@ def _estimate_mediator_probability(self, t, m, x, y): return f_m0x, f_m1x - def _estimate_mediators_probabilities(self, t, m, x, y): + def _estimate_binary_mediator_probability_table(self, x): """ Estimate mediator density f(M|T,X) @@ -360,7 +263,7 @@ def _estimate_mediators_probabilities(self, t, m, x, y): f_11x, array-like, shape (n_samples) probabilities f(M=1|T=1,X) """ - n = len(y) + n = x.shape[0] t0 = np.zeros((n, 1)) t1 = np.ones((n, 1)) @@ -378,7 +281,7 @@ def _estimate_mediators_probabilities(self, t, m, x, y): return f_00x, f_01x, f_10x, f_11x - def _estimate_treatment_propensity_x(self, t, m, x): + def _estimate_treatment_propensity_x(self, x): """ Estimate treatment propensity P(T=1|X) @@ -387,17 +290,12 @@ def _estimate_treatment_propensity_x(self, t, m, x): p_x : array-like, shape (n_samples) probabilities P(T=1|X) """ - n = len(t) - - # compute propensity scores - t, m, x = self._input_reshape(t, m, x) - # predict P(T=1|X), P(T=1|X, M) p_x = self._classifier_t_x.predict_proba(x)[:, 1] return p_x - def _estimate_treatment_probabilities(self, t, m, x): + def _estimate_treatment_propensity_xm(self, m, x): """ Estimate treatment probabilities P(T=1|X) and P(T=1|X, M) with train @@ -408,52 +306,14 @@ def _estimate_treatment_probabilities(self, t, m, x): p_xm : array-like, shape (n_samples) probabilities P(T=1|X, M) """ - # compute propensity scores - t, m, x = self._input_reshape(t, m, x) - xm = np.hstack((x, m)) # predict P(T=1|X), P(T=1|X, M) - p_x = self._classifier_t_x.predict_proba(x)[:, 1] p_xm = self._classifier_t_xm.predict_proba(xm)[:, 1] - return p_x, p_xm - - def _estimate_conditional_mean_outcome(self, t, m, x, y): - """ - Estimate conditional mean outcome E[Y|T,M,X] - - Returns - ------- - mu_00x: array-like, shape (n_samples) - conditional mean outcome estimates E[Y|T=0,M=0,X] - mu_01x, array-like, shape (n_samples) - conditional mean outcome estimates E[Y|T=0,M=1,X] - mu_10x, array-like, shape (n_samples) - conditional mean outcome estimates E[Y|T=1,M=0,X] - mu_11x, array-like, shape (n_samples) - conditional mean outcome estimates E[Y|T=1,M=1,X] - """ - n = len(y) - - t0 = np.zeros((n, 1)) - t1 = np.ones((n, 1)) - m0 = np.zeros((n, 1)) - m1 = np.ones((n, 1)) - - x_t1_m1 = np.hstack([x, t1.reshape(-1, 1), m1]) - x_t1_m0 = np.hstack([x, t1.reshape(-1, 1), m0]) - x_t0_m1 = np.hstack([x, t0.reshape(-1, 1), m1]) - x_t0_m0 = np.hstack([x, t0.reshape(-1, 1), m0]) - - mu_00x = self._regressor_y.predict(x_t0_m0) - mu_01x = self._regressor_y.predict(x_t0_m1) - mu_10x = self._regressor_y.predict(x_t1_m0) - mu_11x = self._regressor_y.predict(x_t1_m1) - - return mu_00x, mu_01x, mu_10x, mu_11x + return p_xm - def _estimate_cross_conditional_mean_outcome_nesting(self, m, x, y): + def _estimate_cross_conditional_mean_outcome(self, m, x): """ Estimate the conditional mean outcome, the cross conditional mean outcome diff --git a/src/med_bench/estimation/mediation_coefficient_product.py b/src/med_bench/estimation/mediation_coefficient_product.py index 81c39b5..bc40ca0 100644 --- a/src/med_bench/estimation/mediation_coefficient_product.py +++ b/src/med_bench/estimation/mediation_coefficient_product.py @@ -44,13 +44,15 @@ def fit(self, t, m, x, y): alphas = ALPHAS else: alphas = [TINY] - t, m, x = self._input_reshape(t, m, x) + t, m, x, y = self._resize(t, m, x, y) self._coef_t_m = np.zeros(m.shape[1]) for i in range(m.shape[1]): - m_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit(np.hstack((x, t)), m[:, i]) + m_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit( + np.hstack((x, t.reshape(-1, 1))), m[:, i]) self._coef_t_m[i] = m_reg.coef_[-1] - y_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit(np.hstack((x, t, m)), y.ravel()) + y_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit( + np.hstack((x, t.reshape(-1, 1), m)), y) self._coef_y = y_reg.coef_ diff --git a/src/med_bench/estimation/mediation_dml.py b/src/med_bench/estimation/mediation_dml.py index 3f075b3..3235979 100644 --- a/src/med_bench/estimation/mediation_dml.py +++ b/src/med_bench/estimation/mediation_dml.py @@ -38,9 +38,9 @@ def fit(self, t, m, x, y): """Fits nuisance parameters to data""" t, m, x, y = self._resize(t, m, x, y) - self._fit_treatment_propensity_x_nuisance(t, x) - self._fit_treatment_propensity_xm_nuisance(t, m, x) - self._fit_cross_conditional_mean_outcome_nuisance(t, m, x, y) + self._fit_treatment_propensity_x(t, x) + self._fit_treatment_propensity_xm(t, m, x) + self._fit_cross_conditional_mean_outcome(t, m, x, y) self._fitted = True if self.verbose: @@ -50,10 +50,11 @@ def estimate(self, t, m, x, y): """Estimates causal effect on data""" t, m, x, y = self._resize(t, m, x, y) - p_x, p_xm = self._estimate_treatment_probabilities(t, m, x) + p_x = self._estimate_treatment_propensity_x(x) + p_xm = self._estimate_treatment_propensity_xm(m, x) mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 = ( - self._estimate_cross_conditional_mean_outcome_nesting(m, x, y) + self._estimate_cross_conditional_mean_outcome(m, x) ) # score computing diff --git a/src/med_bench/estimation/mediation_g_computation.py b/src/med_bench/estimation/mediation_g_computation.py index abf6f86..4b9d55b 100644 --- a/src/med_bench/estimation/mediation_g_computation.py +++ b/src/med_bench/estimation/mediation_g_computation.py @@ -31,15 +31,49 @@ def __init__(self, regressor, classifier, **kwargs): self.regressor = regressor self.classifier = classifier + def _estimate_conditional_mean_outcome_table(self, x): + """ + Estimate conditional mean outcome E[Y|T,M,X] + + Returns + ------- + mu_00x: array-like, shape (n_samples) + conditional mean outcome estimates E[Y|T=0,M=0,X] + mu_01x, array-like, shape (n_samples) + conditional mean outcome estimates E[Y|T=0,M=1,X] + mu_10x, array-like, shape (n_samples) + conditional mean outcome estimates E[Y|T=1,M=0,X] + mu_11x, array-like, shape (n_samples) + conditional mean outcome estimates E[Y|T=1,M=1,X] + """ + n = x.shape[0] + + t0 = np.zeros((n, 1)) + t1 = np.ones((n, 1)) + m0 = np.zeros((n, 1)) + m1 = np.ones((n, 1)) + + x_t1_m1 = np.hstack([x, t1.reshape(-1, 1), m1]) + x_t1_m0 = np.hstack([x, t1.reshape(-1, 1), m0]) + x_t0_m1 = np.hstack([x, t0.reshape(-1, 1), m1]) + x_t0_m0 = np.hstack([x, t0.reshape(-1, 1), m0]) + + mu_00x = self._regressor_y.predict(x_t0_m0) + mu_01x = self._regressor_y.predict(x_t0_m1) + mu_10x = self._regressor_y.predict(x_t1_m0) + mu_11x = self._regressor_y.predict(x_t1_m1) + + return mu_00x, mu_01x, mu_10x, mu_11x + def fit(self, t, m, x, y): """Fits nuisance parameters to data""" t, m, x, y = self._resize(t, m, x, y) if is_array_binary(m): - self._fit_mediator_nuisance(t, m, x, y) - self._fit_conditional_mean_outcome_nuisance(t, m, x, y) + self._fit_binary_mediator_probability(t, m, x) + self._fit_conditional_mean_outcome(t, m, x, y) else: - self._fit_cross_conditional_mean_outcome_nuisance(t, m, x, y) + self._fit_cross_conditional_mean_outcome(t, m, x, y) self._fitted = True @@ -56,10 +90,10 @@ def estimate(self, t, m, x, y): t, m, x, y = self._resize(t, m, x, y) if is_array_binary(m): - f_00x, f_01x, f_10x, f_11x = self._estimate_mediators_probabilities( - t, m, x, y) - mu_00x, mu_01x, mu_10x, mu_11x = self._estimate_conditional_mean_outcome( - t, m, x, y) + f_00x, f_01x, f_10x, f_11x = \ + self._estimate_binary_mediator_probability_table(x) + mu_00x, mu_01x, mu_10x, mu_11x = \ + self._estimate_conditional_mean_outcome_table(x) direct_effect_i1 = mu_11x - mu_01x direct_effect_i0 = mu_10x - mu_00x @@ -76,8 +110,8 @@ def estimate(self, t, m, x, y): + indirect_effect_i0 * mu_00x).sum() / n total_effect = direct_effect_control + indirect_effect_treated else: - (mu_0mx, mu_1mx, y0m0, y0m1, y1m0, y1m1) = self._estimate_cross_conditional_mean_outcome_nesting( - m, x, y) + (mu_0mx, mu_1mx, y0m0, y0m1, y1m0, y1m1) = \ + self._estimate_cross_conditional_mean_outcome(m, x) # mean score computing eta_t1t1 = np.mean(y1m1) diff --git a/src/med_bench/estimation/mediation_ipw.py b/src/med_bench/estimation/mediation_ipw.py index 6eb7041..e69b824 100644 --- a/src/med_bench/estimation/mediation_ipw.py +++ b/src/med_bench/estimation/mediation_ipw.py @@ -37,8 +37,8 @@ def fit(self, t, m, x, y): t, m, x, y = self._resize(t, m, x, y) - self._fit_treatment_propensity_x_nuisance(t, x) - self._fit_treatment_propensity_xm_nuisance(t, m, x) + self._fit_treatment_propensity_x(t, x) + self._fit_treatment_propensity_xm(t, m, x) self._fitted = True @@ -53,7 +53,8 @@ def estimate(self, t, m, x, y): """ t, m, x, y = self._resize(t, m, x, y) - p_x, p_xm = self._estimate_treatment_probabilities(t, m, x) + p_x = self._estimate_treatment_propensity_x(x) + p_xm = self._estimate_treatment_propensity_xm(m, x) ind = (p_xm > self._trim) & (p_xm < (1 - self._trim)) y, t, p_x, p_xm = y[ind], t[ind], p_x[ind], p_xm[ind] diff --git a/src/med_bench/estimation/mediation_mr.py b/src/med_bench/estimation/mediation_mr.py index 058ebf6..e23f37a 100644 --- a/src/med_bench/estimation/mediation_mr.py +++ b/src/med_bench/estimation/mediation_mr.py @@ -45,12 +45,12 @@ def fit(self, t, m, x, y): t, m, x, y = self._resize(t, m, x, y) if self._ratio == "density" and is_array_integer(m): - self._fit_treatment_propensity_x_nuisance(t, x) - self._fit_mediator_nuisance(t, m, x) + self._fit_treatment_propensity_x(t, x) + self._fit_binary_mediator_probability(t, m, x) elif self._ratio == "propensities": - self._fit_treatment_propensity_x_nuisance(t, x) - self._fit_treatment_propensity_xm_nuisance(t, m, x) + self._fit_treatment_propensity_x(t, x) + self._fit_treatment_propensity_xm(t, m, x) elif self._ratio == "density" and not is_array_integer(m): raise NotImplementedError( @@ -58,7 +58,7 @@ def fit(self, t, m, x, y): use a discrete mediator or set the ratio to 'propensities'""" ) - self._fit_cross_conditional_mean_outcome_nuisance(t, m, x, y) + self._fit_cross_conditional_mean_outcome(t, m, x, y) self._fitted = True @@ -74,18 +74,19 @@ def estimate(self, t, m, x, y): t, m, x, y = self._resize(t, m, x, y) if self._ratio == "density": - f_m0x, f_m1x = self._estimate_mediator_probability(t, m, x, y) - p_x = self._estimate_treatment_propensity_x(t, m, x) + f_m0x, f_m1x = self._estimate_binary_mediator_probability(x) + p_x = self._estimate_treatment_propensity_x(x) ratio_t1_m0 = f_m0x / (p_x * f_m1x) ratio_t0_m1 = f_m1x / ((1 - p_x) * f_m0x) elif self._ratio == "propensities": - p_x, p_xm = self._estimate_treatment_probabilities(t, m, x) + p_x = self._estimate_treatment_propensity_x(x) + p_xm = self._estimate_treatment_propensity_xm(m, x) ratio_t1_m0 = (1 - p_xm) / ((1 - p_x) * p_xm) ratio_t0_m1 = p_xm / ((1 - p_xm) * p_x) mu_0mx, mu_1mx, E_mu_t0_t0, E_mu_t0_t1, E_mu_t1_t0, E_mu_t1_t1 = ( - self._estimate_cross_conditional_mean_outcome_nesting(m, x, y) + self._estimate_cross_conditional_mean_outcome(m, x) ) # score computing diff --git a/src/med_bench/estimation/mediation_tmle.py b/src/med_bench/estimation/mediation_tmle.py index 2f02cde..8e59fcc 100644 --- a/src/med_bench/estimation/mediation_tmle.py +++ b/src/med_bench/estimation/mediation_tmle.py @@ -48,12 +48,13 @@ def _one_step_correction_direct(self, t, m, x, y): # estimate mediator densities if self._ratio == "density": - f_m0x, f_m1x = self._estimate_mediator_probability(t, m, x, y) - p_x = self._estimate_treatment_propensity_x(t, m, x) + f_m0x, f_m1x = self._estimate_binary_mediator_probability(x) + p_x = self._estimate_treatment_propensity_x(x) ratio = f_m0x / (p_x * f_m1x) elif self._ratio == "propensities": - p_x, p_xm = self._estimate_treatment_probabilities(t, m, x) + p_x = self._estimate_treatment_propensity_x(x) + p_xm = self._estimate_treatment_propensity_xm(m, x) ratio = (1 - p_xm) / ((1 - p_x) * p_xm) h_corrector = t * ratio - (1 - t) / (1 - p_x) @@ -113,12 +114,13 @@ def _one_step_correction_indirect(self, t, m, x, y): # estimate mediator densities if self._ratio == "density": - f_m0x, f_m1x = self._estimate_mediator_probability(t, m, x, y) - p_x = self._estimate_treatment_propensity_x(t, m, x) + f_m0x, f_m1x = self._estimate_binary_mediator_probability(x) + p_x = self._estimate_treatment_propensity_x(x) ratio = f_m0x / (p_x * f_m1x) elif self._ratio == "propensities": - p_x, p_xm = self._estimate_treatment_probabilities(t, m, x) + p_x = self._estimate_treatment_propensity_x(x) + p_xm = self._estimate_treatment_propensity_xm(m, x) ratio = (1 - p_xm) / ((1 - p_x) * p_xm) h_corrector = t / p_x - t * ratio @@ -174,14 +176,14 @@ def fit(self, t, m, x, y): # bucketize if needed t, m, x, y = self._resize(t, m, x, y) - self._fit_treatment_propensity_x_nuisance(t, x) - self._fit_conditional_mean_outcome_nuisance(t, m, x, y) + self._fit_treatment_propensity_x(t, x) + self._fit_conditional_mean_outcome(t, m, x, y) if self._ratio == "density": - self._fit_mediator_nuisance(t, m, x) + self._fit_binary_mediator_probability(t, m, x) elif self._ratio == "propensities": - self._fit_treatment_propensity_xm_nuisance(t, m, x) + self._fit_treatment_propensity_xm(t, m, x) self._fitted = True From a95e6105490595186c6ffbda24f7e9a4baf6d1bf Mon Sep 17 00:00:00 2001 From: houssamzenati Date: Mon, 9 Dec 2024 16:57:08 +0100 Subject: [PATCH 61/84] tmle testing, exactness tests --- src/med_bench/estimation/base.py | 23 +++----- src/med_bench/estimation/mediation_dml.py | 28 ++++------ .../estimation/mediation_g_computation.py | 51 +++++++++-------- src/med_bench/estimation/mediation_tmle.py | 52 +++++++++--------- src/med_bench/utils/constants.py | 17 +----- src/tests/estimation/tests_results.npy | Bin 362785 -> 360588 bytes 6 files changed, 78 insertions(+), 93 deletions(-) diff --git a/src/med_bench/estimation/base.py b/src/med_bench/estimation/base.py index 9df9491..c46f08f 100644 --- a/src/med_bench/estimation/base.py +++ b/src/med_bench/estimation/base.py @@ -122,8 +122,7 @@ def _resize(self, t, m, x, y): m = m.reshape(n, 1) if n != len(x) or n != len(m) or n != len(t): - raise ValueError( - "Inputs don't have the same number of observations") + raise ValueError("Inputs don't have the same number of observations") y = y.ravel() t = t.ravel() @@ -156,7 +155,7 @@ def _fit_treatment_propensity_xm_nuisance(self, t, m, x): return self # TODO : Enable any sklearn object as classifier or regressor - def _fit_mediator_nuisance(self, t, m, x, y): + def _fit_mediator_nuisance(self, t, m, x): """Fits the nuisance parameter for the density f(M=m|T, X)""" # estimate mediator densities clf_param_grid = {} @@ -228,13 +227,11 @@ def _fit_cross_conditional_mean_outcome_nuisance(self, t, m, x, y): # predict E[E[Y|T=1,M,X]|T=0,X] self.regressors["y_t1_x_t0"] = clone(regressor_y) - self.regressors["y_t1_x_t0"].fit( - x[train_nested0], mu_1mx_nested[train_nested0]) + self.regressors["y_t1_x_t0"].fit(x[train_nested0], mu_1mx_nested[train_nested0]) # predict E[E[Y|T=0,M,X]|T=1,X] self.regressors["y_t0_x_t1"] = clone(regressor_y) - self.regressors["y_t0_x_t1"].fit( - x[train_nested1], mu_0mx_nested[train_nested1]) + self.regressors["y_t0_x_t1"].fit(x[train_nested1], mu_0mx_nested[train_nested1]) # predict E[Y|T=1,X] self.regressors["y_t1_x"] = clone(regressor_y) @@ -279,10 +276,8 @@ def _fit_cross_conditional_mean_outcome_nuisance_discrete(self, t, m, x, y): self.regressors["y_t_mx"] = clone(regressor_y).fit(x_t_m, y) # predict E[Y|T=t,M,X] - mu_1mx[test_index] = self.regressors["y_t_mx"].predict( - x_t1_m[test_index, :]) - mu_0mx[test_index] = self.regressors["y_t_mx"].predict( - x_t0_m[test_index, :]) + mu_1mx[test_index] = self.regressors["y_t_mx"].predict(x_t1_m[test_index, :]) + mu_0mx[test_index] = self.regressors["y_t_mx"].predict(x_t0_m[test_index, :]) for i, b in enumerate(np.unique(m)): mb = m1 * b @@ -330,7 +325,7 @@ def _estimate_mediator_probability(self, t, m, x, y): f_m1x, array-like, shape (n_samples) probabilities f(M|T=1,X) """ - n = len(y) + n = x.shape[0] t0 = np.zeros((n, 1)) t1 = np.ones((n, 1)) @@ -340,8 +335,8 @@ def _estimate_mediator_probability(self, t, m, x, y): t0_x = np.hstack([t0.reshape(-1, 1), x]) t1_x = np.hstack([t1.reshape(-1, 1), x]) - f_m0x = self._classifier_m.predict_proba(t0_x)[:, m] - f_m1x = self._classifier_m.predict_proba(t1_x)[:, m] + f_m0x = self._classifier_m.predict_proba(t0_x)[np.arange(m.shape[0]), m] + f_m1x = self._classifier_m.predict_proba(t1_x)[np.arange(m.shape[0]), m] return f_m0x, f_m1x diff --git a/src/med_bench/estimation/mediation_dml.py b/src/med_bench/estimation/mediation_dml.py index 3f075b3..77b1457 100644 --- a/src/med_bench/estimation/mediation_dml.py +++ b/src/med_bench/estimation/mediation_dml.py @@ -4,31 +4,30 @@ class DoubleMachineLearning(Estimator): - """Double Machine Learning estimation method class - """ + """Double Machine Learning estimation method class""" def __init__(self, regressor, classifier, normalized: bool, **kwargs): """Initializes Double Machine Learning estimation method Parameters ---------- - regressor + regressor Regressor used for mu estimation, can be any object with a fit and predict method - classifier + classifier Classifier used for propensity estimation, can be any object with a fit and predict_proba method normalized : bool Whether to normalize the propensity scores """ super().__init__(**kwargs) + assert hasattr(regressor, "fit"), "The model does not have a 'fit' method." assert hasattr( - regressor, 'fit'), "The model does not have a 'fit' method." + regressor, "predict" + ), "The model does not have a 'predict' method." + assert hasattr(classifier, "fit"), "The model does not have a 'fit' method." assert hasattr( - regressor, 'predict'), "The model does not have a 'predict' method." - assert hasattr( - classifier, 'fit'), "The model does not have a 'fit' method." - assert hasattr( - classifier, 'predict_proba'), "The model does not have a 'predict_proba' method." + classifier, "predict_proba" + ), "The model does not have a 'predict_proba' method." self.regressor = regressor self.classifier = classifier @@ -63,17 +62,14 @@ def estimate(self, t, m, x, y): sum_score_t1m0 = np.mean(t * (1 - p_xm) / (p_xm * (1 - p_x))) sum_score_t0m1 = np.mean((1 - t) * p_xm / ((1 - p_xm) * p_x)) y1m1 = (t / p_x * (y - E_mu_t1_t1)) / sum_score_m1 + E_mu_t1_t1 - y0m0 = ((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / \ - sum_score_m0 + E_mu_t0_t0 + y0m0 = ((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / sum_score_m0 + E_mu_t0_t0 y1m0 = ( - (t * (1 - p_xm) / (p_xm * (1 - p_x)) - * (y - mu_1mx)) / sum_score_t1m0 + (t * (1 - p_xm) / (p_xm * (1 - p_x)) * (y - mu_1mx)) / sum_score_t1m0 + ((1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0)) / sum_score_m0 + E_mu_t1_t0 ) y0m1 = ( - ((1 - t) * p_xm / ((1 - p_xm) * p_x) - * (y - mu_0mx)) / sum_score_t0m1 + ((1 - t) * p_xm / ((1 - p_xm) * p_x) * (y - mu_0mx)) / sum_score_t0m1 + (t / p_x * (mu_0mx - E_mu_t0_t1)) / sum_score_m1 + E_mu_t0_t1 ) diff --git a/src/med_bench/estimation/mediation_g_computation.py b/src/med_bench/estimation/mediation_g_computation.py index abf6f86..852061b 100644 --- a/src/med_bench/estimation/mediation_g_computation.py +++ b/src/med_bench/estimation/mediation_g_computation.py @@ -20,14 +20,14 @@ def __init__(self, regressor, classifier, **kwargs): """ super().__init__(**kwargs) + assert hasattr(regressor, "fit"), "The model does not have a 'fit' method." assert hasattr( - regressor, 'fit'), "The model does not have a 'fit' method." + regressor, "predict" + ), "The model does not have a 'predict' method." + assert hasattr(classifier, "fit"), "The model does not have a 'fit' method." assert hasattr( - regressor, 'predict'), "The model does not have a 'predict' method." - assert hasattr( - classifier, 'fit'), "The model does not have a 'fit' method." - assert hasattr( - classifier, 'predict_proba'), "The model does not have a 'predict_proba' method." + classifier, "predict_proba" + ), "The model does not have a 'predict_proba' method." self.regressor = regressor self.classifier = classifier @@ -36,7 +36,7 @@ def fit(self, t, m, x, y): t, m, x, y = self._resize(t, m, x, y) if is_array_binary(m): - self._fit_mediator_nuisance(t, m, x, y) + self._fit_mediator_nuisance(t, m, x) self._fit_conditional_mean_outcome_nuisance(t, m, x, y) else: self._fit_cross_conditional_mean_outcome_nuisance(t, m, x, y) @@ -48,36 +48,41 @@ def fit(self, t, m, x, y): return self - @ fitted + @fitted def estimate(self, t, m, x, y): - """Estimates causal effect on data - - """ + """Estimates causal effect on data""" t, m, x, y = self._resize(t, m, x, y) if is_array_binary(m): f_00x, f_01x, f_10x, f_11x = self._estimate_mediators_probabilities( - t, m, x, y) + t, m, x, y + ) mu_00x, mu_01x, mu_10x, mu_11x = self._estimate_conditional_mean_outcome( - t, m, x, y) + t, m, x, y + ) direct_effect_i1 = mu_11x - mu_01x direct_effect_i0 = mu_10x - mu_00x n = len(y) - direct_effect_treated = (direct_effect_i1 * f_11x - + direct_effect_i0 * f_10x).sum() / n - direct_effect_control = (direct_effect_i1 * f_01x - + direct_effect_i0 * f_00x).sum() / n + direct_effect_treated = ( + direct_effect_i1 * f_11x + direct_effect_i0 * f_10x + ).sum() / n + direct_effect_control = ( + direct_effect_i1 * f_01x + direct_effect_i0 * f_00x + ).sum() / n indirect_effect_i1 = f_11x - f_01x indirect_effect_i0 = f_10x - f_00x - indirect_effect_treated = (indirect_effect_i1 * mu_11x - + indirect_effect_i0 * mu_10x).sum() / n - indirect_effect_control = (indirect_effect_i1 * mu_01x - + indirect_effect_i0 * mu_00x).sum() / n + indirect_effect_treated = ( + indirect_effect_i1 * mu_11x + indirect_effect_i0 * mu_10x + ).sum() / n + indirect_effect_control = ( + indirect_effect_i1 * mu_01x + indirect_effect_i0 * mu_00x + ).sum() / n total_effect = direct_effect_control + indirect_effect_treated else: - (mu_0mx, mu_1mx, y0m0, y0m1, y1m0, y1m1) = self._estimate_cross_conditional_mean_outcome_nesting( - m, x, y) + (mu_0mx, mu_1mx, y0m0, y0m1, y1m0, y1m1) = ( + self._estimate_cross_conditional_mean_outcome_nesting(m, x, y) + ) # mean score computing eta_t1t1 = np.mean(y1m1) diff --git a/src/med_bench/estimation/mediation_tmle.py b/src/med_bench/estimation/mediation_tmle.py index 2f02cde..22df189 100644 --- a/src/med_bench/estimation/mediation_tmle.py +++ b/src/med_bench/estimation/mediation_tmle.py @@ -4,45 +4,46 @@ from med_bench.estimation.base import Estimator from med_bench.utils.decorators import fitted +from med_bench.utils.utils import is_array_binary ALPHA = 10 class TMLE(Estimator): - """Implementation of targeted maximum likelihood estimation method class - """ + """Implementation of targeted maximum likelihood estimation method class""" def __init__(self, regressor, classifier, ratio, **kwargs): """_summary_ Parameters ---------- - regressor + regressor Regressor used for mu estimation, can be any object with a fit and predict method - classifier + classifier Classifier used for propensity estimation, can be any object with a fit and predict_proba method ratio : str Ratio to use for estimation, can be either 'density' or 'propensities' """ super().__init__(**kwargs) + assert hasattr(regressor, "fit"), "The model does not have a 'fit' method." assert hasattr( - regressor, 'fit'), "The model does not have a 'fit' method." + regressor, "predict" + ), "The model does not have a 'predict' method." + assert hasattr(classifier, "fit"), "The model does not have a 'fit' method." assert hasattr( - regressor, 'predict'), "The model does not have a 'predict' method." - assert hasattr( - classifier, 'fit'), "The model does not have a 'fit' method." - assert hasattr( - classifier, 'predict_proba'), "The model does not have a 'predict_proba' method." + classifier, "predict_proba" + ), "The model does not have a 'predict_proba' method." self.regressor = regressor self.classifier = classifier + assert ratio in ["density", "propensities"] self._ratio = ratio def _one_step_correction_direct(self, t, m, x, y): n = t.shape[0] - t, m, x, y = self.resize(t, m, x, y) + t, m, x, y = self._resize(t, m, x, y) t0 = np.zeros((n)) t1 = np.ones((n)) @@ -59,8 +60,7 @@ def _one_step_correction_direct(self, t, m, x, y): h_corrector = t * ratio - (1 - t) / (1 - p_x) x_t_mr = np.hstack( - [var.reshape(-1, 1) if len(var.shape) == - 1 else var for var in [x, t, m]] + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t, m]] ) mu_tmx = self._regressor_y.predict(x_t_mr) reg = LinearRegression(fit_intercept=False).fit( @@ -69,12 +69,10 @@ def _one_step_correction_direct(self, t, m, x, y): epsilon_h = reg.coef_ x_t0_m = np.hstack( - [var.reshape(-1, 1) if len(var.shape) == - 1 else var for var in [x, t0, m]] + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t0, m]] ) x_t1_m = np.hstack( - [var.reshape(-1, 1) if len(var.shape) == - 1 else var for var in [x, t1, m]] + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t1, m]] ) mu_t0_mx = self._regressor_y.predict(x_t0_m) @@ -87,8 +85,7 @@ def _one_step_correction_direct(self, t, m, x, y): regressor_y = self.regressor reg_cross = clone(regressor_y) reg_cross.fit( - x[t == 0], (mu_t1_mx_star[t == 0] - - mu_t0_mx_star[t == 0]).squeeze() + x[t == 0], (mu_t1_mx_star[t == 0] - mu_t0_mx_star[t == 0]).squeeze() ) theta_0 = reg_cross.predict(x) @@ -107,7 +104,7 @@ def _one_step_correction_direct(self, t, m, x, y): def _one_step_correction_indirect(self, t, m, x, y): n = t.shape[0] - t, m, x, y = self.resize(t, m, x, y) + t, m, x, y = self._resize(t, m, x, y) t0 = np.zeros((n)) t1 = np.ones((n)) @@ -124,8 +121,7 @@ def _one_step_correction_indirect(self, t, m, x, y): h_corrector = t / p_x - t * ratio x_t_mr = np.hstack( - [var.reshape(-1, 1) if len(var.shape) == - 1 else var for var in [x, t, m]] + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t, m]] ) mu_tmx = self._regressor_y.predict(x_t_mr) reg = LinearRegression(fit_intercept=False).fit( @@ -134,8 +130,7 @@ def _one_step_correction_indirect(self, t, m, x, y): epsilon_h = reg.coef_ x_t1_m = np.hstack( - [var.reshape(-1, 1) if len(var.shape) == - 1 else var for var in [x, t1, m]] + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t1, m]] ) mu_t1_mx = self._regressor_y.predict(x_t1_m) @@ -174,6 +169,11 @@ def fit(self, t, m, x, y): # bucketize if needed t, m, x, y = self._resize(t, m, x, y) + if (not is_array_binary(m)) and (self._ratio == "density"): + raise ValueError( + "The option mediator 'density' in TMLE is supported only for 1D binary mediator" + ) + self._fit_treatment_propensity_x_nuisance(t, x) self._fit_conditional_mean_outcome_nuisance(t, m, x, y) @@ -196,10 +196,10 @@ def estimate(self, t, m, x, y): theta_0 = self._one_step_correction_direct(t, m, x, y) delta_1 = self._one_step_correction_indirect(t, m, x, y) total_effect = theta_0 + delta_1 - direct_effect_treated = np.copy(theta_0) + direct_effect_treated = theta_0 direct_effect_control = theta_0 indirect_effect_treated = delta_1 - indirect_effect_control = np.copy(delta_1) + indirect_effect_control = delta_1 causal_effects = { "total_effect": total_effect, diff --git a/src/med_bench/utils/constants.py b/src/med_bench/utils/constants.py index 706b84b..0ae90d0 100644 --- a/src/med_bench/utils/constants.py +++ b/src/med_bench/utils/constants.py @@ -62,27 +62,16 @@ def get_tolerance_array(tolerance_size: str) -> np.array: TOLERANCE_DICT = { "coefficient_product": LARGE_TOLERANCE, - "mediation_ipw_noreg": INFINITE_TOLERANCE, "mediation_ipw_reg": INFINITE_TOLERANCE, "mediation_ipw_reg_calibration": INFINITE_TOLERANCE, - "mediation_ipw_forest": INFINITE_TOLERANCE, - "mediation_ipw_forest_calibration": INFINITE_TOLERANCE, - "mediation_g_computation_noreg": LARGE_TOLERANCE, "mediation_g_computation_reg": MEDIUM_TOLERANCE, "mediation_g_computation_reg_calibration": LARGE_TOLERANCE, - "mediation_g_computation_forest": LARGE_TOLERANCE, - "mediation_g_computation_forest_calibration": INFINITE_TOLERANCE, - "mediation_multiply_robust_noreg": INFINITE_TOLERANCE, "mediation_multiply_robust_reg": LARGE_TOLERANCE, "mediation_multiply_robust_reg_calibration": LARGE_TOLERANCE, - "mediation_multiply_robust_forest": INFINITE_TOLERANCE, - "mediation_multiply_robust_forest_calibration": LARGE_TOLERANCE, - "simulation_based": LARGE_TOLERANCE, - "mediation_dml": INFINITE_TOLERANCE, - "mediation_dml_noreg": INFINITE_TOLERANCE, "mediation_dml_reg": INFINITE_TOLERANCE, - "mediation_dml_forest": INFINITE_TOLERANCE, - "mediation_g_estimator": LARGE_TOLERANCE, + "mediation_dml_reg_calibration": INFINITE_TOLERANCE, + "mediation_tmle_propensities": INFINITE_TOLERANCE, + "mediation_tmle_density": INFINITE_TOLERANCE, } ESTIMATORS = list(TOLERANCE_DICT.keys()) diff --git a/src/tests/estimation/tests_results.npy b/src/tests/estimation/tests_results.npy index d04c49c5590dbe2db9ddfc8e442c0e4806db0129..1790bea9583a23ca86c7f4b80dff28e51e9764be 100644 GIT binary patch delta 12520 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 From 2789d6303a1f0edc7766e7000951ddfd3f5d82f6 Mon Sep 17 00:00:00 2001 From: houssamzenati Date: Mon, 9 Dec 2024 16:59:40 +0100 Subject: [PATCH 62/84] tmle testing, exactness tests --- src/med_bench/estimation/mediation_ipw.py | 17 +- src/med_bench/estimation/mediation_mr.py | 24 +- .../estimation/get_estimation_results.py | 256 ++++++++++++------ src/tests/estimation/test_get_estimation.py | 42 +-- 4 files changed, 212 insertions(+), 127 deletions(-) diff --git a/src/med_bench/estimation/mediation_ipw.py b/src/med_bench/estimation/mediation_ipw.py index 6eb7041..d1fefa4 100644 --- a/src/med_bench/estimation/mediation_ipw.py +++ b/src/med_bench/estimation/mediation_ipw.py @@ -5,15 +5,14 @@ class InversePropensityWeighting(Estimator): - """Inverse propensity weighting estimation method class - """ + """Inverse propensity weighting estimation method class""" def __init__(self, classifier, clip: float, trim: float, **kwargs): """Initializes Inverse propensity weighting estimation method Parameters ---------- - classifier + classifier Classifier used for propensity estimation, can be any object with a fit and predict_proba method clips : float Clipping value for propensity scores @@ -22,18 +21,17 @@ def __init__(self, classifier, clip: float, trim: float, **kwargs): """ super().__init__(**kwargs) + assert hasattr(classifier, "fit"), "The model does not have a 'fit' method." assert hasattr( - classifier, 'fit'), "The model does not have a 'fit' method." - assert hasattr( - classifier, 'predict_proba'), "The model does not have a 'predict_proba' method." + classifier, "predict_proba" + ), "The model does not have a 'predict_proba' method." self.classifier = classifier self._clip = clip self._trim = trim def fit(self, t, m, x, y): - """Fits nuisance parameters to data - """ + """Fits nuisance parameters to data""" t, m, x, y = self._resize(t, m, x, y) @@ -49,8 +47,7 @@ def fit(self, t, m, x, y): @fitted def estimate(self, t, m, x, y): - """Estimates causal effect on data - """ + """Estimates causal effect on data""" t, m, x, y = self._resize(t, m, x, y) p_x, p_xm = self._estimate_treatment_probabilities(t, m, x) diff --git a/src/med_bench/estimation/mediation_mr.py b/src/med_bench/estimation/mediation_mr.py index 058ebf6..6b50d20 100644 --- a/src/med_bench/estimation/mediation_mr.py +++ b/src/med_bench/estimation/mediation_mr.py @@ -6,17 +6,16 @@ class MultiplyRobust(Estimator): - """Iniitializes Multiply Robust estimatation method class - """ + """Iniitializes Multiply Robust estimatation method class""" def __init__(self, regressor, classifier, ratio: str, normalized, **kwargs): """Initializes MulitplyRobust estimatation method Parameters ---------- - regressor + regressor Regressor used for mu estimation, can be any object with a fit and predict method - classifier + classifier Classifier used for propensity estimation, can be any object with a fit and predict_proba method ratio : str Ratio to use for estimation, can be either 'density' or 'propensities' @@ -25,18 +24,18 @@ def __init__(self, regressor, classifier, ratio: str, normalized, **kwargs): """ super().__init__(**kwargs) + assert hasattr(regressor, "fit"), "The model does not have a 'fit' method." assert hasattr( - regressor, 'fit'), "The model does not have a 'fit' method." + regressor, "predict" + ), "The model does not have a 'predict' method." + assert hasattr(classifier, "fit"), "The model does not have a 'fit' method." assert hasattr( - regressor, 'predict'), "The model does not have a 'predict' method." - assert hasattr( - classifier, 'fit'), "The model does not have a 'fit' method." - assert hasattr( - classifier, 'predict_proba'), "The model does not have a 'predict_proba' method." + classifier, "predict_proba" + ), "The model does not have a 'predict_proba' method." self.regressor = regressor self.classifier = classifier - assert ratio in ['density', 'propensities'] + assert ratio in ["density", "propensities"] self._ratio = ratio self._normalized = normalized @@ -96,8 +95,7 @@ def estimate(self, t, m, x, y): sum_score_t0m1 = np.mean((1 - t) * ratio_t0_m1) y1m1 = (t / p_x * (y - E_mu_t1_t1)) / sum_score_m1 + E_mu_t1_t1 - y0m0 = ((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / \ - sum_score_m0 + E_mu_t0_t0 + y0m0 = ((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / sum_score_m0 + E_mu_t0_t0 y1m0 = ( (t * ratio_t1_m0 * (y - mu_1mx)) / sum_score_t1m0 diff --git a/src/tests/estimation/get_estimation_results.py b/src/tests/estimation/get_estimation_results.py index fe98338..6fb81a7 100644 --- a/src/tests/estimation/get_estimation_results.py +++ b/src/tests/estimation/get_estimation_results.py @@ -14,6 +14,7 @@ from med_bench.estimation.mediation_g_computation import GComputation from med_bench.estimation.mediation_ipw import InversePropensityWeighting from med_bench.estimation.mediation_mr import MultiplyRobust +from med_bench.estimation.mediation_tmle import TMLE from med_bench.utils.utils import _get_regularization_parameters from med_bench.utils.constants import CV_FOLDS @@ -31,13 +32,20 @@ def _transform_outputs(causal_effects): Returns: list: list of causal effects """ - total = causal_effects['total_effect'] - direct_treated = causal_effects['direct_effect_treated'] - direct_control = causal_effects['direct_effect_control'] - indirect_treated = causal_effects['indirect_effect_treated'] - indirect_control = causal_effects['indirect_effect_control'] - - return [total, direct_treated, direct_control, indirect_treated, indirect_control, 0] + total = causal_effects["total_effect"] + direct_treated = causal_effects["direct_effect_treated"] + direct_control = causal_effects["direct_effect_control"] + indirect_treated = causal_effects["indirect_effect_treated"] + indirect_control = causal_effects["indirect_effect_control"] + + return [ + total, + direct_treated, + direct_control, + indirect_treated, + indirect_control, + 0, + ] def _get_estimation_results(x, t, m, y, estimator, config): @@ -46,7 +54,9 @@ def _get_estimation_results(x, t, m, y, estimator, config): effects = None # Initialize variable to store the effects # Helper function for regularized regressor and classifier initialization - def _get_regularized_regressor_and_classifier(regularize=True, calibration=None, method="sigmoid"): + def _get_regularized_regressor_and_classifier( + regularize=True, calibration=None, method="sigmoid" + ): cs, alphas = _get_regularization_parameters(regularization=regularize) clf = LogisticRegressionCV(random_state=42, Cs=cs, cv=CV_FOLDS) reg = RidgeCV(alphas=alphas, cv=CV_FOLDS) @@ -73,8 +83,7 @@ def _get_regularized_regressor_and_classifier(regularize=True, calibration=None, elif estimator == "mediation_ipw_noreg": # Class-based implementation for InversePropensityWeighting without regularization clf, reg = _get_regularized_regressor_and_classifier(regularize=False) - estimator_obj = InversePropensityWeighting( - clip=1e-6, trim=0, classifier=clf) + estimator_obj = InversePropensityWeighting(clip=1e-6, trim=0, classifier=clf) estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) effects = _transform_outputs(causal_effects) @@ -82,8 +91,7 @@ def _get_regularized_regressor_and_classifier(regularize=True, calibration=None, elif estimator == "mediation_ipw_reg": # Class-based implementation with regularization clf, reg = _get_regularized_regressor_and_classifier(regularize=True) - estimator_obj = InversePropensityWeighting( - clip=1e-6, trim=0, classifier=clf) + estimator_obj = InversePropensityWeighting(clip=1e-6, trim=0, classifier=clf) estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) effects = _transform_outputs(causal_effects) @@ -91,9 +99,9 @@ def _get_regularized_regressor_and_classifier(regularize=True, calibration=None, elif estimator == "mediation_ipw_reg_calibration": # Class-based implementation with regularization and calibration (sigmoid) clf, reg = _get_regularized_regressor_and_classifier( - regularize=True, calibration=True, method="sigmoid") - estimator_obj = InversePropensityWeighting( - clip=1e-6, trim=0, classifier=clf) + regularize=True, calibration=True, method="sigmoid" + ) + estimator_obj = InversePropensityWeighting(clip=1e-6, trim=0, classifier=clf) estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) effects = _transform_outputs(causal_effects) @@ -101,9 +109,9 @@ def _get_regularized_regressor_and_classifier(regularize=True, calibration=None, elif estimator == "mediation_ipw_reg_calibration_iso": # Class-based implementation with isotonic calibration clf, reg = _get_regularized_regressor_and_classifier( - regularize=True, calibration=True, method="isotonic") - estimator_obj = InversePropensityWeighting( - clip=1e-6, trim=0, classifier=clf) + regularize=True, calibration=True, method="isotonic" + ) + estimator_obj = InversePropensityWeighting(clip=1e-6, trim=0, classifier=clf) estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) effects = _transform_outputs(causal_effects) @@ -111,11 +119,12 @@ def _get_regularized_regressor_and_classifier(regularize=True, calibration=None, elif estimator == "mediation_ipw_forest": # Class-based implementation with forest models clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) + random_state=42, n_estimators=100, min_samples_leaf=10 + ) reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - estimator_obj = InversePropensityWeighting( - clip=1e-6, trim=0, classifier=clf) + n_estimators=100, min_samples_leaf=10, random_state=42 + ) + estimator_obj = InversePropensityWeighting(clip=1e-6, trim=0, classifier=clf) estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) effects = _transform_outputs(causal_effects) @@ -123,12 +132,15 @@ def _get_regularized_regressor_and_classifier(regularize=True, calibration=None, elif estimator == "mediation_ipw_forest_calibration": # Class-based implementation with forest and calibrated sigmoid clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) + random_state=42, n_estimators=100, min_samples_leaf=10 + ) reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) + n_estimators=100, min_samples_leaf=10, random_state=42 + ) calibrated_clf = CalibratedClassifierCV(clf, method="sigmoid") estimator_obj = InversePropensityWeighting( - clip=1e-6, trim=0, classifier=calibrated_clf) + clip=1e-6, trim=0, classifier=calibrated_clf + ) estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) effects = _transform_outputs(causal_effects) @@ -136,12 +148,15 @@ def _get_regularized_regressor_and_classifier(regularize=True, calibration=None, elif estimator == "mediation_ipw_forest_calibration_iso": # Class-based implementation with isotonic calibration clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) + random_state=42, n_estimators=100, min_samples_leaf=10 + ) reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) + n_estimators=100, min_samples_leaf=10, random_state=42 + ) calibrated_clf = CalibratedClassifierCV(clf, method="isotonic") estimator_obj = InversePropensityWeighting( - clip=1e-6, trim=0, classifier=calibrated_clf) + clip=1e-6, trim=0, classifier=calibrated_clf + ) estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) effects = _transform_outputs(causal_effects) @@ -165,7 +180,8 @@ def _get_regularized_regressor_and_classifier(regularize=True, calibration=None, elif estimator == "mediation_g_computation_reg_calibration": # Class-based implementation with regularization and calibrated sigmoid clf, reg = _get_regularized_regressor_and_classifier( - regularize=True, calibration=True, method="sigmoid") + regularize=True, calibration=True, method="sigmoid" + ) estimator_obj = GComputation(regressor=reg, classifier=clf) estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) @@ -174,7 +190,8 @@ def _get_regularized_regressor_and_classifier(regularize=True, calibration=None, elif estimator == "mediation_g_computation_reg_calibration_iso": # Class-based implementation with isotonic calibration clf, reg = _get_regularized_regressor_and_classifier( - regularize=True, calibration=True, method="isotonic") + regularize=True, calibration=True, method="isotonic" + ) estimator_obj = GComputation(regressor=reg, classifier=clf) estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) @@ -183,36 +200,50 @@ def _get_regularized_regressor_and_classifier(regularize=True, calibration=None, elif estimator == "mediation_g_computation_forest": # Class-based implementation with forest models clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) + random_state=42, n_estimators=100, min_samples_leaf=10 + ) reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) + n_estimators=100, min_samples_leaf=10, random_state=42 + ) estimator_obj = GComputation(regressor=reg, classifier=clf) estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) effects = _transform_outputs(causal_effects) - elif estimator == "mediation_multiply_robust_noreg": - # Class-based implementation for MultiplyRobust without regularization - clf, reg = _get_regularized_regressor_and_classifier(regularize=False) - estimator_obj = MultiplyRobust( - ratio="propensities", normalized=True, regressor=reg, classifier=clf) + # GComputation with forest and sigmoid calibration + elif estimator == "mediation_g_computation_forest_calibration": + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10 + ) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42 + ) + calibrated_clf = CalibratedClassifierCV(clf, method="sigmoid") + estimator_obj = GComputation(regressor=reg, classifier=calibrated_clf) estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) effects = _transform_outputs(causal_effects) - elif estimator == "simulation_based": - # R-based function for simulation - effects = r_mediate(y, t, m, x, interaction=False) - - elif estimator == "mediation_dml": - # R-based function for Double Machine Learning with legacy config - effects = r_mediation_dml(y, t, m, x, trim=0.0, order=1) + # GComputation with forest and isotonic calibration + elif estimator == "mediation_g_computation_forest_calibration_iso": + clf = RandomForestClassifier( + random_state=42, n_estimators=100, min_samples_leaf=10 + ) + reg = RandomForestRegressor( + n_estimators=100, min_samples_leaf=10, random_state=42 + ) + calibrated_clf = CalibratedClassifierCV(clf, method="isotonic") + estimator_obj = GComputation(regressor=reg, classifier=calibrated_clf) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) - elif estimator == "mediation_dml_noreg": - # Class-based implementation for DoubleMachineLearning without regularization + elif estimator == "mediation_multiply_robust_noreg": + # Class-based implementation for MultiplyRobust without regularization clf, reg = _get_regularized_regressor_and_classifier(regularize=False) - estimator_obj = DoubleMachineLearning( - normalized=True, regressor=reg, classifier=clf) + estimator_obj = MultiplyRobust( + ratio="propensities", normalized=True, regressor=reg, classifier=clf + ) estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) effects = _transform_outputs(causal_effects) @@ -221,7 +252,8 @@ def _get_regularized_regressor_and_classifier(regularize=True, calibration=None, elif estimator == "mediation_multiply_robust_reg": clf, reg = _get_regularized_regressor_and_classifier(regularize=True) estimator_obj = MultiplyRobust( - ratio="propensities", normalized=True, regressor=reg, classifier=clf) + ratio="propensities", normalized=True, regressor=reg, classifier=clf + ) estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) effects = _transform_outputs(causal_effects) @@ -229,9 +261,11 @@ def _get_regularized_regressor_and_classifier(regularize=True, calibration=None, # Regularized MultiplyRobust with sigmoid calibration elif estimator == "mediation_multiply_robust_reg_calibration": clf, reg = _get_regularized_regressor_and_classifier( - regularize=True, calibration=True, method="sigmoid") + regularize=True, calibration=True, method="sigmoid" + ) estimator_obj = MultiplyRobust( - ratio="propensities", normalized=True, regressor=reg, classifier=clf) + ratio="propensities", normalized=True, regressor=reg, classifier=clf + ) estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) effects = _transform_outputs(causal_effects) @@ -239,21 +273,25 @@ def _get_regularized_regressor_and_classifier(regularize=True, calibration=None, # Regularized MultiplyRobust with isotonic calibration elif estimator == "mediation_multiply_robust_reg_calibration_iso": clf, reg = _get_regularized_regressor_and_classifier( - regularize=True, calibration=True, method="isotonic") + regularize=True, calibration=True, method="isotonic" + ) estimator_obj = MultiplyRobust( - ratio="propensities", normalized=True, regressor=reg, classifier=clf) + ratio="propensities", normalized=True, regressor=reg, classifier=clf + ) estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) effects = _transform_outputs(causal_effects) elif estimator == "mediation_multiply_robust_forest": clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) + random_state=42, n_estimators=100, min_samples_leaf=10 + ) reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) + n_estimators=100, min_samples_leaf=10, random_state=42 + ) estimator = MultiplyRobust( - ratio="propensities", normalized=True, regressor=reg, - classifier=clf) + ratio="propensities", normalized=True, regressor=reg, classifier=clf + ) estimator.fit(t, m, x, y) causal_effects = estimator.estimate(t, m, x, y) effects = _transform_outputs(causal_effects) @@ -261,12 +299,18 @@ def _get_regularized_regressor_and_classifier(regularize=True, calibration=None, # MultiplyRobust with forest and sigmoid calibration elif estimator == "mediation_multiply_robust_forest_calibration": clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) + random_state=42, n_estimators=100, min_samples_leaf=10 + ) reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) + n_estimators=100, min_samples_leaf=10, random_state=42 + ) calibrated_clf = CalibratedClassifierCV(clf, method="sigmoid") estimator_obj = MultiplyRobust( - ratio="propensities", normalized=True, regressor=reg, classifier=calibrated_clf) + ratio="propensities", + normalized=True, + regressor=reg, + classifier=calibrated_clf, + ) estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) effects = _transform_outputs(causal_effects) @@ -274,21 +318,67 @@ def _get_regularized_regressor_and_classifier(regularize=True, calibration=None, # MultiplyRobust with forest and isotonic calibration elif estimator == "mediation_multiply_robust_forest_calibration_iso": clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) + random_state=42, n_estimators=100, min_samples_leaf=10 + ) reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) + n_estimators=100, min_samples_leaf=10, random_state=42 + ) calibrated_clf = CalibratedClassifierCV(clf, method="isotonic") estimator_obj = MultiplyRobust( - ratio="propensities", normalized=True, regressor=reg, classifier=calibrated_clf) + ratio="propensities", + normalized=True, + regressor=reg, + classifier=calibrated_clf, + ) estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) effects = _transform_outputs(causal_effects) + elif estimator == "simulation_based": + # R-based function for simulation + effects = r_mediate(y, t, m, x, interaction=False) + + elif estimator == "mediation_dml": + # R-based function for Double Machine Learning with legacy config + effects = r_mediation_dml(y, t, m, x, trim=0.0, order=1) + + elif estimator == "mediation_dml_noreg": + # Class-based implementation for DoubleMachineLearning without regularization + clf, reg = _get_regularized_regressor_and_classifier(regularize=False) + estimator_obj = DoubleMachineLearning( + normalized=True, regressor=reg, classifier=clf + ) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) # Regularized Double Machine Learning elif estimator == "mediation_dml_reg": clf, reg = _get_regularized_regressor_and_classifier(regularize=True) estimator_obj = DoubleMachineLearning( - normalized=True, regressor=reg, classifier=clf) + normalized=True, regressor=reg, classifier=clf + ) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) + + # Regularized Double Machine Learning + elif estimator == "mediation_dml_reg_calibration": + clf, reg = _get_regularized_regressor_and_classifier(regularize=True) + calibrated_clf = CalibratedClassifierCV(clf, method="sigmoid") + estimator_obj = DoubleMachineLearning( + normalized=True, regressor=reg, classifier=calibrated_clf + ) + estimator_obj.fit(t, m, x, y) + causal_effects = estimator_obj.estimate(t, m, x, y) + effects = _transform_outputs(causal_effects) + + # Regularized Double Machine Learning + elif estimator == "mediation_dml_reg_calibration_iso": + clf, reg = _get_regularized_regressor_and_classifier(regularize=True) + calibrated_clf = CalibratedClassifierCV(clf, method="isotonic") + estimator_obj = DoubleMachineLearning( + normalized=True, regressor=reg, classifier=calibrated_clf + ) estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) effects = _transform_outputs(causal_effects) @@ -296,35 +386,30 @@ def _get_regularized_regressor_and_classifier(regularize=True, calibration=None, # Regularized Double Machine Learning with forest models elif estimator == "mediation_dml_forest": clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) + random_state=42, n_estimators=100, min_samples_leaf=10 + ) reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) + n_estimators=100, min_samples_leaf=10, random_state=42 + ) estimator_obj = DoubleMachineLearning( - normalized=True, regressor=reg, classifier=clf) + normalized=True, regressor=reg, classifier=clf + ) estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) effects = _transform_outputs(causal_effects) - # GComputation with forest and sigmoid calibration - elif estimator == "mediation_g_computation_forest_calibration": - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - calibrated_clf = CalibratedClassifierCV(clf, method="sigmoid") - estimator_obj = GComputation(regressor=reg, classifier=calibrated_clf) + # TMLE - ratio of propensities + elif estimator == "mediation_tmle_propensities": + clf, reg = _get_regularized_regressor_and_classifier(regularize=True) + estimator_obj = TMLE(regressor=reg, classifier=clf, ratio="propensities") estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) effects = _transform_outputs(causal_effects) - # GComputation with forest and isotonic calibration - elif estimator == "mediation_g_computation_forest_calibration_iso": - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42) - calibrated_clf = CalibratedClassifierCV(clf, method="isotonic") - estimator_obj = GComputation(regressor=reg, classifier=calibrated_clf) + # TMLE - ratio of propensities + elif estimator == "mediation_tmle_density": + clf, reg = _get_regularized_regressor_and_classifier(regularize=True) + estimator_obj = TMLE(regressor=reg, classifier=clf, ratio="density") estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) effects = _transform_outputs(causal_effects) @@ -333,10 +418,11 @@ def _get_regularized_regressor_and_classifier(regularize=True, calibration=None, if config in (0, 1, 2): effects = r_mediation_g_estimator(y, t, m, x) else: - raise ValueError("Unrecognized estimator label.") + raise ValueError("Unrecognized estimator label for {}.".format(estimator)) # Catch unsupported estimators and raise an error if effects is None: raise ValueError( - f"Estimation failed for {estimator}. Check inputs or configuration.") + f"Estimation failed for {estimator}. Check inputs or configuration." + ) return effects diff --git a/src/tests/estimation/test_get_estimation.py b/src/tests/estimation/test_get_estimation.py index 1826d81..57486c3 100644 --- a/src/tests/estimation/test_get_estimation.py +++ b/src/tests/estimation/test_get_estimation.py @@ -19,10 +19,15 @@ from tests.estimation.get_estimation_results import _get_estimation_results from med_bench.get_simulated_data import simulate_data from med_bench.utils.utils import DependencyNotInstalledError, check_r_dependencies -from med_bench.utils.constants import PARAMETER_LIST, PARAMETER_NAME, R_DEPENDENT_ESTIMATORS, TOLERANCE_DICT +from med_bench.utils.constants import ( + PARAMETER_LIST, + PARAMETER_NAME, + R_DEPENDENT_ESTIMATORS, + TOLERANCE_DICT, +) current_dir = os.path.dirname(__file__) -true_estimations_file_path = os.path.join(current_dir, 'tests_results.npy') +true_estimations_file_path = os.path.join(current_dir, "tests_results.npy") TRUE_ESTIMATIONS = np.load(true_estimations_file_path, allow_pickle=True) @@ -86,10 +91,7 @@ def effects_chap(x, t, m, y, estimator, config): try: res = _get_estimation_results(x, t, m, y, estimator, config)[0:5] except Exception as e: - if str(e) in ( - "Estimator only supports 1D binary mediator.", - "Estimator does not support 1D binary mediator.", - ): + if "1D binary mediator" in str(e): pytest.skip(f"{e}") # We skip the test if an error with function from glmet rpy2 package occurs @@ -119,19 +121,23 @@ def test_tolerance(effects, effects_chap, tolerance): def test_total_is_direct_plus_indirect(effects_chap): if not np.isnan(effects_chap[1]): - assert effects_chap[0] == pytest.approx( - effects_chap[1] + effects_chap[4]) + assert effects_chap[0] == pytest.approx(effects_chap[1] + effects_chap[4]) if not np.isnan(effects_chap[2]): - assert effects_chap[0] == pytest.approx( - effects_chap[2] + effects_chap[3]) + assert effects_chap[0] == pytest.approx(effects_chap[2] + effects_chap[3]) def test_robustness_to_ravel_format(data_simulated, estimator, config, effects_chap): if "forest" in estimator: pytest.skip("Forest estimator skipped") assert np.all( - _get_estimation_results(data_simulated[0], data_simulated[1], data_simulated[2], - data_simulated[3], estimator, config)[0:5] + _get_estimation_results( + data_simulated[0], + data_simulated[1], + data_simulated[2], + data_simulated[3], + estimator, + config, + )[0:5] == pytest.approx( effects_chap, nan_ok=True ) # effects_chap is obtained with data[1].ravel() and data[3].ravel() @@ -189,8 +195,9 @@ def effects_chap_true(x_true, t_true, m_true, y_true, estimator_true, config_tru # try whether estimator is implemented or not try: - res = _get_estimation_results(x_true, t_true, m_true, - y_true, estimator_true, config_true)[0:5] + res = _get_estimation_results( + x_true, t_true, m_true, y_true, estimator_true, config_true + )[0:5] # NaN situations if np.all(np.isnan(res)): @@ -199,10 +206,7 @@ def effects_chap_true(x_true, t_true, m_true, y_true, estimator_true, config_tru pprint("NaN found") except Exception as e: - if str(e) in ( - "Estimator only supports 1D binary mediator.", - "Estimator does not support 1D binary mediator.", - ): + if "1D binary mediator" in str(e): pytest.skip(f"{e}") # We skip the test if an error with function from glmet rpy2 package occurs @@ -220,4 +224,4 @@ def effects_chap_true(x_true, t_true, m_true, y_true, estimator_true, config_tru def test_estimation_exactness(result_true, effects_chap_true): - assert np.all(effects_chap_true == pytest.approx(result_true, abs=1.e-3)) + assert np.all(effects_chap_true == pytest.approx(result_true, abs=1.0e-3)) From 6cc1b6603a22a1a65ea3ae3924da0616e46765f4 Mon Sep 17 00:00:00 2001 From: houssamzenati Date: Thu, 12 Dec 2024 12:03:57 +0100 Subject: [PATCH 63/84] explanations and docstrings TMLE, line formatting --- .../mediation_coefficient_product.py | 13 ++-- src/med_bench/estimation/mediation_dml.py | 18 +++-- .../estimation/mediation_g_computation.py | 8 +- src/med_bench/estimation/mediation_ipw.py | 4 +- src/med_bench/estimation/mediation_mr.py | 12 ++- src/med_bench/estimation/mediation_tmle.py | 75 +++++++++++++++---- 6 files changed, 100 insertions(+), 30 deletions(-) diff --git a/src/med_bench/estimation/mediation_coefficient_product.py b/src/med_bench/estimation/mediation_coefficient_product.py index bc40ca0..cca56cd 100644 --- a/src/med_bench/estimation/mediation_coefficient_product.py +++ b/src/med_bench/estimation/mediation_coefficient_product.py @@ -7,8 +7,7 @@ class CoefficientProduct(Estimator): - """Coefficient Product estimatation method class - """ + """Coefficient Product estimatation method class""" def __init__(self, regularize: bool, **kwargs): """Initializes Coefficient product estimatation method @@ -49,10 +48,12 @@ def fit(self, t, m, x, y): self._coef_t_m = np.zeros(m.shape[1]) for i in range(m.shape[1]): m_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit( - np.hstack((x, t.reshape(-1, 1))), m[:, i]) + np.hstack((x, t.reshape(-1, 1))), m[:, i] + ) self._coef_t_m[i] = m_reg.coef_[-1] y_reg = RidgeCV(alphas=alphas, cv=CV_FOLDS).fit( - np.hstack((x, t.reshape(-1, 1), m)), y) + np.hstack((x, t.reshape(-1, 1), m)), y + ) self._coef_y = y_reg.coef_ @@ -66,7 +67,9 @@ def estimate(self, t, m, x, y): """Estimates causal effect on data""" direct_effect_treated = self._coef_y[x.shape[1]] direct_effect_control = direct_effect_treated - indirect_effect_treated = sum(self._coef_y[x.shape[1] + 1 :] * self._coef_t_m) + indirect_effect_treated = sum( + self._coef_y[x.shape[1] + 1 :] * self._coef_t_m + ) indirect_effect_control = indirect_effect_treated causal_effects = { diff --git a/src/med_bench/estimation/mediation_dml.py b/src/med_bench/estimation/mediation_dml.py index 7137e39..5ed2ecb 100644 --- a/src/med_bench/estimation/mediation_dml.py +++ b/src/med_bench/estimation/mediation_dml.py @@ -20,11 +20,15 @@ def __init__(self, regressor, classifier, normalized: bool, **kwargs): """ super().__init__(**kwargs) - assert hasattr(regressor, "fit"), "The model does not have a 'fit' method." + assert hasattr( + regressor, "fit" + ), "The model does not have a 'fit' method." assert hasattr( regressor, "predict" ), "The model does not have a 'predict' method." - assert hasattr(classifier, "fit"), "The model does not have a 'fit' method." + assert hasattr( + classifier, "fit" + ), "The model does not have a 'fit' method." assert hasattr( classifier, "predict_proba" ), "The model does not have a 'predict_proba' method." @@ -63,14 +67,18 @@ def estimate(self, t, m, x, y): sum_score_t1m0 = np.mean(t * (1 - p_xm) / (p_xm * (1 - p_x))) sum_score_t0m1 = np.mean((1 - t) * p_xm / ((1 - p_xm) * p_x)) y1m1 = (t / p_x * (y - E_mu_t1_t1)) / sum_score_m1 + E_mu_t1_t1 - y0m0 = ((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / sum_score_m0 + E_mu_t0_t0 + y0m0 = ( + (1 - t) / (1 - p_x) * (y - E_mu_t0_t0) + ) / sum_score_m0 + E_mu_t0_t0 y1m0 = ( - (t * (1 - p_xm) / (p_xm * (1 - p_x)) * (y - mu_1mx)) / sum_score_t1m0 + (t * (1 - p_xm) / (p_xm * (1 - p_x)) * (y - mu_1mx)) + / sum_score_t1m0 + ((1 - t) / (1 - p_x) * (mu_1mx - E_mu_t1_t0)) / sum_score_m0 + E_mu_t1_t0 ) y0m1 = ( - ((1 - t) * p_xm / ((1 - p_xm) * p_x) * (y - mu_0mx)) / sum_score_t0m1 + ((1 - t) * p_xm / ((1 - p_xm) * p_x) * (y - mu_0mx)) + / sum_score_t0m1 + (t / p_x * (mu_0mx - E_mu_t0_t1)) / sum_score_m1 + E_mu_t0_t1 ) diff --git a/src/med_bench/estimation/mediation_g_computation.py b/src/med_bench/estimation/mediation_g_computation.py index 11d4106..5c5085a 100644 --- a/src/med_bench/estimation/mediation_g_computation.py +++ b/src/med_bench/estimation/mediation_g_computation.py @@ -20,11 +20,15 @@ def __init__(self, regressor, classifier, **kwargs): """ super().__init__(**kwargs) - assert hasattr(regressor, "fit"), "The model does not have a 'fit' method." + assert hasattr( + regressor, "fit" + ), "The model does not have a 'fit' method." assert hasattr( regressor, "predict" ), "The model does not have a 'predict' method." - assert hasattr(classifier, "fit"), "The model does not have a 'fit' method." + assert hasattr( + classifier, "fit" + ), "The model does not have a 'fit' method." assert hasattr( classifier, "predict_proba" ), "The model does not have a 'predict_proba' method." diff --git a/src/med_bench/estimation/mediation_ipw.py b/src/med_bench/estimation/mediation_ipw.py index 739d89d..c9ac248 100644 --- a/src/med_bench/estimation/mediation_ipw.py +++ b/src/med_bench/estimation/mediation_ipw.py @@ -21,7 +21,9 @@ def __init__(self, classifier, clip: float, trim: float, **kwargs): """ super().__init__(**kwargs) - assert hasattr(classifier, "fit"), "The model does not have a 'fit' method." + assert hasattr( + classifier, "fit" + ), "The model does not have a 'fit' method." assert hasattr( classifier, "predict_proba" ), "The model does not have a 'predict_proba' method." diff --git a/src/med_bench/estimation/mediation_mr.py b/src/med_bench/estimation/mediation_mr.py index 60d93e8..fd0d07f 100644 --- a/src/med_bench/estimation/mediation_mr.py +++ b/src/med_bench/estimation/mediation_mr.py @@ -24,11 +24,15 @@ def __init__(self, regressor, classifier, ratio: str, normalized, **kwargs): """ super().__init__(**kwargs) - assert hasattr(regressor, "fit"), "The model does not have a 'fit' method." + assert hasattr( + regressor, "fit" + ), "The model does not have a 'fit' method." assert hasattr( regressor, "predict" ), "The model does not have a 'predict' method." - assert hasattr(classifier, "fit"), "The model does not have a 'fit' method." + assert hasattr( + classifier, "fit" + ), "The model does not have a 'fit' method." assert hasattr( classifier, "predict_proba" ), "The model does not have a 'predict_proba' method." @@ -96,7 +100,9 @@ def estimate(self, t, m, x, y): sum_score_t0m1 = np.mean((1 - t) * ratio_t0_m1) y1m1 = (t / p_x * (y - E_mu_t1_t1)) / sum_score_m1 + E_mu_t1_t1 - y0m0 = ((1 - t) / (1 - p_x) * (y - E_mu_t0_t0)) / sum_score_m0 + E_mu_t0_t0 + y0m0 = ( + (1 - t) / (1 - p_x) * (y - E_mu_t0_t0) + ) / sum_score_m0 + E_mu_t0_t0 y1m0 = ( (t * ratio_t1_m0 * (y - mu_1mx)) / sum_score_t1m0 diff --git a/src/med_bench/estimation/mediation_tmle.py b/src/med_bench/estimation/mediation_tmle.py index e28c10c..159720a 100644 --- a/src/med_bench/estimation/mediation_tmle.py +++ b/src/med_bench/estimation/mediation_tmle.py @@ -26,11 +26,15 @@ def __init__(self, regressor, classifier, ratio, **kwargs): """ super().__init__(**kwargs) - assert hasattr(regressor, "fit"), "The model does not have a 'fit' method." + assert hasattr( + regressor, "fit" + ), "The model does not have a 'fit' method." assert hasattr( regressor, "predict" ), "The model does not have a 'predict' method." - assert hasattr(classifier, "fit"), "The model does not have a 'fit' method." + assert hasattr( + classifier, "fit" + ), "The model does not have a 'fit' method." assert hasattr( classifier, "predict_proba" ), "The model does not have a 'predict_proba' method." @@ -41,7 +45,11 @@ def __init__(self, regressor, classifier, ratio, **kwargs): self._ratio = ratio def _one_step_correction_direct(self, t, m, x, y): + """Implements the one step correction for the estimation of the natural + direct effect with the ratio of mediator densities or treatment + propensities. + """ n = t.shape[0] t, m, x, y = self._resize(t, m, x, y) t0 = np.zeros((n)) @@ -58,24 +66,39 @@ def _one_step_correction_direct(self, t, m, x, y): p_xm = self._estimate_treatment_propensity_xm(m, x) ratio = (1 - p_xm) / ((1 - p_x) * p_xm) + # estimation of corrective features for the conditional mean outcome h_corrector = t * ratio - (1 - t) / (1 - p_x) x_t_mr = np.hstack( - [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t, m]] + [ + var.reshape(-1, 1) if len(var.shape) == 1 else var + for var in [x, t, m] + ] ) mu_tmx = self._regressor_y.predict(x_t_mr) + + # regress with OLS the error of conditional mean outcome regressor on + # corrective features reg = LinearRegression(fit_intercept=False).fit( h_corrector.reshape(-1, 1), (y - mu_tmx).squeeze() ) + # corrective coefficient epsilon epsilon_h = reg.coef_ x_t0_m = np.hstack( - [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t0, m]] + [ + var.reshape(-1, 1) if len(var.shape) == 1 else var + for var in [x, t0, m] + ] ) x_t1_m = np.hstack( - [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t1, m]] + [ + var.reshape(-1, 1) if len(var.shape) == 1 else var + for var in [x, t1, m] + ] ) + # one step corrected conditional mean outcomes mu_t0_mx = self._regressor_y.predict(x_t0_m) h_corrector_t0 = t0 * ratio - (1 - t0) / (1 - p_x) mu_t1_mx = self._regressor_y.predict(x_t1_m) @@ -83,13 +106,15 @@ def _one_step_correction_direct(self, t, m, x, y): mu_t0_mx_star = mu_t0_mx + epsilon_h * h_corrector_t0 mu_t1_mx_star = mu_t1_mx + epsilon_h * h_corrector_t1 - regressor_y = self.regressor - reg_cross = clone(regressor_y) + # estimation of natural direct effect + reg_cross = clone(self.regressor) reg_cross.fit( x[t == 0], (mu_t1_mx_star[t == 0] - mu_t0_mx_star[t == 0]).squeeze() ) theta_0 = reg_cross.predict(x) + + # one step correction of the natural direct effect c_corrector = (1 - t) / (1 - p_x) reg = LinearRegression(fit_intercept=False).fit( c_corrector.reshape(-1, 1)[t == 0], @@ -103,7 +128,11 @@ def _one_step_correction_direct(self, t, m, x, y): return theta_0_star def _one_step_correction_indirect(self, t, m, x, y): + """Implements the one step correction for the estimation of the natural + indirect effect with the ratio of mediator densities or treatment + propensities. + """ n = t.shape[0] t, m, x, y = self._resize(t, m, x, y) t0 = np.zeros((n)) @@ -120,32 +149,45 @@ def _one_step_correction_indirect(self, t, m, x, y): p_xm = self._estimate_treatment_propensity_xm(m, x) ratio = (1 - p_xm) / ((1 - p_x) * p_xm) + # estimation of corrective features for the conditional mean outcome h_corrector = t / p_x - t * ratio x_t_mr = np.hstack( - [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t, m]] + [ + var.reshape(-1, 1) if len(var.shape) == 1 else var + for var in [x, t, m] + ] ) mu_tmx = self._regressor_y.predict(x_t_mr) + + # regress with OLS the error of conditional mean outcome regressor on + # corrective features reg = LinearRegression(fit_intercept=False).fit( h_corrector.reshape(-1, 1), (y - mu_tmx).squeeze() ) + + # corrective coefficient epsilon epsilon_h = reg.coef_ x_t1_m = np.hstack( - [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t1, m]] + [ + var.reshape(-1, 1) if len(var.shape) == 1 else var + for var in [x, t1, m] + ] ) + # one step corrected conditional mean outcomes mu_t1_mx = self._regressor_y.predict(x_t1_m) h_corrector_t1 = t1 / p_x - t1 * ratio mu_t1_mx_star = mu_t1_mx + epsilon_h * h_corrector_t1 - regressor_y = self.regressor - - reg_cross = clone(regressor_y) + # cross conditional mean outcome control + reg_cross = clone(self.regressor) reg_cross.fit(x[t == 0], mu_t1_mx_star[t == 0]) omega_t0x = reg_cross.predict(x) - c_corrector_t0 = (2 * t0 - 1) / p_x[:, None] + # one step corrected cross conditional mean outcome for control + c_corrector_t0 = (2 * t0 - 1) / p_x[:, None] reg = LinearRegression(fit_intercept=False).fit( c_corrector_t0[t == 0], (mu_t1_mx_star[t == 0] - omega_t0x[t == 0]).squeeze(), @@ -153,15 +195,20 @@ def _one_step_correction_indirect(self, t, m, x, y): epsilon_c_t0 = reg.coef_ omega_t0x_star = omega_t0x + epsilon_c_t0 * c_corrector_t0 - reg_cross = clone(regressor_y) + # cross conditional mean outcome treated + reg_cross = clone(self.regressor) reg_cross.fit(x[t == 1], y[t == 1]) omega_t1x = reg_cross.predict(x) + + # one step corrected cross conditional mean outcome for treated c_corrector_t1 = (2 * t1 - 1) / p_x[:, None] reg = LinearRegression(fit_intercept=False).fit( c_corrector_t1[t == 1], (y[t == 1] - omega_t1x[t == 1]).squeeze() ) epsilon_c_t1 = reg.coef_ omega_t1x_star = omega_t1x + epsilon_c_t1 * c_corrector_t1 + + # natural indirect effect delta_1 = np.mean(omega_t1x_star - omega_t0x_star) return delta_1 From 13c591f85ebeae3df3c4def33ef9eaba5f30acea Mon Sep 17 00:00:00 2001 From: judithabk6 Date: Thu, 12 Dec 2024 14:59:37 +0100 Subject: [PATCH 64/84] refactor tests (remove old config parameter and have better names for tests to debug, and refactor tolerance to make it useful --- src/med_bench/utils/constants.py | 156 ++++++++++-------- .../estimation/get_estimation_results.py | 2 +- src/tests/estimation/test_get_estimation.py | 47 +++--- 3 files changed, 109 insertions(+), 96 deletions(-) diff --git a/src/med_bench/utils/constants.py b/src/med_bench/utils/constants.py index e604461..8b5ca1d 100644 --- a/src/med_bench/utils/constants.py +++ b/src/med_bench/utils/constants.py @@ -5,76 +5,79 @@ # CONSTANTS USED FOR TESTS # TOLERANCE THRESHOLDS - -TOLERANCE_THRESHOLDS = { - "SMALL": { - "ATE": 0.05, - "DIRECT": 0.05, - "INDIRECT": 0.2, - }, - "MEDIUM": { - "ATE": 0.10, - "DIRECT": 0.10, - "INDIRECT": 0.4, - }, - "LARGE": { - "ATE": 0.15, - "DIRECT": 0.15, - "INDIRECT": 0.9, - }, - "INFINITE": { - "ATE": np.inf, - "DIRECT": np.inf, - "INDIRECT": np.inf, - }, -} - - -def get_tolerance_array(tolerance_size: str) -> np.array: - """Get tolerance array for tolerance tests - - Parameters - ---------- - tolerance_size : str - tolerance size, can be "SMALL", "MEDIUM", "LARGE" or "INFINITE" - - Returns - ------- - np.array - array of size 5 containing the ATE, DIRECT (*2) and INDIRECT (*2) effects tolerance - """ - - return np.array( - [ - TOLERANCE_THRESHOLDS[tolerance_size]["ATE"], - TOLERANCE_THRESHOLDS[tolerance_size]["DIRECT"], - TOLERANCE_THRESHOLDS[tolerance_size]["DIRECT"], - TOLERANCE_THRESHOLDS[tolerance_size]["INDIRECT"], - TOLERANCE_THRESHOLDS[tolerance_size]["INDIRECT"], - ] - ) - - -SMALL_TOLERANCE = get_tolerance_array("SMALL") -MEDIUM_TOLERANCE = get_tolerance_array("MEDIUM") -LARGE_TOLERANCE = get_tolerance_array("LARGE") -INFINITE_TOLERANCE = get_tolerance_array("INFINITE") - -TOLERANCE_DICT = { - "coefficient_product": LARGE_TOLERANCE, - "mediation_ipw_reg": INFINITE_TOLERANCE, - "mediation_ipw_reg_calibration": INFINITE_TOLERANCE, - "mediation_g_computation_reg": MEDIUM_TOLERANCE, - "mediation_g_computation_reg_calibration": LARGE_TOLERANCE, - "mediation_multiply_robust_reg": LARGE_TOLERANCE, - "mediation_multiply_robust_reg_calibration": LARGE_TOLERANCE, - "mediation_dml_reg": INFINITE_TOLERANCE, - "mediation_dml_reg_calibration": INFINITE_TOLERANCE, - "mediation_tmle_propensities": INFINITE_TOLERANCE, - "mediation_tmle_density": INFINITE_TOLERANCE, -} - -ESTIMATORS = list(TOLERANCE_DICT.keys()) +DEFAULT_TOLERANCE = np.array([0.05, 0.05, 0.05, 0.2, 0.2]) + +TOLERANCE_FACTOR_DICT = { + "coefficient_product-M1D_binary_1DX": np.array([1, 1, 1, 4, 4]), + "coefficient_product-M1D_binary_5DX": np.array([1, 1, 1, 3.5, 3.5]), + "coefficient_product-M5D_continuous_1DX": np.array([1, 1, 1, 1.5, 1.5]), + "coefficient_product-M5D_continuous_5DX": np.array([1, 1, 1, 3.5, 3.5]), + "mediation_ipw_reg-M1D_binary_1DX": np.array([6, 1, 1, 100, 100]), + "mediation_ipw_reg-M1D_binary_5DX": np.array([2, 1.2, 1.2, 10, 10]), + "mediation_ipw_reg-M1D_continuous_1DX": np.array([6, 1.2, 1.2, 15, 15]), + "mediation_ipw_reg-M5D_continuous_1DX": np.array([6, 15, 15, 20, 20]), + "mediation_ipw_reg-M5D_continuous_5DX": np.array([2, 5, 5, 10, 10]), + "mediation_ipw_reg_calibration-M1D_binary_1DX": np.array([2, 2, 2, 10, 10]), + "mediation_ipw_reg_calibration-M1D_binary_5DX": np.array([1, 1, 1, 5, 5]), + "mediation_ipw_reg_calibration-M5D_continuous_1DX": np.array([1, 4, 4, 10, 10]), + "mediation_ipw_reg_calibration-M1D_continuous_5DX": np.array([1, 1, 1, 2, 2]), + "mediation_ipw_reg_calibration-M5D_continuous_5DX": np.array([1, 6, 6, 15, 15]), + "mediation_g_computation_reg-M1D_binary_5DX": np.array([2, 2, 2, 3, 3]), + "mediation_g_computation_reg-M1D_continuous_1DX": np.array([1, 1, 1, 1.5, 1.5]), + "mediation_g_computation_reg-M5D_continuous_1DX": np.array([1, 1, 1, 1.5, 1.5]), + "mediation_g_computation_reg-M1D_continuous_5DX": np.array([2, 2, 2, 4, 4]), + "mediation_g_computation_reg-M5D_continuous_5DX": np.array([1, 3, 3, 6, 6]), + "mediation_g_computation_reg_calibration-M1D_binary_1DX": np.array([1, 1, 1, 2, 2]), + "mediation_g_computation_reg_calibration-M1D_binary_5DX": np.array([1, 1, 1, 1.5, 1.5]), + "mediation_g_computation_reg_calibration-M1D_continuous_1DX": np.array([1, 2, 2, 4, 4]), + "mediation_g_computation_reg_calibration-M5D_continuous_1DX": np.array([1, 2, 2, 2.5, 2.5]), + "mediation_g_computation_reg_calibration-M1D_continuous_5DX": np.array([1, 2, 2, 5, 5]), + "mediation_g_computation_reg_calibration-M5D_continuous_5DX": np.array([6, 15, 15, 20, 20]), + "mediation_multiply_robust_reg-M1D_binary_1DX": np.array([1, 1, 1, 2, 2]), + "mediation_multiply_robust_reg-M1D_binary_5DX": np.array([1, 1, 1, 2, 2]), + "mediation_multiply_robust_reg-M1D_continuous_1DX": np.array([1, 1, 1, 2, 2]), + "mediation_multiply_robust_reg-M5D_continuous_1DX": np.array([1, 3, 3, 6, 6]), + "mediation_multiply_robust_reg-M1D_continuous_5DX": np.array([1, 1, 1, 2, 2]), + "mediation_multiply_robust_reg-M5D_continuous_5DX": np.array([1, 2, 2, 4, 4]), + "mediation_multiply_robust_reg_calibration-M1D_binary_1DX": np.array([1, 1, 1, 3, 3]), + "mediation_multiply_robust_reg_calibration-M1D_binary_5DX": np.array([1, 1, 1, 4, 4]), + "mediation_multiply_robust_reg_calibration-M1D_continuous_1DX": np.array([2, 2, 2, 3, 3]), + "mediation_multiply_robust_reg_calibration-M5D_continuous_1DX": np.array([2, 2, 2, 5, 5]), + "mediation_multiply_robust_reg_calibration-M1D_continuous_5DX": np.array([1, 1, 1, 2, 2]), + "mediation_multiply_robust_reg_calibration-M5D_continuous_5DX": np.array([1, 3, 3, 4, 4]), + "mediation_dml_reg-M1D_binary_1DX": np.array([1, 2, 2, 3, 3]), + "mediation_dml_reg-M1D_binary_5DX": np.array([1, 1, 1, 5, 5]), + "mediation_dml_reg-M5D_continuous_1DX": np.array([1, 10, 10, 20, 20]), + "mediation_dml_reg-M5D_continuous_5DX": np.array([1, 3, 3, 5, 5]), + "mediation_dml_reg_calibration-M1D_binary_1DX": np.array([1, 1, 1, 2, 2]), + "mediation_dml_reg_calibration-M1D_continuous_1DX": np.array([1, 1, 1, 2, 2]), + "mediation_dml_reg_calibration-M5D_continuous_1DX": np.array([1, 1, 1, 2, 2]), + "mediation_dml_reg_calibration-M1D_continuous_5DX": np.array([1, 1, 1, 2, 2]), + "mediation_dml_reg_calibration-M5D_continuous_5DX": np.array([1, 3, 3, 6, 6]), + "mediation_tmle_propensities-M1D_binary_1DX": np.array([1, 1, 1, 2, 2]), + "mediation_tmle_propensities-M1D_continuous_1DX": np.array([1, 1, 1, 2, 2]), + "mediation_tmle_propensities-M5D_continuous_1DX": np.array([1, 2, 2, 2, 2]), + "mediation_tmle_propensities-M1D_continuous_5DX": np.array([1, 1, 1, 3, 3]), + "mediation_tmle_propensities-M5D_continuous_5DX": np.array([3, 3, 3, 15, 15]), + "mediation_tmle_density-M1D_binary_1DX": np.array([1, 1, 1, 3, 3]), + "mediation_tmle_density-M1D_binary_5DX": np.array([1, 1, 1, 2, 2]), +} + + + +ESTIMATORS = [ + "coefficient_product", + "mediation_ipw_reg", + "mediation_ipw_reg_calibration", + "mediation_g_computation_reg", + "mediation_g_computation_reg_calibration", + "mediation_multiply_robust_reg", + "mediation_multiply_robust_reg_calibration", + "mediation_dml_reg", + "mediation_dml_reg_calibration", + "mediation_tmle_propensities", + "mediation_tmle_density" +] # PARAMETERS VALUES FOR DATA GENERATION @@ -130,6 +133,19 @@ def get_tolerance_array(tolerance_size: str) -> np.array: ) ) +CONFIGURATION_NAMES = ["M1D_binary_1DX", + "M1D_binary_5DX", + "M1D_continuous_1DX", + "M5D_continuous_1DX", + "M1D_continuous_5DX", + "M5D_continuous_5DX"] + +CONFIG_DICT = {CONFIGURATION_NAMES[i]: + dict(zip(PARAMETER_NAME, PARAMETER_LIST[i])) + for i in range(len(CONFIGURATION_NAMES))} + + + ALPHAS = np.logspace(-5, 5, 8) CV_FOLDS = 5 TINY = 1.0e-12 diff --git a/src/tests/estimation/get_estimation_results.py b/src/tests/estimation/get_estimation_results.py index c84af66..2831e65 100644 --- a/src/tests/estimation/get_estimation_results.py +++ b/src/tests/estimation/get_estimation_results.py @@ -42,7 +42,7 @@ def _transform_outputs(causal_effects): ] -def _get_estimation_results(x, t, m, y, estimator, config): +def _get_estimation_results(x, t, m, y, estimator): """Dynamically selects and calls an estimator (class-based or legacy function) to estimate total, direct, and indirect effects.""" effects = None # Initialize variable to store the effects diff --git a/src/tests/estimation/test_get_estimation.py b/src/tests/estimation/test_get_estimation.py index 9fed454..6b0aab2 100644 --- a/src/tests/estimation/test_get_estimation.py +++ b/src/tests/estimation/test_get_estimation.py @@ -20,16 +20,21 @@ from med_bench.get_simulated_data import simulate_data from med_bench.utils.utils import DependencyNotInstalledError -from med_bench.utils.constants import PARAMETER_LIST, PARAMETER_NAME, TOLERANCE_DICT +from med_bench.utils.constants import CONFIGURATION_NAMES, CONFIG_DICT, DEFAULT_TOLERANCE, TOLERANCE_FACTOR_DICT, ESTIMATORS current_dir = os.path.dirname(__file__) true_estimations_file_path = os.path.join(current_dir, "tests_results.npy") TRUE_ESTIMATIONS = np.load(true_estimations_file_path, allow_pickle=True) -@pytest.fixture(params=PARAMETER_LIST) -def dict_param(request): - return dict(zip(PARAMETER_NAME, request.param)) +@pytest.fixture(params=CONFIGURATION_NAMES) +def congiuration_name(request): + return request.param + + +@pytest.fixture +def dict_param(congiuration_name): + return CONFIG_DICT[congiuration_name] # Two distinct data fixtures @@ -64,28 +69,25 @@ def effects(data_simulated): return np.array(data_simulated[4:9]) -@pytest.fixture(params=list(TOLERANCE_DICT.keys())) +@pytest.fixture(params=ESTIMATORS) def estimator(request): return request.param @pytest.fixture -def tolerance(estimator): - return TOLERANCE_DICT[estimator] - - -@pytest.fixture -def config(dict_param): - if dict_param["dim_m"] == 1 and dict_param["type_m"] == "binary": - return 0 - return 5 +def tolerance(estimator, congiuration_name): + test_name = '{}-{}'.format(estimator, congiuration_name) + tolerance = DEFAULT_TOLERANCE + if test_name in TOLERANCE_FACTOR_DICT.keys(): + tolerance *= TOLERANCE_FACTOR_DICT[test_name] + return tolerance @pytest.fixture -def effects_chap(x, t, m, y, estimator, config): +def effects_chap(x, t, m, y, estimator): # try whether estimator is implemented or not try: - res = _get_estimation_results(x, t, m, y, estimator, config)[0:5] + res = _get_estimation_results(x, t, m, y, estimator)[0:5] except Exception as e: if "1D binary mediator" in str(e): pytest.skip(f"{e}") @@ -104,6 +106,7 @@ def effects_chap(x, t, m, y, estimator, config): def test_tolerance(effects, effects_chap, tolerance): error = abs((effects_chap - effects) / effects) + #print(error) assert np.all(error[~np.isnan(error)] <= tolerance[~np.isnan(error)]) @@ -114,7 +117,7 @@ def test_total_is_direct_plus_indirect(effects_chap): assert effects_chap[0] == pytest.approx(effects_chap[2] + effects_chap[3]) -def test_robustness_to_ravel_format(data_simulated, estimator, config, effects_chap): +def test_robustness_to_ravel_format(data_simulated, estimator, effects_chap): if "forest" in estimator: pytest.skip("Forest estimator skipped") assert np.all( @@ -124,7 +127,6 @@ def test_robustness_to_ravel_format(data_simulated, estimator, config, effects_c data_simulated[2], data_simulated[3], estimator, - config, )[0:5] == pytest.approx( effects_chap, nan_ok=True @@ -168,23 +170,18 @@ def y_true(data_true): return data_true[4] -@pytest.fixture -def config_true(data_true): - return data_true[5] - - @pytest.fixture def result_true(data_true): return data_true[6] @pytest.fixture -def effects_chap_true(x_true, t_true, m_true, y_true, estimator_true, config_true): +def effects_chap_true(x_true, t_true, m_true, y_true, estimator_true): # try whether estimator is implemented or not try: res = _get_estimation_results( - x_true, t_true, m_true, y_true, estimator_true, config_true + x_true, t_true, m_true, y_true, estimator_true )[0:5] # NaN situations From 80f4fa07b98804e3beb12d48134384ceade96749 Mon Sep 17 00:00:00 2001 From: judithabk6 Date: Thu, 12 Dec 2024 18:13:37 +0100 Subject: [PATCH 65/84] remove unused options in get_estimation_results --- .../estimation/get_estimation_results.py | 242 +----------------- 1 file changed, 1 insertion(+), 241 deletions(-) diff --git a/src/tests/estimation/get_estimation_results.py b/src/tests/estimation/get_estimation_results.py index 2831e65..57f4501 100644 --- a/src/tests/estimation/get_estimation_results.py +++ b/src/tests/estimation/get_estimation_results.py @@ -58,30 +58,13 @@ def _get_regularized_regressor_and_classifier( clf = CalibratedClassifierCV(clf, method=method) return clf, reg - if estimator == "mediation_IPW_R": - # Use R-based mediation estimator with direct output extraction - x_r, t_r, m_r, y_r = [_convert_array_to_R(uu) for uu in (x, t, m, y)] - output_w = causalweight.medweight( - y=y_r, d=t_r, m=m_r, x=x_r, trim=0.0, ATET="FALSE", logit="TRUE", boot=2 - ) - raw_res_R = np.array(output_w.rx2("results")) - effects = raw_res_R[0, :] - - elif estimator == "coefficient_product": + if estimator == "coefficient_product": # Class-based implementation for CoefficientProduct estimator_obj = CoefficientProduct(regularize=True) estimator_obj.fit(t, m, x, y) causal_effects = estimator_obj.estimate(t, m, x, y) effects = _transform_outputs(causal_effects) - elif estimator == "mediation_ipw_noreg": - # Class-based implementation for InversePropensityWeighting without regularization - clf, reg = _get_regularized_regressor_and_classifier(regularize=False) - estimator_obj = InversePropensityWeighting(clip=1e-6, trim=0, classifier=clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = _transform_outputs(causal_effects) - elif estimator == "mediation_ipw_reg": # Class-based implementation with regularization clf, reg = _get_regularized_regressor_and_classifier(regularize=True) @@ -100,69 +83,6 @@ def _get_regularized_regressor_and_classifier( causal_effects = estimator_obj.estimate(t, m, x, y) effects = _transform_outputs(causal_effects) - elif estimator == "mediation_ipw_reg_calibration_iso": - # Class-based implementation with isotonic calibration - clf, reg = _get_regularized_regressor_and_classifier( - regularize=True, calibration=True, method="isotonic" - ) - estimator_obj = InversePropensityWeighting(clip=1e-6, trim=0, classifier=clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = _transform_outputs(causal_effects) - - elif estimator == "mediation_ipw_forest": - # Class-based implementation with forest models - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10 - ) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42 - ) - estimator_obj = InversePropensityWeighting(clip=1e-6, trim=0, classifier=clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = _transform_outputs(causal_effects) - - elif estimator == "mediation_ipw_forest_calibration": - # Class-based implementation with forest and calibrated sigmoid - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10 - ) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42 - ) - calibrated_clf = CalibratedClassifierCV(clf, method="sigmoid") - estimator_obj = InversePropensityWeighting( - clip=1e-6, trim=0, classifier=calibrated_clf - ) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = _transform_outputs(causal_effects) - - elif estimator == "mediation_ipw_forest_calibration_iso": - # Class-based implementation with isotonic calibration - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10 - ) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42 - ) - calibrated_clf = CalibratedClassifierCV(clf, method="isotonic") - estimator_obj = InversePropensityWeighting( - clip=1e-6, trim=0, classifier=calibrated_clf - ) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = _transform_outputs(causal_effects) - - elif estimator == "mediation_g_computation_noreg": - # Class-based implementation of GComputation without regularization - clf, reg = _get_regularized_regressor_and_classifier(regularize=False) - estimator_obj = GComputation(regressor=reg, classifier=clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = _transform_outputs(causal_effects) - elif estimator == "mediation_g_computation_reg": # Class-based implementation of GComputation with regularization clf, reg = _get_regularized_regressor_and_classifier(regularize=True) @@ -181,67 +101,6 @@ def _get_regularized_regressor_and_classifier( causal_effects = estimator_obj.estimate(t, m, x, y) effects = _transform_outputs(causal_effects) - elif estimator == "mediation_g_computation_reg_calibration_iso": - # Class-based implementation with isotonic calibration - clf, reg = _get_regularized_regressor_and_classifier( - regularize=True, calibration=True, method="isotonic" - ) - estimator_obj = GComputation(regressor=reg, classifier=clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = _transform_outputs(causal_effects) - - elif estimator == "mediation_g_computation_forest": - # Class-based implementation with forest models - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10 - ) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42 - ) - estimator_obj = GComputation(regressor=reg, classifier=clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = _transform_outputs(causal_effects) - - # GComputation with forest and sigmoid calibration - elif estimator == "mediation_g_computation_forest_calibration": - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10 - ) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42 - ) - calibrated_clf = CalibratedClassifierCV(clf, method="sigmoid") - estimator_obj = GComputation(regressor=reg, classifier=calibrated_clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = _transform_outputs(causal_effects) - - # GComputation with forest and isotonic calibration - elif estimator == "mediation_g_computation_forest_calibration_iso": - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10 - ) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42 - ) - calibrated_clf = CalibratedClassifierCV(clf, method="isotonic") - estimator_obj = GComputation(regressor=reg, classifier=calibrated_clf) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = _transform_outputs(causal_effects) - - elif estimator == "mediation_multiply_robust_noreg": - # Class-based implementation for MultiplyRobust without regularization - clf, reg = _get_regularized_regressor_and_classifier(regularize=False) - estimator_obj = MultiplyRobust( - ratio="propensities", normalized=True, regressor=reg, classifier=clf - ) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = _transform_outputs(causal_effects) - # Regularized MultiplyRobust estimator elif estimator == "mediation_multiply_robust_reg": clf, reg = _get_regularized_regressor_and_classifier(regularize=True) @@ -264,79 +123,6 @@ def _get_regularized_regressor_and_classifier( causal_effects = estimator_obj.estimate(t, m, x, y) effects = _transform_outputs(causal_effects) - # Regularized MultiplyRobust with isotonic calibration - elif estimator == "mediation_multiply_robust_reg_calibration_iso": - clf, reg = _get_regularized_regressor_and_classifier( - regularize=True, calibration=True, method="isotonic" - ) - estimator_obj = MultiplyRobust( - ratio="propensities", normalized=True, regressor=reg, classifier=clf - ) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = _transform_outputs(causal_effects) - - elif estimator == "mediation_multiply_robust_forest": - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10 - ) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42 - ) - estimator = MultiplyRobust( - ratio="propensities", normalized=True, regressor=reg, classifier=clf - ) - estimator.fit(t, m, x, y) - causal_effects = estimator.estimate(t, m, x, y) - effects = _transform_outputs(causal_effects) - - # MultiplyRobust with forest and sigmoid calibration - elif estimator == "mediation_multiply_robust_forest_calibration": - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10 - ) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42 - ) - calibrated_clf = CalibratedClassifierCV(clf, method="sigmoid") - estimator_obj = MultiplyRobust( - ratio="propensities", - normalized=True, - regressor=reg, - classifier=calibrated_clf, - ) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = _transform_outputs(causal_effects) - - # MultiplyRobust with forest and isotonic calibration - elif estimator == "mediation_multiply_robust_forest_calibration_iso": - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10 - ) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42 - ) - calibrated_clf = CalibratedClassifierCV(clf, method="isotonic") - estimator_obj = MultiplyRobust( - ratio="propensities", - normalized=True, - regressor=reg, - classifier=calibrated_clf, - ) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = _transform_outputs(causal_effects) - - elif estimator == "mediation_dml_noreg": - # Class-based implementation for DoubleMachineLearning without regularization - clf, reg = _get_regularized_regressor_and_classifier(regularize=False) - estimator_obj = DoubleMachineLearning( - normalized=True, regressor=reg, classifier=clf - ) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = _transform_outputs(causal_effects) # Regularized Double Machine Learning elif estimator == "mediation_dml_reg": clf, reg = _get_regularized_regressor_and_classifier(regularize=True) @@ -358,32 +144,6 @@ def _get_regularized_regressor_and_classifier( causal_effects = estimator_obj.estimate(t, m, x, y) effects = _transform_outputs(causal_effects) - # Regularized Double Machine Learning - elif estimator == "mediation_dml_reg_calibration_iso": - clf, reg = _get_regularized_regressor_and_classifier(regularize=True) - calibrated_clf = CalibratedClassifierCV(clf, method="isotonic") - estimator_obj = DoubleMachineLearning( - normalized=True, regressor=reg, classifier=calibrated_clf - ) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = _transform_outputs(causal_effects) - - # Regularized Double Machine Learning with forest models - elif estimator == "mediation_dml_forest": - clf = RandomForestClassifier( - random_state=42, n_estimators=100, min_samples_leaf=10 - ) - reg = RandomForestRegressor( - n_estimators=100, min_samples_leaf=10, random_state=42 - ) - estimator_obj = DoubleMachineLearning( - normalized=True, regressor=reg, classifier=clf - ) - estimator_obj.fit(t, m, x, y) - causal_effects = estimator_obj.estimate(t, m, x, y) - effects = _transform_outputs(causal_effects) - # TMLE - ratio of propensities elif estimator == "mediation_tmle_propensities": clf, reg = _get_regularized_regressor_and_classifier(regularize=True) From bc21e837dbc6fb18f14f8e2edfc0efdeebf07735 Mon Sep 17 00:00:00 2001 From: houssamzenati Date: Fri, 13 Dec 2024 14:45:48 +0100 Subject: [PATCH 66/84] direct effect treated, indirect effect control fixes --- src/med_bench/estimation/mediation_tmle.py | 37 ++++++---------------- 1 file changed, 9 insertions(+), 28 deletions(-) diff --git a/src/med_bench/estimation/mediation_tmle.py b/src/med_bench/estimation/mediation_tmle.py index 159720a..71fc3e8 100644 --- a/src/med_bench/estimation/mediation_tmle.py +++ b/src/med_bench/estimation/mediation_tmle.py @@ -26,15 +26,11 @@ def __init__(self, regressor, classifier, ratio, **kwargs): """ super().__init__(**kwargs) - assert hasattr( - regressor, "fit" - ), "The model does not have a 'fit' method." + assert hasattr(regressor, "fit"), "The model does not have a 'fit' method." assert hasattr( regressor, "predict" ), "The model does not have a 'predict' method." - assert hasattr( - classifier, "fit" - ), "The model does not have a 'fit' method." + assert hasattr(classifier, "fit"), "The model does not have a 'fit' method." assert hasattr( classifier, "predict_proba" ), "The model does not have a 'predict_proba' method." @@ -70,10 +66,7 @@ def _one_step_correction_direct(self, t, m, x, y): h_corrector = t * ratio - (1 - t) / (1 - p_x) x_t_mr = np.hstack( - [ - var.reshape(-1, 1) if len(var.shape) == 1 else var - for var in [x, t, m] - ] + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t, m]] ) mu_tmx = self._regressor_y.predict(x_t_mr) @@ -86,16 +79,10 @@ def _one_step_correction_direct(self, t, m, x, y): epsilon_h = reg.coef_ x_t0_m = np.hstack( - [ - var.reshape(-1, 1) if len(var.shape) == 1 else var - for var in [x, t0, m] - ] + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t0, m]] ) x_t1_m = np.hstack( - [ - var.reshape(-1, 1) if len(var.shape) == 1 else var - for var in [x, t1, m] - ] + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t1, m]] ) # one step corrected conditional mean outcomes @@ -153,10 +140,7 @@ def _one_step_correction_indirect(self, t, m, x, y): h_corrector = t / p_x - t * ratio x_t_mr = np.hstack( - [ - var.reshape(-1, 1) if len(var.shape) == 1 else var - for var in [x, t, m] - ] + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t, m]] ) mu_tmx = self._regressor_y.predict(x_t_mr) @@ -170,10 +154,7 @@ def _one_step_correction_indirect(self, t, m, x, y): epsilon_h = reg.coef_ x_t1_m = np.hstack( - [ - var.reshape(-1, 1) if len(var.shape) == 1 else var - for var in [x, t1, m] - ] + [var.reshape(-1, 1) if len(var.shape) == 1 else var for var in [x, t1, m]] ) # one step corrected conditional mean outcomes @@ -245,10 +226,10 @@ def estimate(self, t, m, x, y): theta_0 = self._one_step_correction_direct(t, m, x, y) delta_1 = self._one_step_correction_indirect(t, m, x, y) total_effect = theta_0 + delta_1 - direct_effect_treated = theta_0 + direct_effect_treated = None direct_effect_control = theta_0 indirect_effect_treated = delta_1 - indirect_effect_control = delta_1 + indirect_effect_control = None causal_effects = { "total_effect": total_effect, From ce489884a24152a940b16299410f356db5424f54 Mon Sep 17 00:00:00 2001 From: houssamzenati Date: Tue, 17 Dec 2024 11:42:55 +0100 Subject: [PATCH 67/84] removed exactness tests, fixed TMLE outputs for tolerance tests --- .../estimation/get_estimation_results.py | 5 +- src/tests/estimation/test_get_estimation.py | 94 +++--------------- src/tests/estimation/tests_results.npy | Bin 360588 -> 0 bytes 3 files changed, 17 insertions(+), 82 deletions(-) delete mode 100644 src/tests/estimation/tests_results.npy diff --git a/src/tests/estimation/get_estimation_results.py b/src/tests/estimation/get_estimation_results.py index 57f4501..ee43892 100644 --- a/src/tests/estimation/get_estimation_results.py +++ b/src/tests/estimation/get_estimation_results.py @@ -31,7 +31,10 @@ def _transform_outputs(causal_effects): direct_control = causal_effects["direct_effect_control"] indirect_treated = causal_effects["indirect_effect_treated"] indirect_control = causal_effects["indirect_effect_control"] - + if direct_treated is None: + direct_treated = np.nan + if indirect_control is None: + indirect_control = np.nan return [ total, direct_treated, diff --git a/src/tests/estimation/test_get_estimation.py b/src/tests/estimation/test_get_estimation.py index 6b0aab2..769d62b 100644 --- a/src/tests/estimation/test_get_estimation.py +++ b/src/tests/estimation/test_get_estimation.py @@ -20,21 +20,23 @@ from med_bench.get_simulated_data import simulate_data from med_bench.utils.utils import DependencyNotInstalledError -from med_bench.utils.constants import CONFIGURATION_NAMES, CONFIG_DICT, DEFAULT_TOLERANCE, TOLERANCE_FACTOR_DICT, ESTIMATORS - -current_dir = os.path.dirname(__file__) -true_estimations_file_path = os.path.join(current_dir, "tests_results.npy") -TRUE_ESTIMATIONS = np.load(true_estimations_file_path, allow_pickle=True) +from med_bench.utils.constants import ( + CONFIGURATION_NAMES, + CONFIG_DICT, + DEFAULT_TOLERANCE, + TOLERANCE_FACTOR_DICT, + ESTIMATORS, +) @pytest.fixture(params=CONFIGURATION_NAMES) -def congiuration_name(request): +def configuration_name(request): return request.param @pytest.fixture -def dict_param(congiuration_name): - return CONFIG_DICT[congiuration_name] +def dict_param(configuration_name): + return CONFIG_DICT[configuration_name] # Two distinct data fixtures @@ -75,8 +77,8 @@ def estimator(request): @pytest.fixture -def tolerance(estimator, congiuration_name): - test_name = '{}-{}'.format(estimator, congiuration_name) +def tolerance(estimator, configuration_name): + test_name = "{}-{}".format(estimator, configuration_name) tolerance = DEFAULT_TOLERANCE if test_name in TOLERANCE_FACTOR_DICT.keys(): tolerance *= TOLERANCE_FACTOR_DICT[test_name] @@ -106,7 +108,7 @@ def effects_chap(x, t, m, y, estimator): def test_tolerance(effects, effects_chap, tolerance): error = abs((effects_chap - effects) / effects) - #print(error) + # print(error) assert np.all(error[~np.isnan(error)] <= tolerance[~np.isnan(error)]) @@ -132,73 +134,3 @@ def test_robustness_to_ravel_format(data_simulated, estimator, effects_chap): effects_chap, nan_ok=True ) # effects_chap is obtained with data[1].ravel() and data[3].ravel() ) - - -@pytest.fixture(params=range(TRUE_ESTIMATIONS.shape[0])) -def tests_results_idx(request): - return request.param - - -@pytest.fixture -def data_true(tests_results_idx): - return TRUE_ESTIMATIONS[tests_results_idx] - - -@pytest.fixture -def estimator_true(data_true): - return data_true[0] - - -@pytest.fixture -def x_true(data_true): - return data_true[1] - - -# t is raveled because some estimators fail with (n,1) inputs -@pytest.fixture -def t_true(data_true): - return data_true[2] - - -@pytest.fixture -def m_true(data_true): - return data_true[3] - - -@pytest.fixture -def y_true(data_true): - return data_true[4] - - -@pytest.fixture -def result_true(data_true): - return data_true[6] - - -@pytest.fixture -def effects_chap_true(x_true, t_true, m_true, y_true, estimator_true): - # try whether estimator is implemented or not - - try: - res = _get_estimation_results( - x_true, t_true, m_true, y_true, estimator_true - )[0:5] - - # NaN situations - if np.all(np.isnan(res)): - pytest.xfail("all effects are NaN") - elif np.any(np.isnan(res)): - pprint("NaN found") - - except Exception as e: - if "1D binary mediator" in str(e): - pytest.skip(f"{e}") - - else: - pytest.fail(f"{e}") - - return res - - -def test_estimation_exactness(result_true, effects_chap_true): - assert np.all(effects_chap_true == pytest.approx(result_true, abs=1.0e-3)) diff --git a/src/tests/estimation/tests_results.npy b/src/tests/estimation/tests_results.npy deleted file mode 100644 index 1790bea9583a23ca86c7f4b80dff28e51e9764be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 360588 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

;9D|^`wsEBr?aD zIkWCxc~UUv(Ck2A+fJ&DYDl9R}+BjY6gE6=PW_46UK{$HG2htx46nV%2;rDx7F zbLMr)JQ*iBiSxyo^Q4X$Ngat~p5!Dl$LHhBak8EnN!@>n%=IK^u4j&u{J+Kd)@5FY z)RA$LGb5Rw4@o_9o{W=7=I7(gaZ*nrnV%1tbtGp-vYt84%t;+H&Zi^er2b!=Sx4$g zB=hqjsbfY`PsabnnRU$i`SSDWNIi+9j>Lb($vlb7b%&k&Kf_#+i{h zKOdhjPOitCC*vfNd1hqJlbl3m{l7R_N8)^X<~+$sBB#uM zkX(<{k$gTRb@RPpS7UYjf96qeZ}~iZknpwTCJvbfRy2Z;)x_ht)1x3NBwj&Rodz0O ztllKv1_qr69Yb%_;A*Zd?UA{)*s<}Zv-`Cf=y;{XKVv$CC!X(+U5b5hv**ZF_Ni`+ z(dzxv@vau?LPLZ_Uys0+;w|!z7uTbrvB@2~tuzQaeFxRbNgqihe$mcUjzOjf@X zQ}(ZeohoMqzCEvpC3}Y4?fwP;r={3r-MtPhJAdVtZR#{k2G8_SBg()&bFX-oS|##V zK27X}YS6wQ>QLF&jRpnXnsfUqU}5{Mfh|P$hFQa7fs}-9cy4j#RJ8^j*Em=D1#Kj{ z;sifSuN`bcLH)7|2j(W>NO7+TH{p*y$p1j|>dbpss1Xz`-pN9-D6=sW^2`VMvUm;M zx3gHGE&g+`ZZiExXk~x;k>kS2 zLm_-b*MD4HU8d4suzjK66t*`O_%1roqIVWS?f3H3U^@oR3N#jd?{39ppL3m8y@z4P zmekpM*>p5iJ#HPE@*To7HyPBp41?W3XngS2CLp?{M%ltTar4n7+H%IVM7Qd)Y^~fD zP+sF9we4g(p6BEXxcXrX2kTr`ytyz6TO$rCE`3>#i;)NE3N3g_#nIyXeZt45H=gqm zahluQ%Arast`6V%#C_*pSq_e?jq@b9qOf%6tJo;vo9Z&n&DQ8O1IreO-w{|-4IgAy z9CZ2J1>?)_HY)oQKFGD~k}DP@;w>4&hf=4;u#xxhYMxIM`0l%>neqxcoZr6JueO1h zYf=8NQ`s*Bj*s($V(6yt6XicEc~r=E`W+E3omJv;GxnUVs7@R??DnBFjR zq6}L$O8dlQr^7Af&#{8hT$C#@QkU3{&7p^@%H``>;n<%dS*I%Af+m}f)KFFr!MmsV z55IMffz;VubqRzoFPpkqkb-6-K0JJjZOx%%7#Vr=XF!jb|Ir%cX0~@0X6CF^PCIi@ zBz@O8m%6i3%=G{KSi&8Jl6!ShVpC>8f<5Mu1Nz~$t+G;`UR~hZ-7zb6cm!5#i)QVl z4HI4Wq78dkX*jg8R?v|6_dB&NJ?Ov&9_q*9W z|FpFQ8@p%Zf5Z^oPuVs{Da7xUxLLm02F)UnJy^8E#x?`4aUR)nzO)G(RdckIeP?i6 z?UyTjoeY$EC|PdvmgoX5@>sPZVFLYn-fP}COSnAT9I)ru*ai6)Ws1{?t}3gH{I&cP z!Uf=)^WyrAEqLGY_8mj-I`EG)Iv7{~7j_>!-@c2d4|o62Tq9I52#VTiD`oc5Abz-L zSl)#J7V5`377?F&zq0$Ml!&=8&QCgCxf)NS_Smo1hzG6ET%qye-ELx@h1J>ZYnQ}g z-G`(H%KYqNFT7Um}W==sg6Jp(%7(cCB9H6nC4{Abzk zKUobh@j!V0E8^#BvxYN7eorSZ*mq@Ro%F73Mo;D?}%{_P?YK5Z%oO zOibjru53h>1QU9bs2^GtAC@`3neeOpL3Jk%C&Tc;FEyKgC4({lbnK>2z0mBoX)Hph z0&j;yb}>I4>a1r3F15CzqO)f7<{LvWBe7LIFnk(vza5$qI5`YqQ>X5gq@}|1qv4;m zwht1%XI+=1zOzueZ#VG`-eaLS?l)BDEhJ8tIt2z&$IJ1Tqxgdt8@i!4cY4awwFRVU z;ZBz;hB~YM3Q-*M(8aCvYbe8MIhJ?=FZmi?* zu*d4xeT8T!>bvN``!NgklP-Bx%+WFIg!+%DY2tG^_kG%h_Exls`eL0*_}qo@ibdK9 za8k^qX*#z~=VMO5I9-6d8|FNdshh2uaP080qIQjXjJB`DaSak9XUaGh{CDZwp4!{h>&?3ZtQ;Px`lRG#VqjJB6} zXmYI{^|-8xKb$Ar1ZwY3?flz;yxXa>xk~OEl0#wx$_T#!^EkSbT2 zNd+pfC~D*ybl|fy=Q3XP4@2@BhY|L*lR#7dB59Q62?A;RcHcIs#&dsk^Ubgw{8Akb z=`5VY#Uh`cavUoL?X(tN-3=_13j>$bO>PohZkp%j7#u|)Qjo%N;OG#TY}~&qmpTeV zEQjWtepC{3Kw4}rl+^)6C#oyD-6Y zW58n5XYqY_7FMXpG%1`a!=c3&D+@H*@c9DOnCI4gP|s(e`ry}Ya zbX!Q%l}oTjiRW+KigvKH$jeU*tHtJ9-7jgQqhR~`$uUZCHaxl3=(_*f7<@EdD!{*O z3bVW?mVABL3JshOd%tW*NA9B^S2i;0VLbf{ZB1h{aJ^~O%Css1z73O4b7+J+%6T0g zucgHGpRY8>JFgE?qmR80t)M}x;oI={98<8m`KZYw`!ra8$(!#iaSCbb3yXsvXe4U+n6|#K{4h`)|bj2262?*1dva!G)`L$KqJBOgi@GB*F$#=+oh)cq( zYvG09(sk6`y%17ce`Cg)4ij4hw%qtm2fuuiTEpd&AlZ|*T8f2(@}y99u9>G8X6+n9 z#smMNVu!fv=bd?Qc)7vJMx{Qi;M@F0^+`KgOQ-~fTCq^%^LrwciEb;FUuP8e_twI) zFunH%yK zFy7D#o@-@yU%WR6qQ8@DRqcYHmc7)lOR)~GoaUHF@F{?e55mQ+G&P{HnY6?^+f=L) zTgb|?mWFoAe*KXk{EK5)8u|=2m7@AN??m~UTC^}s9@INUTwhg&tOrZX@wBXUQM<_) zPE(Iv`|98Y&1>Xq9B$0Px7zK`n>QBXhvb)*dpokBq~mOB9N|}cXi8=_VVr?SJq9jp zG984e9XpI_-Rg1W_O`9*Dy0zG+%nLHZ`$NPqJj(i?NN7!8W7?3h;23)0Bwb8 z7FW|Y*ubF1@Yd1bw}$`Ff!qREI4b&n{YqBKHvHU}N_5q0(GPFuPKyW4A4}!q8(P74 z$0yFsW?$k|xxG6RYl4C?Vt8aPI*t$t1Hmmgn#5b1xU7i24MY9uXe z1>P-&Dl@bWoQ{axVES|v3wAF!*FnrP>DH zWq;(N>VhP?z;qk%vR^v;WGDgCcWAS|$(Y6)Be{plA)mMvm@lQ-_3ZaS0xh+THm zu=ZCbjGZRtuB@vxmBbJT4z9XsNVr;w_u0lCDD=UgOuE^+2a~XVBUjX#g~UF6DVL$x zDL=y3+o=4!7cq}4e1W?GF-Pkt-LIC`O+~JZ6p^;jKgg?nA~;2djvUq>CTWC!ZM@Ub z^mCG9sH7QXD-t=1U)ig8uj@{Ni(|x#d?8})NR*b(vc2iGeJ0`l zlEQKH#kvKQ^>GJcc|wBi~6?HQ=^iBxL* zz(M)uD3POM!@!^GG`jDt9K>AqQi|c!9MU>mDh%b4A>iB&fw2#+aI)h_m&pb?Se}kJ z6ever|5OjutbH>EEuKLq@BAsjT~+HY{EQw16{Fj0g)Q3Pv3q|fhhRV2E?4B}>TJeH zea5EUD<{yilD+0PqXj4my`HlAbfB2mjn#~&Kzxgv|24wjpT%YAUg4U9urkqdAk?D| z-5>6?H7#bK<j|jb*Y)hL&nVoV+7{uxkd1O7 zw|JwYM;XkkoIK>#USvl^n5eYFHf`cr_Kv7UmR9ZlvLU4>c1Tn*xxDsGExAr-944+_l4M z`RF$=wAbh4r2aS*GVQkU<@T5#)KYJzla^Pqa-hb77d2MA5W>4!c_l}=} z{&Qbvb{;K&s>xaL>6u9UlCq2MOEt0ozNTTcNT3Ad!XB|6FZGAP_UqeUf2#rR2=0S$ zrw?koqor8gi0jxENguVU8Mr;FbXVLe7ewWnUmh(O!_VAG+y%SJQJwZ?U{)dmLlZIA>0BzO!18tw ze#0IqSkwkA&!SRun{@FRmy^I8tpbh0^T>yE)E#wvbV!Hjj$EE>VmRTUOEN1_5Sp}Cv3fNk~feM>(vBF_eK`lUM|CF@zP^OrlZ8X z#%~vHtt6iJ#Hl^8b?=4n<9saDc9TTcTDmgp0V)JNI`Zd#&tW)mm`8l%`4}u1s(bKp z3$gECU3IbRWG$u}`HDn-OhCQRqVo})A+UvuVxa%I6}lZA`6{N`pn0QtrT>a9Jfpd7 z$e!?Dj&v-Sl)6mJmwS+-+Ba8?L4}^zF0AfA>0hiL--vdAfy>@cw0+I6mbO%jn>88V z&>dgaXcNBGe!LDj(-M}gJA?-puwdZ=rH~qIzJH9DxAJGLV z8#~3X`<<9OVsqN)t!gVg{=I`mmT>nlwOD@QQUE(8`N;U|y7CSPH(YhXO}!D>{_=i( zR$2knLREXmUC(i4f0yS@!oPj>$wDXAn{}8oAohEW^faWNHdhQ;&P!Rssb>}SZVJX* zURG@S(g^2u)mEP{BK{s2dJ~m;zi_McUe7!Eeel=S{BL1mGnDE6e0qUi4nM{Eb|gmk z)xn>AXuQ=WR#Ptz)I--vEj!jjJm)CN^pG3F=H_dXSI=}Ii_yv@ zQ!AQ?=NGd_gU__%4I>sR`Nc`=~QW z^=&@*$fO>A2UkTcc-MyuhDUQF+NWXp=_@gd*Ovh;*iA{8#T7rP+#k&uPluxX2Mnd= zuefVdzw(n?#Qo{z1B+SL{6s#_^_tJc8i0~PyH=sr4Tnx?N1ryB1#9+X_XCHBIV8nP z>SlJA0-xJ)P0gB7*dS9pYVxoMZv=__G(Wi`EFHENr!`-y}0GNif0MjNWE-Y+c*eg(UCG1vO^Fa_O{H*e*g?>M;vP0hQa7Wg6W_W@w~y= z?$bBZc3ARkVfTwhgdW*%l6@yzK=!#qqHRBoa6fGB8)6;C&r04`%>EMYr8kvg_6sG$ zV(P+t`~E4gqHL=^d6@y~v(7IqbN;|eKNV^?v9IyrXXl^s8i9^&Km9+SFM%UZSwtl) z*eJ@!CAS{Y?nmFw+p*eepJ7Aqo-H5s%3!J7!#AgATVd`hl&BVG;<`KAR18MjaX3A; zz|&{~rkaCW-qhv7sNn))eAo>3Piy^IUOEk@#I!G|@;0L38@oTz2}Q8IBdw@*K`{y| z?G6~_>V}gA)6$wsLvV1-VCK$K^USc|^Ew#8D4&Mo&ZZUE{NZoy7bLzY}L$ z4!6UN<=4)ixZZ*GUv&Fj8ppt;;;6#%f>xZoH`>bOoQEgE{0w}HtDwNU+4r>1ze@;IPz)4oSpqscRU4%c^;Ha+x?ak^Q4kDp7ka^XLBv~H~qNS z3U4fXBE@F=P<+YpiyQAIpn!1BTV;Pbcy03cZaYznn?yt1?;e-~n_H7 zzx;@M+J+XDvnf6U)%b-G)A-7!2TI>tC$v0mhn#{x#a9Q4Fhqn+s3f}uPpj|9+(+!! zo_8qQt!ti!ffalm;>27hy{OJG;pSP4F#B9!wY?I0sVuyDgzJiUZ^b$F>?RDV&ey1M zn?{W-d`*sfy5Wryr^GG(pJ;6qz9xjD5~L4%$p+~**|}}`L5Q6(rqyiy?<*m@8(9Z%3AEkf1m`c&69gB#`a*g`PANRa(!^$ zOz6dR?LM@KS@?{ww}ek~KYS#diTh+c(?B|j`x_=cG8%6^UZ?09oooK3+acGC-Ur@JsCsm|0 zh!KryVRtS!Va3CvNq$AMxFoS`+Wgrl-t_QDzjLb^GaVgn2)a~(@D_2&Tw=bCO4B8c zck8I2`@N9ovBMZ#-*UoeUpFzAn{g`en$!>;>9LL89>_}J^GK4ZXdZ*qoNlMfzSXEX z8CT-=un5FC)l7RIvQmaOZsBb?+6-BJf~Hp`2-m;5P(e^D2YdcKfh!v)F&+2aiE|!- zxVaAZAHhYq#O=jRwPoM23=8=x7G$B^?PVLDI1S;T-xi}DIERimg+ z*xHV&T%?@3w{yw#5XSCGxU-6IZ=wuVv~H4Nr^G+KMjr{vL)u&Jvoz&G=oNc&zI;~~ z8eR3Xo6s(S9|rdIGB--W)+76^^U1HM8>R0NLv+`R7+7Q&8Z)ry>(#(;xo&*kDD`Qh z&Nt|N{pPsj`dK{sFuX+LME#(=W!*fk8*5y#4Kao;71pqK-+CM-wCKkDlIP)ZgusoK5JStv2G`&?J4Br&h@5WoqWr2lK;$y%4j;o8Q3O# zSx^Q-1JgMxR(C+U%+S(FVt$1&_kt+e>PTWv{0nWu3l5scJ$FnmPKKZgQ8T5xmMHeZ z@70EZ8Myw4{Y>QDDfAfP%;h(#!;w0^n}dnNsHNflcf_s~#brFC#rqibnUP{%0X4Fb7Xtzc)zU^QLb@Sc%Y`AZ6D!>Ny(g| zEujSeV)D&KH&Hnp1;0B=J5|sFj$Mc;+65+Mx=xcqCnTeSIwmY>PehI-Bsh@tP1!Bm5@l zt0k;nWi}$Wx9NwQma{NhI8532B_Dk^R$KSV5tG%|^Ju$iPk^(0IOF)6DKP$|8+EXI z7^oqk*Exj)h>6;dT;(<{pePDVZ! z-Lxu@`^{1xYG(;(nw9KYWYLA!M3pF>DcQJg?G8(yI>Jh2YFJ=*@-!qLJ?lFsJp&c% zYQh$aETZV#7TbMuZVajtA9(37TG23!#QUq?CKstY#6q1T*E^7C`a4B zN8vZ@-l=5Xh5FILPQDpFHz#RDt8)k}Ve@G7}%vws9X?Ph4U0EDNVIdciulB~qi2@FBUScz8nrC*>Y> z=!tX)J5|G2OK~q(0~l@QWl86qg~zn)ls7G-u$$rW_uwTKN~%Oj_@*&d%K6#K2bBw( zaA9}+`^(b(u+`d6B&LB1#n*m)pG+!*3RJOh?zVs^>(E*) z1}nw=Hc$4>n+qtH+_nj&y@~{zmA>1ea;D&z^^b-a8CJ?@xv0usOEwC(Kew?#Ko?#Q zD{bfBFadru`tGtme~=G6in9CS9+nP;GP z4nFqm&U$GvjE0%G+>EY`BH`UDGHu`6;dhvvEL#>~ zOQ0HCpclQLj(B(H#;J?g6Xnm!vYl9MXY9VVGtyX^K%D2(TbXJchQ;n&YNf^nLhiXv2kvIPZ^Jz$p zfA*&R4R*4ZOcxy)TLiO3dsS?*X3)HZwCb6xY~<0pdviF9!}pt{398UpIHPc^!`&78 z{&#tu=x42h`Ozvq;n!HCmuK3$a^`Y0TUUSVj1KmMq*VDKUz|Y9AG2qE#afL@r9=sz zw=|;*iuV#My6eHEd1DW$q8TXfy3ZZN>iE(2tGnI)+>J>4y>j+4n_zYFJT~rVUqT!9 z-(#>^AP@-?(hZaQ#!wv>C8K_JA6nwfn!Ln3jCSib>N1;_A#K~!T~o6(#Eg4>d(D=5 z(MsNiO878`lKbwuY?q%!S8Z-4SoSs`(h76RLjQAkxBGn9EK4Uc8~5~J`m%)b&QQt|YE>WnXk^_mn@vM(woeRw$v=ihS8qRS zkQfFFmM;0Z2aLq@xZKA_Xoe7hk3m)bG*$;nTc+{~R<}0oWKMWvO)lCpFK_A7H--G` z;w04;R>3PaGVOrjB3wUmZEVqc4Ouk5yZZ3m79cfjl}~GVj?HAa~9iJH5y2P-m!)I(x}atTUx+b!-TB(s)ql zo9QNN&|OY9v7#G+vp4os2z^}w+nW~_xz`3E$=o4VY)2RHsBqTBV)X<&6%)3x(NGch zp5Et<1Qwtt2bf(KJJAWV`n1nyX26;9NWr%@Et28K8X$fMxZcw52Uad8H4Ngh zy0{cu$}cImBA<#wuXKJbfeL9PYUm0LaZ9JyO4PGHI2)VyT!?86vF_!JK5(6q*p#@C zx%DG~IIiYa@$+aT%KmZd`m3=8=zcz(u{Sae?K>4S*hw)6wZmhK(YZay(4Nhp%fbhe zs-q&7u$`X#(_;3MEF(w;_6lUY$wZcyV>Q)2F9N6V=qQ~Pw$tV!c`12cKLnhvmU)vj z4R>z5yL7_74k(2V9&32N1ZR5~`#P7~!EHXQn^p_K&(OQ~j=wKMPdEu49>LB~1ZDeIUNpk0C^$}ZlqSZBt?36_0eMj+NHn{D9|Uq#kmZn!rJEg_eC zjVgKqU5Ht%YwFpiLgYUFq3eDY1@Zme*#{cGr(w}o@t4L0O5${*s(;T#tg|)4YpxgA z6JnuyGPjLw4tmh-ZMHUybwUo0;I5#mgK){bmLNeYqRQ2p&_`dXh#47=Qv`RlASN)p z%;JUB$2`sDYAD|aZRf%*Ry9UoS~#^aXU_t1u$yZBwx=CkYMx%%W-^bMO^nZJO9TK* z)zN(C>Nr^KTzTwlK8qei+>gm}8ikE!SG(_tFcKe~5`M#db^+=SrX=X^u12Au;bMG> zGf+=BXt5<7tM6*Y7ro%sj98Ke_dcJjMDq(3Pf{8j^Q_8~$=v{9&d!*Tk)4Rfe@ z+~`Zntrhf1fL4UY4tvtppj#uDHNfgq_qBtXtJsMt?|t!IZE)7`S{uUF9p&Y|THeE> zh;(Y6sv;8W=xcWERh(%Yv|F;iU(iVbwd==o4`Dkm1lMbOTWn^~!l8;enaTx_vb9N~ z#@4yKC+E*~%J)DiyWaT~EONk`lbdA!g+LU}>3OHnmxb;mo-3oj(2J-~UT|Cy&qs7r zirbXpsfeGnPp3uX6#%VYfW1)G6bfMVxk+eQhEW%$D`72ta7T0_X#%UKdssbWAOKsR z2EI2bo*7(3QT|UUuBhfAI?*qAXFpOC4+KS>I=6WWxt-H|q=`lN9aj4t)JhygqzKJ6 z`_L7v9{X_@ajd^eRpFJe^6%7G)kR-zCOS$|KO;NI){sE-W%^oM+_-`SPT%kK!Xi1p z?wS7e@!dF*f7nnvi`Byu74<#&MZONG^JWcE;Uvm&ige)~?MA50NKt)IhWn@a}g;O!Zi z*R7oWaMo{(?Y=U$^DaRp%W)Yy;X5ZqtNk+$`MfZ=?Yj{>8DLFZlMch~-@UiOm&E44 zEBu!NN8A#;t&9Khz#$*$ZE`YJbLm2F*qJ_8VJA^tBf(8pj=d<=QX=1#EfPK}Xa{y< z9dX}f*454~En^Y3ZLK}o$>2Ol(w$rUj-EF<+Y|?qz;z^5Z$)nuMDEb?rc7YJM_0wQ z(TQ=S$IaQQVmkpQjxL9b`j+6%HTGZkPf`)@&NvE<6fqDp8%<3p28v-#C;wfI#~P^E zZRxvJ)`uod@;{h6kAv@1^nf{8~E&^%3X8Is3EGkpUa=#f~Y|uAUOc zZcjmc(*EAT9ownSEBo$KXi@>=O0|ufjt-(1Clt2X8EF$CT zv&AFj3OktLrcS9f6vS@2;^0AAxHCetWJ>{!TQ ztYhl9|E@hPC`Mc9-7)P+VEoO-TRe|oRjyZB6U z`?qCS9-KbP!oxruWTYF+v!f%@yUX6Jm%`T3Wy^O5vEQxRdp^EO$0EE-sHLsHUMCQP z-}=+4T4sW1!dI2bP1D$k&*x!wpH8HcJvj6uwF(Jy3-M={CZm?`fn4pSR76wT=Igy- zEhu}hFmqc%J>nQ%8G74Ti@v)hsn}TOLbUVi>rMp|kmr3+H_8_4qhPm1_oI3RYDX+a zyRiFs!o%}7Z_JdyHqT$IR*W=6icYFZ~IucIMa$KIs%c3gz;<25IrNYfF`2Ni;!I?baO!3CLTiU>q!h2g*hnK@wW>#Eng za}JC>emBnWQxi9@sqox*H-S82#e*JBU^_dXadUqZs4@Jly>yk5*!V!I;|w#g9cNawrd_}MF*ug zA6vBaz@{J4y;I^dC|gI~LU}hmvD1JV3-uU+Wxx7%@l^)mu6t7y;Y+26=|maj&>Des zSFSBm`phD-wNfKebT6ZRnj;E4SRW;#PLSW0wgD(yDA+M@XdJFuTE4y@z5uiCY_H1+ zv_v+c39)zEno!}09KU*aE{yH$+LjhbMP%A^-0D>63OHYhjT~yZ>syNQ^0Y&J+otqidgM=Wjg5P0zB>C zVrE)h07tln-aHa$K!zn&$udg`XrPz=O_b^o`bc-rEtdm}sNJ*B*VR6Sf~j}SN@348 z&W|XU57{omi}x9R8f^0@&^rBj)5#^Um>zC0AvGe-vBU?dEDNCj!r)WPI|4E6QH_*w zb|qqbc%41oeH44Y$yEf6e3V5+t;fKjVSsWU&GPpPd{>PanL$ zDgR;-a>cpqX_X1Y`vqC;baB5Sjw^rT`^G9HaCXO!Bp-=r#4PDh$+vx7sN;={`X#qz=$77a z=yX#xxJisroV->HiZPM_pRs!2LaVpv*_g*swfmLl!Om+iUoybwzt)28*1BKv!S2Vq zqO*b(5*A>4LnYPzSN%}HlfA{rasm-ND>%G)ny?5p&942CCFtmm&2_z60}zw?Ndt0*=Bi9G+R z9icRhDCX5xE<~(>GpnK0;rm#Bn5+txb8d|gpwgPc(9(k-c_WW9{}41+NR?Hix(5_zh9z8egb4^Q%4{MS! z7V(W9-cGd074C=Qk*bp1PCZDyn59=iVGYu*OoW`5z<$59x|S}}GZKmXqo3ritfJJ< zDX*WkW`aQF#_XnsD&W`ml6PorH(iMW~JTtwFq*+---9apb#Gz}?wo7Kq}bA5Xy`*t@qoNdyeSWA>Py zii2ZNH0t4cdA(K$XPDmj>EvI9qA#U?g+hNK`AX3K0bLS7O0b%45yM@Gim{iUzY1OYo z+(bX48G9d8ZxMP#aMvul;(aKnHIb?5nW)v8sHh}_aKlU)fSA)cDT8>Z3y`bFB3 zc>;0QPb;N&$uvaupzt;+0}3ny%-R3h??u?`81?y^_Z+IOIdm%@iwJBC&+)Ym!+yVF zeoBUBcLTTcjS`O3LAXD+P+4WW0K`uo_r!knp-ZXNM_xNH5>;q6mmH~|hp%HVeJN!r ziBYl?l4(b~(aRlT@^3G9L5Qnklr{wk`(5DlXnKe}kKE}#>9&=II91_HtV~{mC^Nav zWXW+P_ueEhFnR^7quA}JoNIth5K9-aPJ}`A+tZc7_0XcwV_}idi=Ji6Fx}s_02#dH zGOu~NfVsWZp7B5jG8W|vH@#g5`R@BP0wTwN?!#t97R5C*$eFi(x)9cNDC(?#q zNM7uaH5rD$?bmf3{5yeP&O~*=suJ$hv_6VH@f$tNukb$deiXPIU$jdGufqMcOWiFS z2*mBGJG!5;%t8gncVm(hmMQ4$nClnV4rgm0y*T}jp7>OzD8AxkJ3NS7B#0awfH}I4 zcdwR>0wG*zPeRBtl0O~?!NI4@ArdlVVD^WfrhyD`-z?EQv#7-PjbCkaJSOnEeA^SF)9He<+ zwZs_9keL&RF{iJefRPq~b532@eP!E~t}k(O@TKilU(x9a-s~wi5VEE5#4e| zr4KnR9H&X#jAcqO5NK!F>Jf$cg0HhnElfT=@q7&1$4K4Or7S1kj|QTBeqF`Z9h?Kl z9IJHKKv@3-o7C-DDC5h#*t)e7wA78LjIm55y>k)rRX$kc!HxXJHAF=$iZ*50RhM}9Ab-PgT*8N4-O{d|pey4QBLk8mVslyguV=0K<(S>=ELaS)2T&REv z)@O9JyzRLD&EH6pdEu^!)CdgkvMz`VEkHM`I}%$j&w(2!w{p!d?3_q1^2pSoNpwZ7 z+=27U1YC*nKn3bVw&zUcg zSmsZXWzdu6(iw11Jlm=)M@f_k)S5nN)()?Fb9cM7jH1y4c?p#wU9cf-bm#+iVr#;t zIGt{_0PM!%KgQmS!m!JZ+CYJPT})tGFYee5~|@szx=_g8i7BzoFI(TsN$ zOngV5%e7*ecgIr%EqaPkbdt)3;@}=+TOXDwC$<2Dm7N*>cL zVhd-j?Dr+Q|(>f!^X&)~^ldc;?L? zPfW^S$LW!1GwCsOsP5LN?&uk32oT7o#pw{QHWRnbg$t38vGPXalN&=j4JAPeKdGK3xU=h z6n>JUh|7uljL||P*nZ#gc`|Peyr=KU-X_!lJ3YF9rQ4Mhl5^2fk#*esmM5&(W7|=2cgD;o2 zB~s;pg|3>m4c{bG`@e2_h3)&!$6s&c8*77%R|l#YB7>;4_no0=O{CtF6&=rbbO3mr1xKX%OAAn7iYa*`>&3&d706DCe{B`nVO&d!_=>&1$R9y`O7@J z+9jnQV|y0=@@}|6|L%*3zf5iT*wyOC=7fJ`6*rxCzDs$$uTRJm7msk>G!S&j0*um^p6!cFrdKE6b>I@Zd$B0(@$_|No|T|HIUb35{#p ziGR83t=-vt`u2ah#M6e?*RquUqN>?eLmQWj{`IP5+nj%|ywAX|`t2X4-fSrJ+wkIF zrcPL;I8bu#FY~m_Ir2WY{)>v`VJ+jy7eD`X>P|+{g{bZS{WmZ*5C6l|4FB`0+5gs6 zlm6#b%l-ALQ~xma-@EG8|9RESf4u6VKTOS4HuZ{|`7a-MLAGqwW4-_WbS>p6@!N*b z=a42*+4O&Y#Fj)%Z)#rszYqUhUCZ2*_lAv~#SLrT>!w#MjO=dM@(NuswZ3Ix=P1N$ zVa=;``jj%S#Vy`jw{2{0*xH$1;k{vP<;Z&#<4Gv-8e3Q!**gAzuD<51=9K0%CkgJp z=5&v-JCN{6iqrj6|5~tvwk&jU=w1Wt6KgmW`)(BN+1XYdk1hK?XFTFI*w>8O#Aj=& zt`>uzRn}usVmsV`Caw+N2hr{??t79b7m!Wrrd95U95lHgcrP*KHwrDc+~Sx#fKC|P zXD4b6pc$TC)*F0Rz<;0jHaF@nv^k3V=|*EZ;ugc^M{y3l$a255C2wLb+WKK+K)q=R zRRp$HZX&j$jxxuHp(8a&D#5Bj=WRcn5s_EE%rb>Syu*c=mCI0Uf3lQ-Qvnz&4!`pE z>qaZHH-hNLy1;?WDB&{G1WHxr5O;T(hl7d1yV;)gBHmP+#rEPMr1y3>J+e0#eH6`D zvhmORsb)c~LT{|+6 zw-%{p$wgw38$8njG!dHvNp354Y^ugmO79}qf#PMf+|tsRY_*k8AZ?7=i2m4enanF zi5xnuaVUS9HEeXf7M*_>xAoMSdNBM>A*l2`AMM!IGh}pi3M9`O(FJm1%gKYMMJrvG z;nCS(SGvnF;CUwJw6aST#0oLE?|Or^ojc2xoBwhcc+Ij4?fSFehuZP&TbHOwzeijN zdMsV&nGF8G^xF zeJv<|wmrelKY+@^*{{g&>qj>6TP53KQefi&mRI!$8(_;6cdin1C3E~<#`U5@OHvV z)hwr_K@!>`{E$1vs15p?McgGMXh@vrazazL4k5o@&nr3auThxwN;T$HinU7E zGx>f5N#B|H z&WVg8RkncP*p542R%2oFb$i91`VC0OyRef!eGqZy>@-fy^hc#;#{^m?$Kd?;y@$kn zlF`gW!W$83tX-F#hT9x-EeLLYsO}=wf$F619`C^teG7yN9_9xYAZ1^NZpyuLP!JKX zm(NfMi9>R2de|blsqV0LXJ0oQd+ju(*V6)5-WQ#u$J*n$`0mjD>@o;Fk;5md6DWyu zd!z17UhIUm-FMW%Z?uWx&huJq8;N?iXI0i%2~v%^a#Z8&7z)~Km2=TE1Ugmx zN~Lb~AcppkoR}jMaN!z{*5d9-R3@f1ahQJ*j$~CEInOpAtJ`H}4F|?x4^z;HcvC0R z*YgMuzBmGp>5ZZSKVqTxT{2X>-~EAp#|7uRTzRnXd>`iz_Xg4n665k`m4{4kbo`pV)Ys z(Jy9=*^Dpqpjqp4xj?!K#1cL%IBSo=N|!}k!!E3ytX%M%yIL=>Z!)AbnW;zPr?WIX z97@n2v&E&`F$ilPY^KONQi~>)P8@i>VHjW=DQ-e^3<`&zmze7`prJ$>9#)n-i8O#hT|~8r0McsB3k6bpT70W9S|iukJ!qR=;oemyaR)?eo3y(x1cN5wVYY>y|ZSKjtho>ppAB)VX*bJ`X>*K9%RN# zb!%&WCrXOEe5(D|I1&{WwsVQDMth3x?z;AE9!pfF@)&4qM(5^I>dsAtfkT7HH>n%_ z=x7qv(ft?d;ZSn@C+EZ1=MdLd{zR)3Nptp{7*^~@51itjl%1{u30C^iGy08a=UeM5 zYg(NUyXS|PiO2~0CB!_i#E}Z#wu#ewTC#!Rim+3lPyq@#=b)*0I34Zp960o19&48w z{b2Y*!YnKcT+7s%T?V&9Ud{6zt)L^)d%h1#_^jQ)!_r_j2!_kj%X)J)5c5kZ-C+4M zda9Wu5K=b*GeuqYU7sQljiyNR0p5O)<=3ZW>zf9@c&g)L?ekE#s3+9Q)dC%}*LrG!v)(TQ zy`tTv`R;>Ay)b6=svrq2)_SZRpX`DOwKlITm2uENyG7UAmV!8)rbA=oR0|VzN1U09 z#-aQ5r|KBp9-wGxkfHfJg?@M)qISsb2j-3Mg+w2Wz|dK(6ZhI0koDt57O?Nf5z2YCu^@dnX$mhtXA@ z{W3y!v1r(ilA!sm9of~h@U3iEfc<9uhzx37*muQL3A1#zF4NZgXr?ju4yJtWajg!Quf1<9#{z03xCP8Qa)u%%| zC0L<7iT<4*vHR&7-wBHy*fC1I@j$9|GiY(|Gh(r7MUmfMz1`>V8@6ejJs#kc4P%e* zyl1`M3VS?VJEO1yRJ%3#5*R+_fXSZyKXRAmklHJ;c=NZDD5;rctmEM@P>*oeo~W4s zR?51Lp{_8nPo`0c+d2tjB|gp1>K2h%htZ5_QZ3R=)|N)r6UgA{)&6k)CAi7g6ZrXC zJ4|o$yE{`*gDxayTSeQBqxo0FNBe_&Ky-A#Z+lk@w!I!Wo%pK|X$i8?IHh6*ey&Qq zxf3vlOeJ~PBJRv0K3LV4dqqKFVJ1|$V%z^(O#K1Ex3RX=mtLq{jx0hJ1J@p8?Xcyo7`DeU&JE!oi^*3zvIE`#3;&&jhlbQs$oPszVP-{36&;C%9?|Jt#UF z4xKsstBnVKUOJEnBB;;NnWnZl0w zUNUjeV+F3%<+$6@r%|rn)o^)iJFl24N71aZ3SxAWh0|q+kkDXkY0dmJI=tCseEi!8 zC{D0tPo2e%g+|_dom-iJ;?CG~M(rtd{ycwQ(-|yLX=ltwLx&~gM87MxfA=V)t}gvv zIgtZiVZmobwqu1OytADnr6(an$AP|5vK>m&a!8l#F&Mj`xZ)-4OC(lsX=F;Jrp0^>9M1%Otqz=oixIi^wCFow(XBID%DAm+N~Oh6`~BU z91~DyM%p8%U$wAFap+vm>q+GL;jr;U?=-aehi>e9I}KhA%@_5pv3A2YvoCTO`ryp) ziylYpdtP2xbxo2qhYr0o)nj)_Mx3WA#Xe}yAj1g-8&fqbd}x<<&`@zdTzsZ+O~Ude zlIJu`bDb$etcQ4e6|lC>=Xi~ml(6S@)E%ImQo*TiA?`oA6 z_N2l!YmV~!&WSoQEe|@O@!GLcxaW4X`R6mC(rcoHmtg!s$GUX7FgJ? zg?p;@Z-F8Bt?}U)kN+f;d1YO&9!^IL-RHKrr*@&Y9Qmxb-%J3VI?oB}q8xNB&q7kx zfr_M|B4x8FqZ{&>tQypMp9U zeGin~uZSa=^&(9g(M=3zs-ZSDdz^}U2^3hKGI7ZFgIIWLLk4!ddd+jZPxsjrYS~?A zb1G^KQJUWQ#+X!wm?!LvfBKKWbLYvg6tA1m9xwNbU3;oQXT%?j8As8(_UW5@DEm-O z8lQ|6^ArSu?ddll}TRoe@n2W`rq zzsZDhmjTv9YV3E)?ltSQS{>3HT2<<~Uw}sQ%MMK)qr&FmIn6ZCfjroX*$#JAp>9hh zt7`jXu4PSb=d{Ve?6bXyMXRYuQIM7>FQaa(6W9x! z>iP#VclN=v{9G}^wOOQhyK7IB;sDxogeanpJx86Iy0!Vj?kNbeFpxgxmIC6O9=(}I zCV?`zUpHjD4?9kMPr3Yd5i9IgR##d*j!vC&R}GFQ!Jt@T$p=;J`xe0_?RTjb4WGZS zUG}I0Sv*wXk%ar3F=LTE{+k@%i{!arp)i+O+XpSP2$Z(0oU`R}L#^ zRF`w)`Qu-3{DVepw{Z_j#ex-!cl`p6p_!?{!eSH>T1BD!g@VMcKH^-F)(TFHc?a6G z>Y+=a_eQqb9Qx&D&CH42M_Lc^`Bq<^Lq+}%ltzCfL1SXT#p6%vP;Z=002NCs3bT1} zw#$DCo?c%m*vm8xDl%h3B==^pZ^(K2qpJ~QTqD03g#U!B=~omJPo`nx73)!b+77hH zGR$fgHvvC?MqbLY7zR>Bp=!(ZDPX@DDDe7mHViQHKGzhiM7)7SGe*>eHU&17`TBOC z4|E4goOaY9#Sc~q6H1+^R?T$!`>#rLiFMbctA7ui?b?%dP9I#e2K?kLq4*bi+gd6tqQ`O_e0nxt8Cd!lq9ilx)<+8Q4s@Od?&TGP9R02@^Jxd-=iR8);GKH8{(#+x~4ri z50}G*2k$h_LWwNlni`=Wy%pMPzRzO{_B8PQZut5YT9k@f_+0u>{GkIr*RJNF@x#2C zOU9FE=Y>EuDyu%=`Ov?MYM4NJ$?fvYbQW7*3m>^Hu)7{fw4P3=-8X?2!ldfyvsRI% z!g!|U(@9i!`qA-A@fna`&@vr>t&ess)Eu2qZw4`BSMFOi4FSbWZ~d{tGVhfx3jTC! zg#yO$<&#*#@f)KMxnK)yU(sB!>tfarYTNvimBZQxWWrUvuA_Nm`gB;7WAhxMYvNy( zE$xEn!H+uc2Gikza>hxn+F4|lM~vR~c?FfPIVZ0k?gOq&Hz)V}TxfmdwaxRvIJ}L| zJV>>%7Wp?a4A&1w=Xex)5tS87+D%5qov40Y9W z@UiGI;CtVLlnibR=g-Xot80K=4Qna#lkM7CDANG?Hv1g&c!xoOtD&jYW*q$d%ZhI# z*C3kM%s0YP zd-&$#`-i|pqvee6_BLoA&egd6xe67pbWg)Rr#OScsOF26X)LDK}xv>ty{?HofNERZPTTtY}JFeY9{@DFI>fEg-g;=536R-Cf z+)B*{#Z@@T?O%@=@(lM-`^+P@^5=Y>HnjkIgQ&llk0bv3s@o5zC!^wKzp$2&IZ)N{ zOO&DLfWr+QROfAnVX!%7Iz6%z9q?up&*i2gx-uQMuM7HtB1Khgxo29Dkn}zwE}t4S zC%og8P3R;Fe7v$Kpc@BYG)^2cIz&%;%^;?zNtM*yzu^y#p_|vArDS8HI~QwRWjR zElB)@6;t4CtN@gpye!K*ESx{!M*fTTpWs!s1KDC}4h!WApWbesK|xe&Z*Q+;Ar332 zC#3E+XYfn~(DWIy3?4Nwx+)#nmuG7?|!pToCVG3++FAxOb0@q8azr{YFNe z@KCqI!V@b9nohN7m@3hX3Su6NzdSetfyegth7^Z`Y(b@*r7f1|fA@#Nmee$O@08Rt zN;Qg%Z!zD{tX)Qjbr`SMa&^NE*4sjiXb^qisB}|fs)wWAr3E!yBgooxhhu_NJ1kqj zgB>S2k;pBzqZQ{1(VGVIyDl`nSUS^)v^H@D6*+ReWsRRfET+CzS%i7iz9H#Hf_o@% zs>!>@__ZL1GI2xAlzKSc81vrLDi<_ge$IJ=?c*{0sy;U$({(yhubq@E0+m$nM~Z^uky1uvUkul*PWab>O3H#@L2Il3ByNtP*ytMqmk zfbXdL{41rlsuI}D9ur|;@fH>d)q^Y!jp)juz%MR5$q*ryF{xochO)MQ)H-}&8ig4@ zH8VWi1}~J}YUi>PK)y}jnv7Z(`lh($v53kfT5|t%RHA(eN*r3%Gw+b#h-O=41jRIJ z=6b-s>NyAf*({qL+O(sjosQcZsY&QNGnZK5+#K@Sq)vMNJOc$~eUq<}%0P{7!i16_ ztl+tczh?jA9Oy}%KbeUY(klD1<0a8H5+!(FjUwxZ8Td(a#Z8= zq;I1rP{*GbaB3Q6=$98y=Ztf-BF8&QdP@S7q{qD~%TDQ7n06bQpt_R;PZn-&F}IsR zA62;@)#*2ayIRu@h7D6NqNlJ}aC{EEy`joj^tcun1O}eQUn@Z#8i^-{U1#7Ym8GjP z^8(aH+-RGf8walo=11GC8h|3t{V@ghcQ$grK5?p~1G<+FZqUz2f(0)*uDQDlP*l#( z^j>`h?OWbB^bspG;Ur(FF4NZpXF@9JB41;LnU0<^k;4j&SBRw~rhB&`*TPeZ_ipw; zSFDth@w0IhviY)Cv|25wSoophLw&GWZs#ctQa|FWopS8*?MBN{JO-7rEoh8$hH^L6 z0Ln>;nD$?+g!@$TKSI1FK;VVXb7>JQJjsYjH2YE_>}pi}Ch{x+*-d#HxbajYot0Gs z$|Wp3-g(r*!+91Rdbp#)@H?Hi9T=|}Mo6^!WoGGVE_KN!*=ZGUGV8K z;!XnLpPc_9{?`jGy3x& z$$8{5&chM6|GP-;zn)C4|GV>$`{D9>h>wfg|6Q5f@89(&=i}q8hd3X{^?2*)$^F)o zasB@-;_rieoPSqO?vKmlRr;KQ6ClC)eXLIg*bINbbL$9_Qgm&Lh|3b{yBU z<9Zx%J~^&u$Mrap`~6)R_s5ak57*;}+t-tEJ&rh^9C7=4i1TqfE|Vi}$C2DlF5^5L z*RzxBaT)jfyNLVYNbdJ1J-Pkw$~cc4|1>|&$9d%PdU~9PBRLP(<4A5NmvJ7B>)HRL z$L%=cPNZpV2zlG||^M{*vnUl0FXK0Xe)A1>pF^Zs8UJ}x=_X?$`%xs3bc zdR!()+`b;-d~*Ar^tc^I+#i?MLvr5Vm2n=9?|cxE)7w9xne0$^F;klk>=B+z;2|xSpQez8-HqJ?@X=-{s+a9C1H##O*ke z+sS2|ha3oQKOe{#`$uw;tl-t%u}(I1ktVNyd5Pi2LD4ZYP)5 zz{%j9-kCP#AqdiM2rxE@E`|L@8;4@Yu;T#qAe z|GW4nKXUuum2n=9`1>K3as7Juf6M>7{x}au{QcnapKv`sxgM9valP^X#KY}>*MB`e zx&A+u*Ym^m&eF> zx0A~_AJ^kZuE*u|@Za?#=i}qzdUE``cASSJJ`OIEBe{J&8P~6e>y1m!$9e1NaXXId z@o+sk50}Z2oKJ3FPyUl1ZYM{4y!G_B9Y>sp%jAgLar{s1Rq|#}U_)Be{J&8Q0@TJ`TCO9uL>!NbZNr zxP3juc{t)cT*h%dJ#JqQ|K#^4J3cPXBS+khBW@>`aXpT>9Y=CKF0Y5U-+zjK8h1TA zt|y;&J^g>m`;*^#^O5WSB;)h^qjJapcEWy=#>3bAAKftm2?XJ=Nz%jW1XRIUeJB6I zHzZPghMO+42P(vuuCVQhfKXmB>0MujpvxoZnQac%S54y>-Is;WpvlJJE1I8yh@X#3 zt`*mT&OV#|;IT0*9k=+=8>ePO;tlg+y6=ec2X_v$3{Jsfub$7H#VMdKxY;lgn+v&F z6lLW$1*m@{t%<%W1^DN9f5m3Cpi4*JQr0E4!(PteocZAfVAr0@3~d@f_SzyZJ%9Eg zEp01}Q_S6nus6D^pfw$SP+V5w=jsGaAMGJQ?=IM(aN&4ja}&J0^Ne%PY6tND{v~;o zc^pU|_daae@fvL85|ebUcA=4bsR?#T9jKCmj>PTPjygSe!|Ul%R4J-HetED2jngz; z>A6&m2CEMdiqF(Q`z7}ny@rQ~#7Fqxq1BA+DK@(G+-^sN?A4?#c`P?ar+JsGrHz{MEVoZ_Hb_Gnan^hwjNSRq38s^ zULnTls(d6<+@Q{@l?8;v?sts+G00H)`^{^*gOG5(!7^*#2=L49e?XEQ1U6@?#V3Jb zaJ*c1mm5tJe6URpUdkCnc@ECy&;3eKxg3|(KCD{Uj@B#fvRGA`mG28_MmBvAoHIVd zY%~nQq2JVksegcaP^$5n=pi`St?WuUgY_+vnR2?kR137bB~OiDed$i_(m%DD)(%Q` zQ-YnhXRs~<(S;fZd*P0t2i2p4Sana9yK>jtDxsf}DM*y77iFd#)s)1l`61zbnU8<9 zgPF7OksXCY$h@qKcF$$3TAg#?>3qLl^v;9Qb>w9wDn4G}{9_Lm{<)!Yg`wsbQVCHBcc~pYRj$N@+#&hVBDi8Al)g(IG z5-qTOz6!-;gg-x!ISwL;mG0ceGeEj88svxdC(5)IWk@dWhSXdpJM$-v@bhiy;P8tH zAk0mP^*KF*C(jrzCrRd^drV<%!SrKrYTuDZn$iPku~R)-V5tvm6)JhPiQX`_N9jlG zKrcj$InWB#B2;xw=&EYkC`6p*C*`G8q4ViS1w-lEfpvDZKK?-;Oslzlc~eS49L=jS zU!1Y3Nc-yjdfZLP)&SR_Y$ab?8_x;65IO;h~G8X&_GPGCUc!o_P)AILcUcYXK z{WV%S3!fU$2i|>%H?$UMDtcXQmimJ1Sxz)2nPPp=6Pbl5uqvUvGVCq)J*tqFgD+dQ zCDw<%UWFhX`2(Ga-8U%up6!fU|`GeVgt~!fd?rn+;f4WYc`;pgopmRsZ?ttL9KFC$z4O6u*e+(_<%~KJDM)tWr2bE=3Y+cR{>uX}zeB_J!^T8ZJaK>a zV_h};ABxVyk?QY_<0>?431x(k)l$fONQo#jtFNLIg@{N+Np?t)j4~n_*(3Yddtc+) zT-RRLrujR+|DaFTIp=xa&-;15Rw=rXObRpLG(9vrva=1FjFPLBU6>CQ8X#qTdJ`)4 zn;5)%j8hm#FBXfx}dYfuR^B${nEJFVh2iz2<^S%*aTGSJAxKG9I;dyq4d@T*%+&7FUcO zmZR$ml_y$A6mWSWvbAz@2-f$+&rhWHgM|v0<3Fc9#K%kNm$IM4?rLF|@ycOPd46b3 zB>~$_A4v22er<+tc47x2MKI4)LnfQ?$SPj%F78_BX#?K6z+`*1Ch#9s>GBe;fRj3T za$kB#@QasjD9(on8MErIk4g7|C!4_GneIVgJn3cC#?}t@zRqPF0^=y=V9JB}cFa$X z4fQ_KOF+(Nv^ zX{(|COi(T|cjG^p>sXAsFk{D!X#yM${F?o3+X@Th9 zdBD$px0x=!1J=k3VA3-K4lijxUA0dHp5ukHd;R-hfalnKA(dQR5fR zxzB>S?fi7`!wy8lLPKG>NPwF!BW zDt7k1nudq0R(|;&{ji~adq+%y4Abc(x!$9-@v5WIy>sPPz zWLGnA<`nEVGs3)U-l)48VtvS9Ms_weYZQ&mFLh>j&Y+t^>fG;nyAc0b;z>J>T$INp z{rS*|Nt7SqMgL zk-@1-Wwn-3bcy#4lhENR=v%I(@zcdIGqgLr#BLItB)(tytTqluWCJvd45nd2uO{do z8S^-!&V4$F`H*Rs%Ri^53;5s^KuAa_7oUl+}SHV)o(DI1=n1Emw2untR%fjISyO z;c38=#rtwNc7TOw1vx#SpFpy`w2UbhHXcn9@e`<=Y4YvcLu()s5Orqs6$z+Jcd1l* z6`>M&zMuQWS0U@Tra1A*5`-=u3o?(xDU?_5%jOw1pxeAUm#jL+!KuczmZUKYug_g) zyGSC!>7P+VRna)a%YSdau&5u(IF3htNohm&=hCw1ww92wHLHKnnN+a!H8?}_+PM?6r(Pc%fwV_vem@QeaL{;mwD8L#Tn(>FjlzVffU^@$%NhG`xJ*-7%xK zj_&cV*oGIhAb$G&ve7t}WwCZ&(lx#c_>6hbH}TrBO;tpPE$h(2_FAyYbJYY_#HD9CpDEP+ekPIAiN402A&S5A)-I@*Qr(G=i* z^sci2$BmpcWR>PFFGO8qHo}1%nEoNi5<-n^iCQwguxigGKr_r(#xLuY^A z-s(2AWFZlG{!a@eYM*V-HZMd;jDqH3bwwzi=~bzPE2hl-iBb1CmV-E7k)K^L#A{pz z(Gz=vFkRv0n+GiI+prq=GPr1t2uUdg{OJwJsE6>a*eYTO9`r)CD{}>6w2HbDBcF?o ztL`AhrB1lLE8G7Ip&RTa<6?^Zs)3p(h^xqR3by|&sju2}zy+(1qtf0)$hFAZXuUp$ z7*lUYM4szMBO03-L-_amAsxmpSUmt#r$r?j!_T9KXBPJ-Crrc1`(4sA2Pv2)_Ezn_ zNe759oNaefqksgdk`yOehyIb$#cH&B(P=JTf-60aoe~W*6<8TZ`vNkq8*NM?k0bwy z?XmQQi}8lt%J}zmB-3#8{Od*PJ&B<+T{F;-C_w39AA;c1weyC4^U#zbBbIdzQ>*j? z`;rT)AYkqV`?KO{xGKKn(jYevCWR;b9N$hLqpT1a)UgyR&O8-@=P(_^)u}ur_-i%b4A#8s zWL!_}IX%dM)1d42ats6SHIi}`b9R+SPtah=s)=I*cNUJo@L z=ApgRI8C3j>|{}q1HhqH%PC2M)%^FAS`IQqG+o{o9YO%oz;Sx#9bAXa?HJDMc!O%M zNR}9D2d+EVGg;CKPcvEgUj;CQaywr zP-9vRL?_pQ|HnoglMm*;?{zpfdan(IpUW%qbzK8bftV??`U&6@mJaS1E}5=G8wu(0YdM0-{A&KTRM4R z>>^t&Qrr`}_Ca$7!rxi0O5UG9yP6CwS&5S{W^_k$;$b}M-SxaAnuiPvS!ov;AC|*N zZ{A@Ia}r4GTH36^>);hW^>0_b3z3H>x!UT|W02Lho1?$B3K`Zjs&@%JaGbY=f3u_? zS@u}T9B8Wn_k)iW=EM7u#IYi438n$q?_;FuNFbn}iMD;t7p8&UDe7D@=77Ficomc6 ziqq~LXx)3iuS2Ywcl^+eSx`8;OTMHm1$55$?5Em_1`R9Y(!)xf=>C&-`)s_X^4+)- zIA9FZT5d;OEdGSDbPeB6*_FU8U;Zqro;ol-Uo4uEJ_ORGzqEOy7eLu>In4+2Q7>qH z?vUHH4j)h^_x1ciIJ?x&mu!#w0afvKI)iNVXiFm`#23foFlfBey;u$5qGGN0ddR?d zQ}!+uFByExAIn*|PCydjDUG22BDfATEW|`&ejQH|)r;R`u;o#{^9hYWNThx%DIyiv zd(^6R{YKFHh0Gs+6>^YZMvhiV(ikG(W#Jlpei^jtqkGvXsH=L{uNtKi#CpQ#M@wxT zv{|BMW7L4e^}_}{zYT-BQ@1ncW+AHD6@OIx<01;r+rup*I)dV;L_CXLXG5x_J9)T# z4E1V~AAdfZgGwC5n*t}specgt>glFAtS8jkHj;b5r29i+D_(z9ePNp|t7_NH%| z+mN)frtp)1B}8R$=Iq+VTd05e;7UZzBFc=otuW$Pg>HNp40x?N2&U2Zev`CAd4DNhh_E7Et z3g4|WM>GdellX-5Few_HBhe9f&$OTq+wznA<^wR1v~JO2-2tgy^|2FJ!oY5GZ z-)poAWX6N0lfOpbruMP@gGS9@AnD9v7FhzEdtT{u4$Xk{XrF8$M;+>ld7+WcKM7M? zHIg~h(}<#9MoTA;<3W;~2W8#MVZX|xh=|H0dappVidUHex%1jt+?t7aZJW#cz_A51 zK$%3gTnmW8&K`K+Tm};2qt0x2O-5-qzWI4P?LnK=ziv;L6M(*a=aJSr1#!PWmd_nH zij;2n8XASQ!1_pr<>#^vc=ByvLlW1woD(hDRfnRX_+rAcsZ0~P;_%G#m}?)f4fDBJ zTQ9@>jfY3GCl?@jq_>A~5XY|E72Esv-x`R&x+3`H`vka2FvqwD&O(tvnEXMhCg5uE zxa!W`hVlqfnR;9$sC4SYomHjOhq~B$FR^BFoBe1P68P`JmJK+bMku#{mQt~z5dM^518+6e|V-5NLp}Cb< zJcG1+dd-t|R?xMqdp8JwYEa@miyTpdDG+k{s5&i7f~Czy-DiXSz)5(s$@*gvnCgDc zt5vmwr}dk~0|Hy{fLohCc6bA9yT}Q`Ha{S^>Hf?4_BpuwhnEJZ#?cGu%m4Lp4L~Qo z!Sf|)GO~2le9p00f=+n`w(S2wfGh8PcZ8-p(Uq#b4E8sP;5l}J>~9y5gD6S zOoM9rq<7`QChR-@cFR1u2)|Q?Vr?{wAh{CylgDQq_@W60mstqN*qbLi=GG5nypOPl zU$+{VdS88cHI4h|TK`bpP#j+q%f9&E(FL%S3_9)7MTW60lb)MnSa%dG5_{M;gPIjr zrRkq^;Pdu;tc`sTyv2eCDwyXWBE)Xz215rd(ATCmQxhOc&peMQa2d$a{zPiD4Ya<` zYBxFOfF{amf_L{OaC&@tCS-xoO&Z1hi~@;ZIh*5IEQ8Pgb23d2M?FZE9cp#w#B_#( zJbOCa2rx%A^MG!25#j=gQnxYPt!+KvrqYWo;Ps6-k|eYa@0#ZJ)H<%9No%?^>ZD2} zH684^@@oWfKaA%$Vk4lGq`r-d?gi*BYiioVGc|~NC30@UV;KBX7^V9jcB7GQjb!T^ zL=Y*IIiZi^bvmDJdo`pGVC-oCuPj|Z%!qaI_)L@FU4ih0KjKYrsU*bT{qZbhQFdv? zVOmkgLyKPw*<8*xiH=9UIs|n`5ey8#-8K=Il zFX+qnqcQ>JFQk$J6r!B7zvS*0xbuBy$`Bd3)fa~j8l05m0Q|GC(u7mX5+OWVp{L|&KUDJ@K2c%&uaHV z@o1<0TZU1@{Up$!y<`l?DZ$ZS@!TMo+0Em!XafqBpIWNXt%D{j*62C)aS*S4c+~wz zJu;IF-FM&=*0(J7O}GkB;4d*={C?O37_j_Z`X$?l`=Aas*ZE=O5fWgp``-f0ib}gP z;uy9f@}Vc}y%Weo%|buRbqJVEa}vUrYGLyJH2bRTGDLLbh<9AU|K57>;Hy|)JK2Pm z!fEHB)ZtHArA{LxX+BW9{GI{|qf=-6y8Dn=Lsr4{&|WxONcAy~egLkWUGo=tHjUS( zRTtz-5)r>lL2%~Y8gzkm7_m8(6!b+<#lxqvQBdBR^Xih zKP&U*g-`A9I?*`qsvFkXo(~_c;u?mp=>c;LjH_tuq^`x@JyXz7U7!8TZyecGD}Qs_ zUyqs`O6H9^s}L(E$pnWeA!8hU=x5BeDBr6CkY;NdXB9mF%StEio_IP8PJ0f& zxg>_;Ztt6ksA z@y8uMvOB>;~B`Q$hLUZnlwO?XwnD&%~l_ETu>1WEDLm*{dWUUx1P3sxP6 zn77Bi8u5)oPtN^|L2tXD#BJGyQ405Chqc)RwMh_JsWcitLqt_~|6J;=$Of-(t;9FZ zbMPP~PH^OMJ&0wMD}BB?iRENrd^IC!a1(9tasar(T&k1&kK`eXyA6~ zJ*`v&T0CASu zSPERnboFxXy~QSaLuj%t?ftw^Bi75F9^CtG2O|HHhrW?|!9ggCeXs8Z>_c|zRRd#4 z!}R*qt3yK&jxzbux>k{ni|}~~jUVVd!Mw!rC<$EHiIZD}9Y{>lC$C%cJG$BYFJ5-i-bN_XJjku6oYpKIhsg6GBJJ)K;B(7_NX6EMbT3-uY~Jle;TIDGQ?AdU z2hp2zVXwN;&AzwEMB8LYe0R62J*^TwQ?`jet4M(V1|?af&kdoMX76ZN+m0cGNazn#=^4Abqf1Hy)FNGT=Z;~k|<@Zcc`-^geK`#)R!_4Ly? z9-42*x@;ANDa35P_93Avopq}_xL>tBvP3#{t^x*VnraNPaBTL~dxqJ2$H8SI&}poH z7>ufXI-}#afbETLnI}UfD1eaE7HuvB+Wkt5acqE(yF@C2s-{5YMcw=tlT~QgaDxvs z?dZ#;Om*V9VOV;qUO-t|0rjKe#zwbtLD2Ei5wEvWl|MC1YfM@%x1f1p=;kS|Gl?+ zQ7EHt^5%FCocDcn%5z^A{I=EaoHVEc>ak5D!l5|mkZ(}+D;)y)&DwN-t8uvaq(c1G z+Bls4?A3i;DHfK;*yuyIZZ1NU z+0unX?H=@oA&vXVzcJu)d9d6v(t$!-9$&3j!u@R{eMGGkj!8H#!hQ7d0H&?zG#jSgP}m34L-!YMLpef;In3XVxA9L{2iew~CCY+co} ze&m3Pey1MJsD(Wa8+X<3&jTfZ@6QWN#}O^G%vz3V0_LX%A1?4`Kyr8=zi!ha?4Pav z@8e`Iw4E)brIOiz1`QLU_4WeLN({1$f1QSi_uhjCk4^%&MoQDS>-lg=;H!!nj@h}$ z!K=4+;s?@NkmD+A&w?OUrEhZsohVs@ZLLX;gs#62{Bmrd3xcfQv=&*<<2i}(!w9`q z_~XB5_x?BuZuvFTJpDS2yx1E`V>ee}kBKeY?NLluS6mSqf7lAU(>+v2%gd$^6;1N? ze*v#Rl-a2&!E^|oUH|nxH@X@+s*l9m^o&D9&0ozro+9YJ^TB>oIv0J-S@!2VI1i%Q z0l!m{I*{u4P)P*GEP9ezoW|CS`zOPX#iSib2+|iA zX6u2WeA8s%gg&%KgDK6?a~_R-G^tYZ4MB12(h9fFE`fU(b(_FU2Z+c1-6a}6fK+_b zY1ldzK`_14rsv`c_?(!J8I@Xs^9*<5<-V05WkaERdxX>B@eyC;(^NH(ru6BNaue3a zz|UJq_7fs{t0t$nQgUJlFfl8Z-f(yo?k!$nGW^m4X4bz$5}j5-<=8~zh3Nq_az~f{BN7H;8zy zax-z2q62rb(_i-Wz_ZC}t*B2uh?{AFBcF-@LDz|nXDI7XDxLSWe|#L0-L?YLbH9Nw zm6?@r0ulMXWU{tC+JQVCE4+SxxfD^pZnb^modvf}vfT&Hb?_GIb8l(r0L86nIh=Tb z>Sx2Uere!H+0=FK63PZ-TJ`x~=-!00>cu1bzK?5s(*A^e|+;L08f(n(c6vT<=33d~+bTgMW>%wRdCoNg9%)yc0X(NfSJ)2E@VZ3URp zRzsjVHUav^&ewy#lOdVQ72X^CfOxtu&ENTI;JJ>!d)0eP3wtoBSkSr%N81_ZgYObR z@V^(tosk9b3gzmm3hzSQk@>P3jWZDZXKR1ts}^9s!8E`b_6=o^f3f8&?FYWJ>Q47L z9A6ka@$kp_X;27jN>{F!fSXT->%N$eLt&4cejcG0>uNH0SR6^v^e>$~oO=qqT;5gq zg=5K(^C1}AqijuBHy{El6kF?mub6ECPp@x#e z)Gt`?yg9^SO~@$#ufT-2GAA04j!mK9Q#OxYrjyaWqkAMM8YyrzZdKtXo`{|MXrw;$ri9#sZ2Z2_~L@cPEz zY;;D#`2BJEVYI?Ka_ala5b%6eZoF?b0jpN6@edbh{@_+3wzf)}7fm zjGqlaX4#OUvFkL{MeNf0ToMOob4xR8655gUAMx8qnnn>l{!G)dZb%T`rFkWI4((GM zr^|8dfbhGDdJX-PFfe{$!)bLLCJ%U>x`};C`*`&P=A$sB_L$WbLrf)?@|;Vsy)zG8 zJExW(P2gBc??j24s)6v}Wa*woo=)VjNb+c6-GQ(7K5E~q8H2~W7k)&YoCAgOdx5eK zuznARw0Ut%Zszt@Ub)d01YGmbiRfQM-P|Q=$1}pwwf(f44t@l%((V{v`P~e+I4%GD zT^|F%*wg1foUB913S8|{10?W%o#8tDY#dn*)(xqoPU5~>Td(0UuS)rgSMxg3V0v=a?@DRNtvTl@M+~r+eg5&O}Zk)qBFH)9xkmgQz1EHdzsBK-Z4Rh?kwE1RU5Fxa>g3>)P4H{awBB;+0GU=b)1!EP z8{FSpoM+Pq@^;^24OwyA`64rY1Z^3JL?yZVP`aQXiQ>Z&N`h`49T}|~%izgjnJDsp z9^yo|l=NjvK;*{GsQU^5wrjfRY<0$f&{&?Fynh^+^XLj6e;-5rZiE(Iu2smEf0f>K z0>`VKY6>v7nuq$Rzb#I<@4BAG6&!NzyDAS$lgqp8Xa8?p2*;NbSI);wPi=Iis>iPmw*rfVO;ZXDxo@`M7Sd?tXq z`QXW*?osftld37?9{|$ppv7kVJ?S3W!fC=3VC>#Yr!Kbu4uof7GI+kpc=dX%__YcY zPBXn0U_?YOX%k+MH5Y*~Ye_+cx&h2hj~$-vPeMuE_n53-6X9IO<4a?)IdEHXYzX?8$0(2x_(%WRVolr`GC>eU33fRIn7#ZR{Q|Ewq`TV zG(|)T&pmeJ@f_w};&6+^fi5JsTK^z>KaTxd>Akg3JBDtbz7ZE~Pe$|RZ+~T8nuDbc z+Jwq4GvMY>bZie-F|2zO4-1tKLk00!T(L|lBtAYk5Pf|NN*nHQt_sb=_ZeFeS-J{z zARu(38sGDAE44zRcwV(}<-)^v@gsOHq|5p6`wG(4xSLkFfpvkIK>tJz3R-7O{UrCk z2PuxtM?bnV2SF<5y{QoaXw{xBSG5g6cG5`rvcx}-w|Meh+l&aOEI;?tHjp6f!}ZfH z5v8E;dCM`ij7oV&a>A~_hzPG7y%|na;+VPnzj8*{dx81X`nyMAz3^l5-XoS7T-Oj& za&kmRV65Po7t3Te@X;KVn%H&&`b^une>Sbaaiq)Z2Cmbx^t%e@6nxN6dv$M#2Vc<; z@0F_?rx#J!UAIS0w%=CZ|n4a)5uwd$vBLDpvuB(TR+ zqxsNh1&_K1P-+HU>h;xb;CnE6Z?=32y*h4uVf8Krlpm^;W#^|L1BTQ4S#-wHmc?NS zo1bGymgaq(J?|{aDc(dLJlWtGA;*5rsS!E!oTJNBO#~CZ+<5)WZU8yj{a)cSs3D8) zWh&1YQeD?hT-}-k!wx3GVO{+DFi{KM#(0t%&hDQXt+mMU=w7q%-Nn#R5Hcu7Xo2K1 zqrT?q4j_+JW|iDqf!J@JZ1dO`Sa{>Fz+0@R2RL8IF43O@p63qq*+Q%E!e-8Q1?#VD zf{MPm2WO$}@^Ae<0|Mfs_A_&hH%Eb&6%-rgTVOlU)Z3^h7HJHqNPB0lAU-)%a^`0< zh+KJ8bR?)6CDAGe)+J(G71`}fJN*D+EIT#t6~BP~)|+X3)oq8edD`CG`W29Uoe{n| zxCP&@(#gD-sXzj1Cm2dEP~g84FJ5?1#X+gqt=BraxKE|<$@d(`@8Ok&KS4#Us9$A% zH?e&jGA_t16C84pTNO*N7Cx8R$^~>Ue)S;*@%g9}93Qy5^ppKrZR{J?n#rh1n1$r& z&$3cw707h<=HKjrVI(u}iSXvAQy-m)U%z$rKNv)NeoDx;TY~TpFj6*8NfWMgF&)vNb42 zt(+sucMNRujbcBwjv(c%qvB^uO3{nU@^iV73-EKl8UK~QArKwW34OFW1D0H&cFRR% zC;vd3?(}2{93C)t6ydZy3%S<$ZE`|xT;wYYQ4YWE`aelG$z-a<@%w{HpjG* zFb~Qkl%E4Nz(ZXnw>t#WX`KzP9I&hfrE1GD-HLfQ`=gXs{QrIC%hxa46_b!~ZcElh z=SEZ)#xo-qPy&4PoRMEI=pq8c)U8a%Aw+aP5fXiR4gH~O4WX}HgO9IFYIrPWphVvG zM;?y5Fa7M@u%7xFDLmM$9{Ae}yypgHjAjNPXW`)<>X%)haM6zPezp>Rwb{$$D2+jw z;Lo&7tXJhT(u{t;G=;t%bj-A-$ML|A(qf*v)PX>*MqY(3)@==WqE0O4p_6P6OaxR1 zQJ91;$Mnb?Fxy1W^ZeZe`nvB=`zaVxQXd-JdAA3+z3hFp*a?W^@zAfPx5MDPW8W23 zREgq4o*Yz3N`tkzrDqF|Mo`PkDn1p*N%(3h&-IcIV|MO{Qrl>3L1o4FV?qB-0UsRD zyS5&M9{Lpi+21pedLpADA#DjXuW$~0xjBc@zILZ^Y`1}p!_D%@GZb{M zL%*IwcMZ=aa=R~fkZ`Q=N~y#5Z)lJ4=cB2S6qGKvciE3H4rBD!{V1x*z$n$emF+PL z6S6ZTcjg(eqrb0P>xlbFuEAR_3F#oX8n&b{G7QO&o(&8i$%A3#9=_XD2}p5SAnsgi z4=QNai8-M>3uA9JgSe}55x1U1!|#d#Acj!Onnuh*=z~`lmc&``JNfq?#eNhh<@ddV z??$6Q`7%2p>`%_1(HTIlAAR`CQnjO$`|udt=tksvoEfY74vpMP#)KV25dy;=dE*Cf?vxqPD;cyva&=h5~U z^yTnhz4(}b{+zoRKgV7RIySm>cXm3#NGaX1<^B=~6!1Su-K0{kn_4(;RWk)*T*ZRS zIF1+f{x|l|bRJ1NSk+#AJPuw;=by_Qok3KZH^!d))dOe0z*l>Z6Hr5bp@sny?gy%z zY_9sP!qHCpy70>rkV7z@ao6Za=juX3pJ3m$>DSQRw<!rlt3&Ja8T&28!Amd2szB z;h=5*D;B_XbaAEohpK%BEMnj z`Y!my-#A)+yA5Nl`h(msecLm4?R7*Q_LVYx6Ci8XfFDI5qAOz!A{_apiz}8O$KYXE z)BGef31^=E{3HS86gaTM6gs%zLpH zuHyLmnQ;*5n;%~}GL7PO`c1q(e@3^9rQhnBkkPqZ!FMK;!zkjf`JtB`?-2i^mJ)%8 zam3vr-**#DphL;!gO!D2*uV9j4bmEr$E>&f{*^IsxMzL)Wa)68%3OvfG)A%? zsth3|UkSarvs3W<-@LnM8yO65JD0KX&%spl>5VMxV;#HXe)o;W7vy*Jtg=OQG87%; zx4N2-`*Fh%Iir$AG}XS4wO48szN%*Q6^M{Qw^MFv#i$Loj%CDco36k;>QlQX8Tufk zis6I_{(iGnigqQ-G*~Ls>oT3H<#j(f$YfFHiE!u@SUu z(CrBimook?h!qV_V0B(YtD+TYU*cO}$l^wpH^%ho?h2?Wj-N&rO8G8aCu@ z(QIU}D75{pz5v=R#(AQ+iqNy;`6XqGV{oTx_b%Du5vbZQd_%jr3`;zsVy`at0!1R} zGV@ImP!f*Pa=#&?+v4s~efE7oW{A9SW^oPweKg)Bzn=ugeZet%{#ysm$1`5q7f`YO;H<&*l81vq?;>bC5S8yg9W#3oKnn%M91s(1wQ`pX7m$V0qNT@dwis zXubHu`(t(nWMqU6*}p7C`-nrK=R7HR4i#*6j$;Z2EaZ(7J=Y*`gs2b~wgQF6nvS?v zF2J+Dv!%C46Hw90bWeT^>m-?V|$_{78G* z63?T9FFljxdN+Uy1)W9)covWwRmu&s-<6PcMZ(2^F&FL6+OYhs+6d}XB>)XQ*dr@6ri7)A5A8MU$6}eo5Y4j($CjZWL!&8=$C$Z*zAVPE4 zx!xuZO^I3Fyo`1InQw%|+lMBBp8CAO4RcIsZz&00%PdAzrI$w9MN3hieVAQF*bwTt zaX{wRmoS7}9zBownhWK3SXF=JkLY_?2m6tp!M^jMZ@OEY?xqnntA3CSdFxYwz)WVkET2bHDXdKq879kB{QD zXh4spCXD>TurGoVV9mhS3OX5n&)AP)eCPJuKDi_5(3B#n?iMi!*1zvEIgxvi#l|G_ z?8Yzz7QcL@C!31$O*lR%eO*LuQh#~O4Lc#xveGAqs~JLS5>w(Q3L&D+OmWm7`-XmB z$)`)JN4Z9c@%B4RH4diyM6Zd|Ap+39rlTHd$X3wcbwU_Hpf+~8T!T<0ZhDY=8EPStK#RBd(jz?LY=NyBpl-*KQ!dOSL);#GG zwgepsEgTt?C72oajmhBdK&+2_-1xI+kqY}N&t3-#N^A~DY8e|qCl6{p6~?~sC`s`w zZ%QsYPq&@V-m!ux_qv9haLjY?u7r1i)H`Tv=AFc`e5})ld+qThPD84E5u+KNH`0~_ z*NbX3pg(7IIJIxhp_@?;CKnfb&~x{@I%-$q(fV8e*x0+1=)pipMx${%qISG>5>Hs5 z+f-gcV7Uh!=BJ#|A02~TqR%IZ&1)#EzLMrs=PX>C=AR6#jYl3)>x(g8{NRl__tEOx z{U}RaN|DH2i30j7JyY1o;9!z_>$i#%;t{Dh_DYum4e1`L5;R%JY`2W@p^+K*^Z2XO z;>bss(wMOgc+-KdwS=mP$4(>511A#(u)l|v^1Q}YU;vc+I!mr}X2Awk~_ZQv9vwDhh9?H>S(k1U$Q3VCpG&#jLKU3=hRnAM@1RdaBqcmtjNw+LTDFU5bv z?^KPOoR}eD34+tNW&h|+LW8SgscTp>B=TjI*}cLs_i3M+s<=0>-&b+V9Q#Vd&*gVp zj`RVga%uL&$tY01(jynO(*XP-bv3qqlkoguxm@(MO)zFWGD00)iG+j$ot{6Lg(~X1 zRrAj=CfVvl(wgcFZ2CS>pYz#cYm`9t-@Se}tEV?4k2{<*>LVDdWhy>2t^_JafLk0e%=Hqo! zz;NR7hHQ2%cxEMfU3c0*0bEu-**au&hx4`WKAj#UEX0wNF*O5^g9__g^9GUJ#Z)m#IEZfnA@k zJKL?{J-ZVuPJhq+hGiM2yA~L`p&0RrZMu35zMEL?joB%NRlW%i&HEUy`uJ}J9rita zzZdIN>D>-*qVK=xGsIrM%J(MD^E1G^ucVXhR36C0i{1G2luDT*Xm9lEN(yk>mkc;^dA0!^=lC$MN;QxEc@!B(IW$2b^ePu&e+3vQ zd{o;RKx9k7m^PnI)H|Q>rh;J%7z(HFC%v8o$|Xx9hstBBoKBz_?lg~54sWMA&2BN ze#c{m9&K#E_k!FgzvgL>>wVVOzq$gNy^>~6tY^{Udz#;H0LS4US*mQ6tb=n&ia|He z^dY_O@!5j%LHIQH>hUAC6|`_>%E<`Ni%yakww8_$gVy6q#d>#EfZFQ)w&Obr96Q1M zpNIYgsGOvADOM-Jg4wwF!aEW$?#k)>+S!DztB0vyYHb5^{(I-M?dRd4uh%mns#$n0 z7{ngMNrCuu$*ME>o_+PbzwZ`vFN~)u`n@R(K@5%E{RO?9=s}{Mwh)eS64bi$qUT-fp$+78sTXvvvDUrA3j(@E2)L9A!tLIwrb zTV1~@B&HxFuu?h9p#`j`w*RBqT!-I=HxjG0CSkXJZmY|$2~;RNW-#bZf|5V<%jYI4 zAiuDzEy4u*z6-rnTs};I-u37CEPJvLy4*qdRuKiu^;4V47-ydAZStA<;~d7pHPVgz z7(mZ0PsokGst4(36NhZt2f&m|%~T*3`|B@dvcE1!2ewuhUNu}_>u=n1ri;b;4(gJEKt?j26*BZ0Tds!+W1r`;5-ylaV za}HjseCWa0B*y|LMfqQFXTbW7F8c_^aoqm$oRa`e7LLQBZBt0i^z7&Pi=U9;rI*PG zjzqK+b}4Hd>l0G1u1tt=^n%FDX@VKY3Vf-|I5>QZ0^g+M&K9z+f#2hPy=M-!$dITR zzHUAP!hQif0l~OWzEZx^eyI!z#7Acz8pe8Q9kFIK{5P<&Wzz`n$LD0v7RNEiUQnME z2!7YT06)A0KAUAs0@adjRPIkB6p)dcl<{)`!Ve~pc`%Nn?}psdGLLz9eoS+dld&5v zXzx4qKDZ0l&kWZ~m8rR_gQUZOnfQ~7 zaHc#b@?p{_LQgNtv5R#>YR1;H?MNc_yUgyk!T7DWKaP9awXcEoRRX*8G64?yUhEJ( z_Y0WUCw3C?etOv68WAJxLm<_%$gcjJ1(9;&(;+2uh`PQ#!~b+Cs`(|AzSPnI*K+sC z-o+T^*SG5XV>ZZ03`k*=f2^ zC`c|nr--q`dg(2H`{`!k`^F8QuRlt`y6fQAU+l#|V&7E|#nXrcyxaYRXu83p<}&n1 zE})y-rOdUrCeZAwi}cfR6jZ7wa_{K-A>`)ws${2Q1uBxulk=2g;of1npPgnTR1o{) zTeTj>V7Ik+oK?<5n+8hXd`-q+XxA&aH%kN^zXg8t&3WvT`xd@`4eOFcJ?<6z@P4WF z=Yh`OBt&Ij8*|1r3;E^k+)Nv;Ll>7bt{Pw;v$aacN=$zzN<5Rv;)VSir*Ab;Md)9lc&i8U5Zk{0B=d(v$R?T=^f z%)B>@e*C+cY2!~oangOen4-s_jwsFGzo#0d_GhG%M&{wfQt*{jMeKjAG-S+q@&)6c zxq9v#nSjC!H43d}F7k-EcBD4$K6>FwxlCO;56lD<^+1&flgf)st|oox-0z?dYNp93 z%escP!LbWvnHjh1Kf^vfgY*MOACq8+dh)Dyb0;E3#5_CV(ga>iZl5Awufo#~Bi`U< zZ=^kS{H$_38O0m@ypt?kkCb(iiie%~?)6DMz<%1h{kFvKQcDqWu z=zBxxPfZ@9DBc%Q_S1aocjh@7BDAHrhb^FRr5hqjZz!NIY$oZ)GJ{ms7WEG`RYL`H zyGHThL1Zexqb_Sm2D>}%!e5^+g4O1W8vEm&;E;cdmR0*3nEGg~%cKq=@6W95dV5H) zOm+N(v|tBnykXYboZ1IopZ-KXyWI_s^;Q=yxz&L0r~8Y`*ayRwROpqsl7o~kbZ5J+ zjG(NRNP4B3B}Ae;VD0!jhk_+(_tRRE5M?~=R=!#cVla*qj+5#^suLepcKeM(*wOOw z?=l4VBPi86gE7yP?A?2LC9_b)bB5dhxaVQ0N7`|{Z3V{qt<0a6dqT|5)Hn(K9Hi~J z{ox^T5)z(%*?sp;C=^K1Cmi7Kzz|xltV1re=Y>dYm0-a4KA(OI z_g^fme0DYsaL}An;M&jt;%=zh)y^M@bheaJWffM@{X;P&g4}ptN-uZXczp;Ihh7^9 zJK=p9eb%fRgz<~IuL+M{PJnO3x`?{MH0ogQ{_)jv02R$q&#K}5UUvqQprt&FRozqm zqEs>ssOdR&AH=%-k;qrZ2fH@lsq5!thmJAetojo$GFS?77GbW})+xX)OxJJOF^goU z$G>fH55sehw=An+TM*j0<>nzj37TRDH!?Q2LD}8dGpgk~TD;Ch^h}urtKt(b8%!gh zs%Pz1$T$V3H)?c*_-nu_Zt8y&oo76j?;FO2N~w?;Qb{NckwQ4}D@j6DNF^CXRwzV> z5QS_)wkUgMUH0C4d+pYL|_ZVlz`LADMY07pb4Ja?vib5e| z3CxGCPtdQ|pf$m>HwE?Q;kAFk`r{*OKzlUnx=`FCuvGoI-v4+FhB_Wuj-HqVR?8b% z5V-`&;kw-6OE`bO8g*PSwi~=o>mIVoB0@Lwu0IXt^NZHA46A|%Q0tV%u^fx9@PhyA z%HfiXEK;zMaHTn!Gu95^_xAd*%xE9MrNrejEp%)Ht2zbZ0>L&|Q&3mF2+5 z{a!9Lj|9z699-(JkHASInTYdIt*BjJ%|fJU94;-%KWM$a4Yh48G91q;(boIK%`&nNcpu!+j-o7uJtHPb&v%$Z=YHs7wr>M2ck|Qf6Kas5YeO6b zp&9KRVo2mMs0W9p4+8X5c;Cgl`H)~X1_vH?j@bX-|H45h$g|%BM2W~QA-4*#8IGJD z*qDckDAskRZ35K1I_qm1Hi}qMR)*x{Cy{shRqjm@^aNc z^MeM4N2@bPwy$7=$?7+Hq+x3+7~Fw8LybBG@V@`nnJ4q&IA8BlKP$ukm4N2V?Hk!~ zZ6w*!)qSlM!jNw^lIr;141_8;TDs%&HIa+&0ht7zlkzSnM$(D$Wy%7%y_pM9UGoHaVV?+DMwWc=Nk-x zl5F4siqp8Z{S7~v?3*D7thLb)>sx~30*Av4uWccWrP8NA@kOs>I|mdq$H4g=qshCc z+mN_T8UG^?^HNK)qrY&zc_roFQ|G}7jBF1 zTT5RB3y{N{_PL9<*MRWE%uv)T7VV4EV$6Hc2T?_ehu#_YpuxH0v41Rn!&2mU8rDobpf3rZ&+h6S^}N2k2Kc|YSGXkKEW)@HsH@QyPEL24LR{9ttym}khhNX zm>A}Q#dvO>`L>36(p&$0FJpyYQSI$O-KUJ?0nssZyF{zhEm36qFy?v~gXp7Vr@ zxP&`4k3x-y_Nbuo3gjo0Q&K)EgMeQeWXTlGkjfmMkzGEC8WgEx*~G?CW+>B7)6H&V zcY*ez<(nzQ&2W2KreqLRrbS*(xl;@Ri)v4_{n~-ufKjl`CmPp%dW*VU>;)R5sY0ud zW2l!HeC^+-VeEx^JZS#f2JW>89o>4kfaaS2^Rs`A^Ib;z{{}zSg1r0nh4sHZ$n>yI z?0;L;sAT^B6#JT%FG6=Cz>+ z;m=zNyzRhLvhtdPy94w`-k!fx*NAS#Z?3DbjzT)wgv5*K2^2Qqza1zt3LnnWM5m=L z1JP_V>P%D($XPp6)1DZC@Zq!fd+*FbPmt^-65jh?ND^+7U26tn?Y?XZ{C<_pmeISt z`3dUomzh5~xdLKG|MMQ!n}RO-`)*OMr=a2j58^q{il2A2eTN@(fKBMEJhF;`)9Vo& zyXBuyZ6m+(qZ3>3G5m4)oeNXwsqYF>hMXEC*7h~)nSLosHOgf@V@p6? zK~Ha&*-gNnSw7L`ei~9bsG@UzW)cF-l!{o+6(XhY)@N@@EI=5=^LJ!l>%gGyMP?~q zD}?dh)n}_-19{r+*WK1@z_G!2-l<{{ay0@OgOfYaR`~-q{fKs;rBM50;`JFZOVSsIfOSj_#9& zWdEJ(g|ddHE(J$cA&5)zNdK`_aHKeI|smR{3NGwqZSG>SZn&|>rm@_uCx7mH#(X*F{rmNg*NsWXF0t+4>tmXI>jox&{}Ko zwL0H17*hXe8%EIvcKf@?kJ;h(-{pnMi`gBB$0SXB=6MZdFr_u8G?Q@c?i1DGwOY{f zD$Wn9EQR~2Oewd|b)#NE8n#90c;rn|wJv=^fH=(?`evuQ5#{bzIu_G5a8_S)((A%` zrO^v=RCPWOHA9h-SDFU8WcOE<2ba;V)V#o4VkcU7;JowTZ4I8YeEIY2Zaa`W(Iobt z90c;RKKWoVBJi{@m#1PcjW6ZKF@3H@ppA-RJC~RUMmejl>~E`JhpPAPZpsSid6tE5 z)6D}}dG1~FYY$PX`O2*Lu`x6q_4eyEmLZT~bYY7jC!hzPXr8@97NF#url(_o=b>2? zT-G}+;PA^xS>G@gZ79Eyp7h54AbyQ;$;a-<-&VP!bgdhCZ}DaPW2uMJX9G%PB;BB& z#=ZTH=R7Q(yR>d4+lRC{>k5xG;Cqwln3|e(EihUZ#s3_ugR`PM?>Pu-F!#j&Vy1pC zP<$9ApEBNrF~5$Z?O|=O1&b~SbIH4rAz6ZtTfubnGCQ|a3rzKD-hFj-4OF$~Mn~}9 z6|Ih3k@%JmwkI5RYhF*G=OXb5(XO5Fv%kb-;!+my`u$-$K06L!GG52uvEsSu_u`D~ z&UIMOO>rp_s|QOJ*;+A8>^ z`G;?BzR$#W=6l62z+8%&s9&3LAQ+f7tW(|KoRn^sCuRq z-L0h5tv0Cwd5bNEDqrjgSl7568C(VG#|GF~7V!B*X7HsBBLTIVkufT6jKD1i(p8Bc zQ7GX?8Ta11NwlB4x_#|j0m$h78#>rEgr?H=&Q7^)ptH62%LC$b!MSy2jwyHuDut4S z`hDsV>2L0;G-DQG?kel_O2!<(zu+8Yk#Qh0VhSO82Sv^aO0MHNQ+q+8Z`y%6WWS!D zz=?D2pZud;v|bV5vGXi*&IAE{I$1&IVvO&*rw3LSL^{!{xswWi7S_ODit_@C3jr)v zTtChnA%OeQL<42pNthAy+8#yU%RS!JeP;mCC(M$gP`weOzr7Yzvao+g0ab zIPj(B)|GCcA^@C$DkvZz3| zk241{^~__3r8av;yskjKen~B=2=hvYN9M=u7ExrO zZRXr9oU?VLc(i)23Vm-+yaf4hc$%-Q#5ZngkI&pBq(Z zMV=>uB$E#eqW1(_c0TP6p!_9P9`U9Kb7Um7uR9s&&#})oeg}I{8nfxt#=Uw#qT6FT z+4Z2pY@}fnumo2-o^Pd1Ey2Hed|bgf{mTJa9(4OUQSb{!?q_%3S*-JjF)7_r9O-X0liJ6#X5r`A|+x9mlxqLiBo z%hhOIOJ@4ES{D+erhMn-+YJjJHMc$Ju?L4wH2N@IE=rAhZk8X0^X2;wYjF&80q^Wb z=AZ6AP?g`i?)_zBXyuBOeYE==x+gL#ewCa6pq5F!am*in`2FiqVf96_VlJr{-sgju zC7DhrSv_nBw#acDA)%X;Iu|Q%t;0Z?C-3_!2!%|l6c-VTAu1|;I23d7snoSb<|i8< zA)tCyqO}`9#L$`M_cDaui($Tf9HGNxPN$^=abD3(uDBth7hakcK9}~YK<=uAK9YD} zp7cpbs75CN?cc{#`Ae$}3q^@@V+>Qsj&4+BX|Vte#_e}&j~RyL;Ki)jtBsI8D)xOJ ztO3o@z`;J3MIhJuSf~286DfpBMHu1xx5Op-jxXm|pznqfi(!8*uvk{9{}k^+hqCT; zsCnZ56Qn>Tmo$mO56(Y1Y&Q-&<`EZpgGjKyxUKNaJrX*c#W|9zS%ZocsJ%T8Wg_u> zs|Rz7lR(b(=Pt>-ACx{FF}oQRkD>))*@n7se(fDm!P$8fY2UMLeMG(nvcD;eqas?t zpgDN4D|{5l9KPC0AB+XLY=*2966Sd~=Q3obM&Ws#KC|uR33zk!0@bJJYH<6JIHYP; z4`jPeZ4l_y?Cbo#$n_61Iz#C`0smW zWk$PVF3$bJTN;-wh7|KCK47;Y|KZX&{KfA0CpYk9mWN=siZU%Z#*+VDuXcT1mL-{xL z{(`r5IqjqC*uNt;KJmhA8{{=cu9n^ihE#<>-P+t1c;u&b;!QyYy4ChE^u_ZgNEHd? zDQqf7`~q~OAZr`M)~CJC@OT08)+kb9k|v=MQN7*bvT<~w>FnVD^MpZRM{e^+w}5qZ zV2Hqn3RK{DYDC#44}E*LQ*`(s_8}L)qogZoN0aU>uCawn0JNw7BHkgm86xMsaAE=& zTy&K8SSk=fhI2QUF${!noK=NmB#0t0s}iXvK~`bkM}p%L@Mm00Ou`k7G!g*9e-kKZfnGEA zUvVz59t%VDQiO!lBh#QfLgV{+avTM$=a^N-r^8j|1==7d{M~qVeMt3OIZ9|6sQo5M zfLaEoy=8OkopJqq&ENkWh)z#O1ro~f^L5HkawHfjU0*$>`K=zkmtCoh*E#&ntPT&0bG#t)Z+*|j^M^BaPQb|1|s#k~=@PT_w-TDcEoABEg%t;V?ziGNeYqnn^}-r*bd=^2>2 zpTo4<(*+eJ67?3rqp*99aFj)=9<@H0ncQE~3QtZM&1eT<-!XTWfyfV>t3J2^lCyDW z_drs~`@Jf}Cr`hMXh%R&);yW+*8~JeS;`-#>;gYyf7&mZOK@PKeqLs!5K3;x%bgfP zh)TmMddP18ZJOS6m9;NG^Eax>rbxq>V`p=1(&~p*mbc7R`*3a`Y)m8b&?+c%^nS~e z!JOi$5BdXw<#0TiBSzy-1@L>!jvV7{h4(UgcRI*gfXVJrK36^gg1_}iZ{$sbJZqR{ z`h!te`l;mY{kH(x%5FL2nNEOd)wW7dLlvq!_r&m-ax1V$J$`+;dV%-{ z$6p>tIS}1`h`TCg49OV?eYkXr2)WK3aW>86$n6z-Oe1|i`ql|s1}DeR)XUoe-#Erm znMb?JB~WVZV9tpBY|kJR~Jd76CRE;p67Z= zfQd%g%OkBD@Pha>Xoo)=)vJVZ_}ceC^0p9DOYRx%~mSCHtwprrKtd^{ggRTQILLRN0< zzXG;SHd>nw|LV5bnCnr(r3mrMh)Cy3~ zG0662!F!S?JPp^%6A=Sv=AqQXWr(@Ko8S^X1ErLur}xCZL%zaOVT}dscX}ftV2pjO z0rRA6TbEoUm#moJXNtWi8H8KiOcQ{@HA-eerjT2h)S1Xn_1{BQXr>}lUpa#Np!1O=j|-Lrn|N8tK2g6HTyCHHTh zz1EIO0}|XGM2sT)J8SpLu$PrbqN(}OdI9pen{n}86Xve4&?;?r1oOrLgU_?Z(a5pE zd{(L!L`&tQXl6}>|9&_cIl5HA$nxLBZ*2th=TOQmpPWJT$vau;{-I@LnRhV92DpL&f#Oyk-;bb^S^wdDJ}!*jErPptVAbB59V5JT6>Zwn~)3FD)enD1x5WTu;X z>Nh%`!6MmqF$6iAu@ku(hmoOIIYn+j4T>t(@**g%qL<}?=|(km$a(B@^%~s@a5cp* zYd6-QW8+4F9luL~>-3<$pUe`N}AVvTQDGHDrFr!)y^DF?-Ob?3UrlbofX@Vl!yDNh^`o7PZJ6GEv zob*9m;M_XsNb1?t6*M74n(-0G@1bN9vIYtd0@7A{L<$aSg;(nRUsi7pqa`oxrkW@` zkJ!ny&X#-&GkX%}%YU|D9^Uxr(XLjIS8L{34;@7x1tsI@uT=vfpGHMzu?p6d_^5vO z)gclS@kt$?H?N*Y@Ac6-G|G@{Kg`a-#Yx4ulhqqQds34qIX(rh8poFYL)c4PkeFOs z6^`zH*msi9F$@($%!!$?B%qvazoAYx9EvXXSF5nC<+aH61jtdsvbRP!4``14I2^vGU4RcC|_qCy=Mu||nRqUfR zILrLaVGK@AWe@RIE=IgoligD`mo@4+v&MKp88A!Y7_oL6_25qGh>{I~1% zh-Xu8TfSfty;r}MzI-?p+}2IGCb2(-{eC^E8Q)8rB^FX|+`#uSuJt9utqC}E+3cEb zHTIE63~BUX-@T+yjG!`kKJtxe&wSm1pHH5d`MbiMs6_LfgRI3M(p71A!Z%5RQItO! z{h0{;T&?A=W5l-?n^}}h|^J)k2zEayGa?C0z4+&WOH~dp~3hkN| zzD|lRMNUTZMjmTrsKzZQ(M!1paeUZc6Y5xnZalA*%F9{+-{gAPUD{4`H7F%nw3dJz zej6%~z7Ub^p!fluT4&(8vcSgsq!A7mmy{gv-++r!^)sdIU*LiUo#OMd9uV$+GQM@T z6C|G=q(={Hp+7${Lqll|%tFOwi+5+?pVDWYm*L~c%U^g>3wxkgUbua}e_@OY$1~;v>r8&-<*| zH=^SpOGPn|k&XF+eaAnNP~ zM`i6vcoX4Mw2jYC+af=T%xU|f+`*2iYj_%%-iPze9+`%yr^iaj)Z&qK_@LkUuLLNU zwcd%(#B)lA$L#UylTb$`PI;idA5u>(}F@u>pfyr^-kuCEmm=w;qLI@*RbPy6U5-z`Tr4YC6I5pf`?T&FbJ+XoYOVtn`E z?+C4V$^BQ6b#UQj%tlIoKhVr^&}-t~rCeQriGklZTpWC*Tvss;rWc1FI2z2u6>_%S zh2bvnbv|L`B9HqEj+?~&nx2Q>JXK~6c)xg3UiouJRRV8bSL$NWzE7E zj|TU|izP4{FuwUA4$tXhs=tsIryz$2vyf5DZ$}S`_-Ipip!rw2w`{)mqTN3yTP_|U zBL0o-pEF-aV0G)t^Ue2b;9l@fz4AQ?<wIXvG*QEPF!X_O|TcVXY^_o=b@4o1I%P_zAGA3hTOh^?#icPah#(Qdq(qo^<^tOR#Rfp|4;>u z&xSjv-IicC)7aU_aUAJfcDzs`ZrnWdCSn{o!H`a zyG|t2f0|_q=dP6ch3w?4CcyksTMM%c_Tf{w4LThrLTZJspf_z9n)p_he6Y6@L_Moj zcdI&4Y9K#%%eyRij?$IFk9Go6yOMQF>I}+d%&yoqnnJb%Ocg&?aGtlNx59lJa}rw{ zG46-cQM8XgO)se%(e*i*{~Z1eR(@vdg-Qezc&Fr{gi|Zx&yX$n^E48LjAfp%pzH>2 z_m6>Vg8KL{2jANG~kv?D@<^qaIt4M4`qme2mD2dPz>mp)4E0mBraHQOG*E@>+F#(xyu6zM#FCKmt%8t1jPK$l{W%Xdsou_89 zxC*5bwR$8u{$bEIP1$p~8G14qC1MOQ;F;0}YYi+=F+&q5}ej z#;)mA@b~h|)eD}ZXyeYgx@K+?3Qy;Wxx<`=$SbN@n57!Q;_m3w&^ZFwy9sS{#TLVn zqCJuCO*24KIg&o1HUeTrJ+Gc|XCR&Ghc@l43&?Fq$FT~}-7>jmoS07F+{*H>d74Hp zlG%v0O?*WJ?}K^V*>pJ9pbx=+R~jJ5f$eN^INq-<->v_O`yOaRh1R_Ayp+SrYE|bM z0g`GdNRc-&=b~tA(!5g--vc79N_i51xmx!mzseuzm7M=~3h%3C{yTaF?hwIDmc_Wm zr33kHRqx8pFGKpf=L&}lGtdvGv6;BD*1%QB^G88_5KPIgS>#bCf(OI0$Jf9iG&4uM zID((s-JCsd?ap5_~Ml3N$_*Kt_T$>Mv4uW|LD{--fv7K1E}nzjs3;U7K7VWJ~`c>`*Mik?d+s-moHc zOaEsUvA7%t9L~<1r*A{Vw;op*j`qXrm8G=4oOBd2M{iALngy}^N|cVg`JkEEoO^_C z4E=cMc+^{rh}gnkrW@ohp{|0kZV|5@sMYqeB>vuk$j`D<0{2#+R7@{lfH(v7o`b#) z*hj6cvB~uBU^}{ZoKZrSdJ5@mSj;x+KM*2%n!0U2P z`6KP!h=2A$IySzg8JssL`Ux|?Arsy=hY+T-Yj258QDzabIxdL$p z_OJ&(A|bLT_a$mijw7RxcT`*b|KJp~rG5=ao?I^BL**jGdX{}p(ImpEyIP#ZD$afDblf{ry$nVd z{S42_tb>olq0qj-a@6w!m3NnUBmHhqAD7FM;1HE{`9IHMIJN&)v_#Q7df?*xWaR50 zHP;F^i-`qTLHeuCf^}+2CYB|W3Jwp_MjrPF>-!(zeBlJc z&&*GY@Mz}vT7nCnzsQBBY6`@G!js-BL>s(sVlYvCCxrR`2XDXZu?>UIY~V#5r4cwT zN20!9xB+UCzYE$Wwt&y}`Oo4nODLSm9*QyT!-rEHXIu&aZganHBFOq zxrjTuOGo|O5^y?vB39sgq|SeWf5fK~fc#T|Tc&6W5Ou5Hzs>GJ+YH|_g&arW%GHRI z^M~>8Qy{C7ZnXl`cvD6`wh=(KPyDAN<^fb6|1)@s=LrGELfLHnIcR1k-kf1+6zypp z{%A7QiaMRS7o?lEK~}CYDpfZS-m4ifc_eiLgUP9?V3$FNoA%A@XB>h!jiia|G{Z=`s)6ZyDIb@A|a74vA%S%fa?_ zzF`Ft^X18$Qfx%YqXyO5*drKt@733nRPAX0d!4XKcM>H0VZZz3aTVBSb55xq&4r5x zw!_al<)CHzoxCSigD_?NYE5G*5w*J*h45vSqfA|!T+vsp@cM*;*HtO(K{dCy@pTR% zUU5nHK-OaT7UQ{ko!9}7hPnUo6R@v)?h?bLogTDf``cuDs2jrU-QLAvuFp5E;_#(k zwaDXIDfR8=EAaiCLfb{_zd*ZjU((>+06ahTmG6hqG(3=X&0zPfg1m7^CYL`xig6^63BEb87|;c}k;i;x;RhmHRn|Gf+YiO+m!(aU@$*J7IqKRric}f@ zHLha*Up~#Hmgm26^zCdz>Q&<*6yWr1bir{N;=*20Dp|CmhLud>!W*1t9jS~Ja+?Ew zm4^{qsrWr|qb**YCJJqBN=H99)DDm7+I2Fz*1+Z`TP6?AA%qF&m(z*k_cx9971WZ7 zyi@9St_)(HnE5ZTDA4b~t`t$raN` z4PnlZJIi$rd$eDuKYx-uiWC(cD8F1D21bQfnvTNVuq(>et@6tc|hR_LlC3aO&Y*+gHCOH9Pdxl8uqE)U4^e4MQOG7Dv_xC z!bI-jc5u%>%^#2V69)Egvshl`pkx+ZY6HQ zF}NtMsM(El6-!Ls-X)+lQSvc~(IzC|&mnSyy$Rk5_PO6zDuajS#Bp_X+#_~4#kd*! zb+^P{9N83YK?eL}qEV}juvAwfWQ6^OgZ+cQ)~5zwce|`txDK$MY&L>+q>Lu*n@7oulHTphyAC=BwH*`;(ivZkoxvN6F@fIC{Sq}h!mER z1a6mv0&k!|_4^Y`sOqQ(&hth?$CHb$^Fpg=q{@XOlz#-Bsri!f{B9G{Vd9|uk=2WY zOrpzbabB~CT<_j{-Dz~X--`L!4{tc%@pizmp%~8T5|~du)&yy9=b_uz^I-7l7k1Cv zYpC>mcIkPBab)t)=JgA%31B6iWUwqBN1Cx@L#r$8kk37Nag@;zv3DL_t6i7_#>E38 zI~I9}c0-+6x~&qjT}!$4iB>}5&T<_Uc@3!S({z8mLx5I=X^J|0KYdPS{KK&=3wB9y z=YQcnWoH~)*rk8Hh}ZvU{pGjV(^^(}Yj>go4KH$v@E9)xEp12tf^#3dI_46ns9TBj znU-Gq3e1Ahe}f&KXUk#pLi%^r;cl3GsWu#RdmJiKrtj6wu7XlGvQPPh_w={^9eO~4 z^V+I`Y(JD1K$qjyOX!|5;J12q5^5~##aEIxpd{9VyT2Cu5~~aU zx+wUf79wXMQBpP}VN(vc)xmPOi%et6j+l4v#wh<_jc< z%*-pbEgQgG4;_6T=9Hy&!(<@^47z7^KYR>)pesld4R<&wY(b!>uerxbz%Oy`^{3a#T=N$f8E~h z>O~HV&$SCR2ao{OxxkbQxF;@4B%|ZtI>^to{1-xM1}Ep=mvzV@fz4RD#O(_K_X~|4 z5g*6iVxL7?QuYL_Z5AyW;Cp@x3$-O0!a0laJbHGjam2bz`^EcJ9Qdx88nd2hL}lqJ zXUb1j!h)~l=XPTP5)z63tXht9JmkI|5z)KAORrwDPoWEizlWR3^0uRAt#_y#QQbKV57arG~K8a@J427exzl4gLo z+UtIWqv-km>V&s@V@O=+x}X(4{|@IaN0Yu}0L`^>r1`T4!UG2$7o2T^ ze#+%TDg^`ZRJg;wv8fi7{6~2P@Z5S)*mvsFfmOUeD)29U8-@rHb*c{xe?SILO!|C$ zKb+$C2g{=qsI5!%hu=2tO|^IGDv{WPYc%|=VyxZhZN?FDsaI=Yey!1wJaG&yvKTIW z!1<2!phm)KYaZ&i@qgp#kb){`&bH)BHliz4H-6+^;gpWZA15$pHf2?i^u(tz^*o#ZxDev0OE$<7p7 zOEmi$HkJ!F$$hd$az~N7eMEuOgC2A^!G$bp?>FR7iEOHJoz(aUo^hRZq?aLt>=#!j~wwZ=cCkPpZGP(9A?&R@cQJ$-5$=3f&iwK3KC z`)CH5*bHTiOAa@5!UEXs-tyhSy#`K{G!ssjj;DP<42n#30WjAa}|~~ zLY44bxg^d@vA@l{My5D|KGbmUQTh#on(UZqyk8}}uV9YWX6-`6I+ldX+GWuC?WMJV z-aN{B(zdLB4|{`TRU^%?7s5*2Dno3WhnYO-#Qs4_?JuY*yIQ$oO4_zw6u_OdfqaWRLR=ivui4DI<*_ zp|_>uFZfO?rq|>9O?#1Vet>ue;&A)(q>HB#afRlYo8a?yja0eGE$fBmyiE4pIBdcdoE5vc@8 zUU+(C207i8q7OjHh$lHAp3u1lV(n!ugLcE9Ok;w$@clyx?Y;ilG6X-f8Xl#^4Z@2e zI;(TIXM6Io#z3Gu?wfiORNPb70pG;ujX&ZX1^+~rp0+|4%%nctCH@`4D>Y z5PmDGT92a|bk<|qZ(%;VP%2K!C4dCQ{NdtUmwI79=~o#Md&zhnYxgteR3Q;BX_@m= zSwN#d#XtPI5pBgbX3Jf~d$M?f><5=-#93w)AN#Qb{d#rpys3Q`WOK`2W&K$Xn%b93 z##1XH9Syif9~c0J=XedJIRydww3_+>*hBPiIjqfc92w3JYrG{*0q;XHed`R&5oFHF z^Eytzinxo7y6Ge+9lavbzc~z4)=_U8*Ha+QSta?+g+|DJ{9nm8M(jVLx&7;1n=?`` z$<%-T3+HscSlV&b8?K3ko;CR-_?3`DGMtU)w(%BhLT@InT1Hpk_cP}SEn^M*UfGZv&`~4-RYa`<;l&nY?S1i~ zl3M`#LnCQX3fS*7@^j4iR|oFLNFigZt%i^|--yeZxDWZKm^un3!u|ttvpXj;VVAOA zc&WS**7IHj*pDs4A4|Dq)qj|$Kk_j{dZ`1M+*yhmH|+$AqL~i8%sx~e;X%&+vJ1#8 z_J4>R`w!Cnqolu4g(B&VJ?1d~3RHfqFt@*O6#nEoOLx5?p_6`>Zz@oAq0Wov6x>5Q zp+VE`-Mf%!Xk<|-x-QcJe>l{6QC!*iU#yLWYC^G_)6GUk`xZnNJH#ORaz|%hajv!@Z`rSjT$$x>5S#u2M^82kw2(*!n50 zgid81V&V{MfXrZ3fvPR{WTqo0<7!Ocl{&n0Y{E~z{Z;d@=; z<$Tp>`P1J#p#y_p#mqcd##Rqk4mOMyGj;&o*&Xr>|0b|G@n`1f!FiC$k!jA;!@U4r z;|8{RM09^Y#oykR86;E`vMG&o+~3NEwu>cZQ2B);Dt#4MaD7t$zXaT8!9h{$JMnfE z1m=z&y>WL2T|X!kAu3S--xW_it;`uiD#I&13y1m;%kJ@uo0x~YR@}K?ai$NE^*+3u z^{^aCPmbO_C_V}lLpztLWd>oH^8H{x_b9N3ihdQiJpeIdbj5I|3G`axEq%#Kkfq`8 z7A{WAO~0{XkCz@ooxMvjYqMR5=k7gDEDnR0eZP+h;`snm$B6o?jY-gu$;(N4M+C}e zy{E~|@qBoxl(QhC9$F8HX-CIkf2@>lH05#{-g^Y+KVzSU%XEvs8oWx-PyN*ir9iyb zu}XdI#EOt(+ck-IN2cJp($VPk+7Z-ct(84zLPTfhU+vI4l0f3C*O7LwA;f$6+i51d zI23ZKU2foRA@X}4cV5ty3|#+fK757*ri!%HPelh{_TSu{PyQO~!CAM*=;^nLSDw#U_hb=R62+8Gomqk=2ZN)DG%Kj9 z=z^5t_i5atV%xAjC<8NVw5D7Rn5VoX!cP6B2)&&v6l>pGhOv4*LgVRr*t)^L$+D3F zZ;j%NqF!LnjmS=of_*MJ+W*UaWnvXMi3I5JrFH<>dxDsFp#yNXiAuxM3B>A~P2j>k zQgRZyfRI4fUNeO z9(2NchEnbGA+xUv;YL*Yp*}qS?z^!6H*d@s@&7-$*| zXC7te_gtw10lM|X`%jl4Ik@IToaPWTrctQ1_+!3dYU%=YaU+s;?UdSVs7KLv{z^+p zEF$Bp$tH(?&H^{%P5ugLUR1Y z-k*y`Wdag`Yq)oP@Zhq{j?V}vBxS4aC9Z?Hu*z(?eHD24i8qY=TLt}^Z95h0;V>Z` z{(0BD4(zp#lQk1_(B%aYJum%El_8XA$N{tfa= zs#$1gv-;##NgmSaDSWnKRE9zbgUZaJWpLyN!>#S;Jxg!h--Xc#D2Uj1#@ z-vuY~h6C)yC*Z%o2Dyq#>tNJcYH^&m7jFG=agjLJj4b=O$L_m-(un=&?!Y3`wBHO` zO7mvw`8$qQ*N8h*lMU!at`9?DAOTWe8vEa!SqD>)y5Uuby{xUYT3(7@QT7K1r>e~v z(AsWBEyeBVl(A3D#qvRE@;Rc? z56P@;55o7x;Wyp%^ABVzpiXhrvm57kWCcB31>W?7QCZ+lJiZ4}rMKuQ{#t~H-gKHd z!ye#vQQ=|zh5bF8pC2(h*TVZtUGWM3#*wOIW5u@XXUO!jmG!ushF)iL(D>`&xz5N% z{=?)&D8jtC2;TUOwhmGy|Mern(Za=~lLD>au=ep){dodt7jqvr9GZcY z;GYEp-^V~=xxpghJPA~0YgRJ^Dxq)J#-`138V%=tIDSAi9o7wgZ~2zkAp!L|-^P+M zNKoF4aB;<+e0ljO8S!E8=RNEa_IeC1WJvJ(H1-0^iT2O?wzE-t9@VMIV=W-0rq4^g z*#_1>V%VKOm4PB><3VNY|6W$^+HJZqj#3ECxnc<&NLlIOKm7^J>lxXx-xI6`wU{@a zS?30!lPkPu`9vR*PF>{9xLOUDPv`8&)ZzZ#Ygc_|<5#dxc2Pyd1NS*-M=sha5`mU; zD{vq`0G0-g)`X6&K-#@;;c?117x2FB-$UHLN?UXFZb2Urh)m^!tU^5~l;ted-qSir z34i_CpmYWe77zGY8x^4-z9Baj;XxGtDwQ~#GYRf|A^DkOosetVMcJdA3Ywofdi)Ez zVME}#^uw>XuSdwz^va`jkpJSz(0;WPbKL4QB*8r>4%>VBuZ0BfB|j-#a3bONZaJT6 zOee6YUVpc=HH$<$32pI|#C?~gV;L5;Wok|)a%%t zD8uulYR=upm$umZq;%=$Q?m`&`zBsYOsa(1DwqHIi}80j?fkL+0lWwHWfAtf*#$)r zd9)$|>rkoTymuyZ07Y>&l#|})Ah&tTr6HFk@HQK`as5gLTqg#s7Rz@+z4V&XUadRo z+a~(lJJ*H=1|QPg#QrZ<%U`;J|3;7qxr?FCWI4)KJ^EnDwjDT4lZHpsR=_D){l5Ul zM)a8^LZiIWh}=FzCJD*cfVtgjc(G9yY~5R6Js#MN3Zmj=bn*H4mdcv%gS-m(p?yRw zx_u8UL-Tc(;wsRBY-d7958f+qk*FeH#zBFE#JjZD8EDPI8yQGw=Ta>B_ym$K zaXWRie;)7kuH-kc?vp(I?KShu`fOxAkzR72vI@wQSC-E2YM{`K@uY72eH130-#FKt z1x6!R_>M~~LH~QIX|`*=O1CnehR zMb3e=*>R&Hvl$dl|92(Wl!QDuiFBF$^B8E;jN{?Oyls{Ver0)UmN-jsm2cjaV|tC z?cvmk7I6FmM$(J(AUMiw#m7C0l>EPo^4rybya(k{hEfg0wafS3{vUB~9!>Sv|9_i@ zN`@js$WSQ~p;2CMqREhwiVBIy5T$`igh)|Hh0Mt;^H7F;lzE=#d7d5PF}wHmz3$)o zeXe!?*1GO>|8xJtYOmATXTR&b-+RAa&*$U05{jmZ4KHcnzS7k;;}gF3Yk`A%`ypqM zA^0|4QY=n04Lfgtd-i5=2qL5D?W1ErG2!>3{!3 z{*h(+@;L*LnySFU@}>;7$8$UFh{=E@$#L?R3zc9vqdt-?Sc?vNh|d;|^@8*LJ)Z3= zNpO0ucH5aaoNG}Y+@IIphOW*!AD9anhGUO6^P~D&P~(PA3lmWfFK_Gc%-<)Y&96kG z1_kTf=>lJe-|>Xs&AYsWnDb$|@$FS^TqlX}ZmcjfYCtcuE}i)l+Xn^~N2rcoE&}4V z<|lV`FCd=Ha@^UP4)V+w1cK6381x>+ZTa z3r!O&#|(TsaUCM%p_xe?a`2;j$0JaPbDwh$FD(>fef89K)qoik{PBC6DE$-)$&k2s zJm@bHh~=A!k?esl!ZPdx_Pci|TZSzUXW{zEd-wCgW8kXw`Q`GbCX^e%QM;r&435HY z_a#~mLg#5EG2WeHFu$U0q{Pq%esu5CB~}|ikGlNI?Ua6~w!!z+jZ(zL#L=?tOdS|p zY?w*$>_fzmw&+q$C(3D!soZ>wxgv_Jq0Hg~=)rS?FY)Syh-xMv*k*YMOymQ$xPBP` z&jaPnMYcU~dZ&$D_th3K4l33^=+Xl@&qObAed~hranH8A!n!=)O+Dmwc>-<yV@N#1%3h%^m;e*QBuvrGqSSyezjxrOu7DNAY6BP z53*rC0Y;xx#m&P}!2>)OCo4eI(`)kfmtSZhEq)=lvJ=t2FMAvs_Zv!^KU++eCnI0E z65+irrJ#~jLngQ3JT^l|+A6Ca


o$0hR`&*OfP(fhFI3hZOuEo>cs*#_qynYj%6 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

W-gLmUfmdB@f9iKKDlmL5}R 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 From 5a77e671230520c83ad47b0830e9ed97cc847b26 Mon Sep 17 00:00:00 2001 From: judithabk6 Date: Tue, 17 Dec 2024 12:26:44 +0100 Subject: [PATCH 68/84] slight change in test formatting --- src/tests/estimation/get_estimation_results.py | 17 +++++------------ src/tests/estimation/test_get_estimation.py | 4 ++-- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/tests/estimation/get_estimation_results.py b/src/tests/estimation/get_estimation_results.py index ee43892..26b21c3 100644 --- a/src/tests/estimation/get_estimation_results.py +++ b/src/tests/estimation/get_estimation_results.py @@ -31,18 +31,11 @@ def _transform_outputs(causal_effects): direct_control = causal_effects["direct_effect_control"] indirect_treated = causal_effects["indirect_effect_treated"] indirect_control = causal_effects["indirect_effect_control"] - if direct_treated is None: - direct_treated = np.nan - if indirect_control is None: - indirect_control = np.nan - return [ - total, - direct_treated, - direct_control, - indirect_treated, - indirect_control, - 0, - ] + return np.array([total, + direct_treated, + direct_control, + indirect_treated, + indirect_control]).astype(float) def _get_estimation_results(x, t, m, y, estimator): diff --git a/src/tests/estimation/test_get_estimation.py b/src/tests/estimation/test_get_estimation.py index 769d62b..307b6f9 100644 --- a/src/tests/estimation/test_get_estimation.py +++ b/src/tests/estimation/test_get_estimation.py @@ -89,7 +89,7 @@ def tolerance(estimator, configuration_name): def effects_chap(x, t, m, y, estimator): # try whether estimator is implemented or not try: - res = _get_estimation_results(x, t, m, y, estimator)[0:5] + res = _get_estimation_results(x, t, m, y, estimator) except Exception as e: if "1D binary mediator" in str(e): pytest.skip(f"{e}") @@ -129,7 +129,7 @@ def test_robustness_to_ravel_format(data_simulated, estimator, effects_chap): data_simulated[2], data_simulated[3], estimator, - )[0:5] + ) == pytest.approx( effects_chap, nan_ok=True ) # effects_chap is obtained with data[1].ravel() and data[3].ravel() From 005fb21fa626132e0497656b86cfdeac764969fc Mon Sep 17 00:00:00 2001 From: judithabk6 Date: Wed, 18 Dec 2024 09:52:17 +0100 Subject: [PATCH 69/84] remove unused file for the tests --- .../estimation/generate_tests_results.py | 63 ------------------- 1 file changed, 63 deletions(-) delete mode 100644 src/tests/estimation/generate_tests_results.py diff --git a/src/tests/estimation/generate_tests_results.py b/src/tests/estimation/generate_tests_results.py deleted file mode 100644 index a559964..0000000 --- a/src/tests/estimation/generate_tests_results.py +++ /dev/null @@ -1,63 +0,0 @@ -import numpy as np - -from med_bench.get_simulated_data import simulate_data -from tests.estimation.get_estimation_results import _get_estimation_results - -from med_bench.utils.constants import ESTIMATORS, PARAMETER_LIST, PARAMETER_NAME - - -def _get_data_from_list(data): - """Get x, t, m, y from simulated data - """ - x = data[0] - t = data[1].ravel() - m = data[2] - y = data[3].ravel() - - return x, t, m, y - - -def _get_config_from_dict(dict_params): - """Get config parameter used for estimators parametrisation - """ - if dict_params["dim_m"] == 1 and dict_params["type_m"] == "binary": - config = 0 - else: - config = 5 - return config - - -def _get_estimators_results(x, t, m, y, config, estimator): - """Get estimation result from specified input parameters and estimator name - """ - - try: - res = _get_estimation_results(x, t, m, y, estimator, config)[0:5] - return res - - except Exception as e: - print(f"{e}") - return str(e) - - -if __name__ == "__main__": - - results = [] - - for param_list in PARAMETER_LIST: - - # Get synthetic input data from parameters list defined above - dict_params = dict(zip(PARAMETER_NAME, param_list)) - data = simulate_data(**dict_params) - x, t, m, y = _get_data_from_list(data) - config = _get_config_from_dict(dict_params=dict_params) - - for estimator in ESTIMATORS: - - # Get results from synthetic inputs - result = _get_estimators_results(x, t, m, y, config, estimator) - row = [estimator, x, t, m, y, config, result] - results.append(row) - - # Store the results in a npy file - np.save("tests_results.npy", np.array(results, dtype="object")) From 566a08c5cb825c89eca5f1901d59ad94c7c894c7 Mon Sep 17 00:00:00 2001 From: bthirion Date: Thu, 19 Dec 2024 15:00:31 +0100 Subject: [PATCH 70/84] Update src/med_bench/estimation/base.py --- src/med_bench/estimation/base.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/med_bench/estimation/base.py b/src/med_bench/estimation/base.py index 9da1e5e..84f0a80 100644 --- a/src/med_bench/estimation/base.py +++ b/src/med_bench/estimation/base.py @@ -176,7 +176,6 @@ def _fit_cross_conditional_mean_outcome(self, t, m, x, y): train0 = train[t[train] == 0] train_mean, train_nested = np.array_split(train, 2) - # train_mean = train # train_nested = train train_mean1 = train_mean[t[train_mean] == 1] train_mean0 = train_mean[t[train_mean] == 0] From b22d50f5d099f3aee181b5c8a266f9fc50b304d1 Mon Sep 17 00:00:00 2001 From: bthirion Date: Thu, 19 Dec 2024 15:00:48 +0100 Subject: [PATCH 71/84] Update src/tests/estimation/test_get_estimation.py --- src/tests/estimation/test_get_estimation.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tests/estimation/test_get_estimation.py b/src/tests/estimation/test_get_estimation.py index 307b6f9..2272f25 100644 --- a/src/tests/estimation/test_get_estimation.py +++ b/src/tests/estimation/test_get_estimation.py @@ -108,7 +108,6 @@ def effects_chap(x, t, m, y, estimator): def test_tolerance(effects, effects_chap, tolerance): error = abs((effects_chap - effects) / effects) - # print(error) assert np.all(error[~np.isnan(error)] <= tolerance[~np.isnan(error)]) From dce928d65a7fe4c92a54de17a4079ff7f00e7634 Mon Sep 17 00:00:00 2001 From: bthirion Date: Thu, 19 Dec 2024 15:01:00 +0100 Subject: [PATCH 72/84] Update src/med_bench/estimation/base.py --- src/med_bench/estimation/base.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/med_bench/estimation/base.py b/src/med_bench/estimation/base.py index 84f0a80..e62fe22 100644 --- a/src/med_bench/estimation/base.py +++ b/src/med_bench/estimation/base.py @@ -302,7 +302,6 @@ def _estimate_treatment_propensity_xm(self, m, x): """ xm = np.hstack((x, m)) - # predict P(T=1|X), P(T=1|X, M) p_xm = self._classifier_t_xm.predict_proba(xm)[:, 1] return p_xm From dfc0cc0be8b99b78ed1b6ef824c1f44cdfac128e Mon Sep 17 00:00:00 2001 From: bthirion Date: Thu, 19 Dec 2024 15:01:12 +0100 Subject: [PATCH 73/84] Update src/med_bench/estimation/base.py --- src/med_bench/estimation/base.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/med_bench/estimation/base.py b/src/med_bench/estimation/base.py index e62fe22..f42d046 100644 --- a/src/med_bench/estimation/base.py +++ b/src/med_bench/estimation/base.py @@ -284,7 +284,6 @@ def _estimate_treatment_propensity_x(self, x): p_x : array-like, shape (n_samples) probabilities P(T=1|X) """ - # predict P(T=1|X), P(T=1|X, M) p_x = self._classifier_t_x.predict_proba(x)[:, 1] return p_x From b4a26a950f58674be984e6950cbea76bc817b8bc Mon Sep 17 00:00:00 2001 From: bthirion Date: Thu, 19 Dec 2024 15:01:25 +0100 Subject: [PATCH 74/84] Update src/med_bench/estimation/base.py --- src/med_bench/estimation/base.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/med_bench/estimation/base.py b/src/med_bench/estimation/base.py index f42d046..e799544 100644 --- a/src/med_bench/estimation/base.py +++ b/src/med_bench/estimation/base.py @@ -176,7 +176,6 @@ def _fit_cross_conditional_mean_outcome(self, t, m, x, y): train0 = train[t[train] == 0] train_mean, train_nested = np.array_split(train, 2) - # train_nested = train train_mean1 = train_mean[t[train_mean] == 1] train_mean0 = train_mean[t[train_mean] == 0] train_nested1 = train_nested[t[train_nested] == 1] From ab36036edbcc613238c39e182ddaf2bd9b401a77 Mon Sep 17 00:00:00 2001 From: Hadrien Mariaccia Date: Mon, 22 Apr 2024 15:53:12 +0200 Subject: [PATCH 75/84] add doc files --- .github/workflows/sphinx_doc.yml | 37 +++++++++++++++++++++ docs/Makefile | 20 +++++++++++ docs/conf.py | 37 +++++++++++++++++++++ docs/index.rst | 22 ++++++++++++ docs/make.bat | 35 ++++++++++++++++++++ docs/modules.rst | 57 ++++++++++++++++++++++++++++++++ 6 files changed, 208 insertions(+) create mode 100644 .github/workflows/sphinx_doc.yml create mode 100644 docs/Makefile create mode 100644 docs/conf.py create mode 100644 docs/index.rst create mode 100644 docs/make.bat create mode 100644 docs/modules.rst diff --git a/.github/workflows/sphinx_doc.yml b/.github/workflows/sphinx_doc.yml new file mode 100644 index 0000000..6b50cc5 --- /dev/null +++ b/.github/workflows/sphinx_doc.yml @@ -0,0 +1,37 @@ +name: documentation + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + - name: Set up Python 3.10 + uses: actions/setup-python@v2 + with: + python-version: "3.10" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install ghp-import sphinx sphinx_rtd_theme -e . + + - name: Build HTML + run: | + cd docs/ + make html + - name: Run ghp-import + run: | + ghp-import -n -p -f docs/_build/html \ No newline at end of file diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..d4bb2cb --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..40f79e8 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,37 @@ +import os +import sys + +import med_bench +import med_bench.get_estimation +import med_bench.get_simulated_data +import med_bench.mediation +import med_bench.utils +import med_bench.utils.utils +import med_bench.utils.nuisances + + +sys.path.insert(0, os.path.abspath('../')) + +project = 'med_bench' +copyright = '2024, Judith Abecassis, Houssam Zenati, Bertrand Thirion, Hadrien Mariaccia, Mouad Zbakh' +author = 'Judith Abecassis, Houssam Zenati, Bertrand Thirion, Hadrien Mariaccia, Mouad Zbakh' + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.viewcode', + 'sphinx.ext.napoleon', + 'sphinx.ext.githubpages' +] + +templates_path = ['_templates'] +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', '.venv'] + + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = 'sphinx_rtd_theme' +html_static_path = ['_static'] diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..e4fbf4e --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,22 @@ +.. med_bench documentation master file, created by + sphinx-quickstart on Tue Apr 9 16:50:56 2024. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to med_bench's documentation! +===================================== + +.. toctree:: + :maxdepth: 4 + :caption: Contents: + + modules + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..32bb245 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/modules.rst b/docs/modules.rst new file mode 100644 index 0000000..ae7f15f --- /dev/null +++ b/docs/modules.rst @@ -0,0 +1,57 @@ +.. toctree:: + :maxdepth: 4 + :caption: Contents: + + +med_bench +================= +.. automodule:: med_bench + :members: + :undoc-members: + :show-inheritance: + + +get_estimation +-------- + +.. automodule:: med_bench.get_estimation + :members: + :undoc-members: + :show-inheritance: + + +get_simulated_data +-------- + +.. automodule:: med_bench.get_simulated_data + :members: + :undoc-members: + :show-inheritance: + + +mediation +-------- + +.. automodule:: med_bench.mediation + :members: + :undoc-members: + :show-inheritance: + + +utils +-------- + +.. automodule:: med_bench.utils.utils + :members: + :undoc-members: + :show-inheritance: + + +nuisances +-------- + +.. automodule:: med_bench.utils.nuisances + :members: + :undoc-members: + :show-inheritance: + From b93cf223e39c4ddc6339b1e4172c71c82468335d Mon Sep 17 00:00:00 2001 From: judithabk6 Date: Sun, 9 Feb 2025 22:33:16 +0100 Subject: [PATCH 76/84] make doc build --- docs/conf.py | 14 ++++++++---- docs/modules.rst | 59 ++++++++++++++++++++++++++++-------------------- 2 files changed, 44 insertions(+), 29 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 40f79e8..b964820 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -2,19 +2,23 @@ import sys import med_bench -import med_bench.get_estimation import med_bench.get_simulated_data -import med_bench.mediation +import med_bench.estimation +from med_bench.estimation.mediation_coefficient_product import CoefficientProduct +from med_bench.estimation.mediation_dml import DoubleMachineLearning +from med_bench.estimation.mediation_g_computation import GComputation +from med_bench.estimation.mediation_ipw import InversePropensityWeighting +from med_bench.estimation.mediation_mr import MultiplyRobust +from med_bench.estimation.mediation_tmle import TMLE import med_bench.utils import med_bench.utils.utils -import med_bench.utils.nuisances sys.path.insert(0, os.path.abspath('../')) project = 'med_bench' -copyright = '2024, Judith Abecassis, Houssam Zenati, Bertrand Thirion, Hadrien Mariaccia, Mouad Zbakh' -author = 'Judith Abecassis, Houssam Zenati, Bertrand Thirion, Hadrien Mariaccia, Mouad Zbakh' +copyright = '2025, Judith Abecassis, Houssam Zenati, Bertrand Thirion, Hadrien Mariaccia, Mouad Zbakh, Sami Boumaïza, Julie Josse' +author = 'Judith Abecassis, Houssam Zenati, Bertrand Thirion, Hadrien Mariaccia, Mouad Zbakh, Sami Boumaïza, Julie Josse' # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration diff --git a/docs/modules.rst b/docs/modules.rst index ae7f15f..e9833f4 100644 --- a/docs/modules.rst +++ b/docs/modules.rst @@ -1,57 +1,68 @@ .. toctree:: :maxdepth: 4 - :caption: Contents: + :caption: API: -med_bench -================= -.. automodule:: med_bench - :members: - :undoc-members: - :show-inheritance: -get_estimation --------- -.. automodule:: med_bench.get_estimation + +Estimation +========== +.. automodule:: med_bench.estimation :members: :undoc-members: :show-inheritance: -get_simulated_data --------- +.. automodule:: med_bench.estimation.mediation_coefficient_product + :members: + :undoc-members: -.. automodule:: med_bench.get_simulated_data + +.. automodule:: med_bench.estimation.mediation_g_computation :members: :undoc-members: - :show-inheritance: +.. automodule:: med_bench.estimation.mediation_ipw + :members: + :undoc-members: -mediation --------- -.. automodule:: med_bench.mediation +.. automodule:: med_bench.estimation.mediation_mr :members: :undoc-members: - :show-inheritance: -utils --------- +.. automodule:: med_bench.estimation.mediation_dml + :members: + :undoc-members: -.. automodule:: med_bench.utils.utils + + +.. automodule:: med_bench.estimation.mediation_tmle + :members: + :undoc-members: + + + +get_simulated_data +========== + +.. automodule:: med_bench.get_simulated_data :members: :undoc-members: :show-inheritance: -nuisances --------- +utils +========== -.. automodule:: med_bench.utils.nuisances +.. automodule:: med_bench.utils.utils :members: :undoc-members: :show-inheritance: + + + From 064dd297b1411d0c91191dd29db3496684ff8588 Mon Sep 17 00:00:00 2001 From: judithabk6 Date: Tue, 11 Feb 2025 17:33:57 +0100 Subject: [PATCH 77/84] fix bug in tests --- src/med_bench/utils/constants.py | 2 +- src/tests/estimation/test_get_estimation.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/med_bench/utils/constants.py b/src/med_bench/utils/constants.py index 8b5ca1d..396e54d 100644 --- a/src/med_bench/utils/constants.py +++ b/src/med_bench/utils/constants.py @@ -45,7 +45,7 @@ "mediation_multiply_robust_reg_calibration-M5D_continuous_1DX": np.array([2, 2, 2, 5, 5]), "mediation_multiply_robust_reg_calibration-M1D_continuous_5DX": np.array([1, 1, 1, 2, 2]), "mediation_multiply_robust_reg_calibration-M5D_continuous_5DX": np.array([1, 3, 3, 4, 4]), - "mediation_dml_reg-M1D_binary_1DX": np.array([1, 2, 2, 3, 3]), + "mediation_dml_reg-M1D_binary_1DX": np.array([1, 2, 2, 6, 6]), "mediation_dml_reg-M1D_binary_5DX": np.array([1, 1, 1, 5, 5]), "mediation_dml_reg-M5D_continuous_1DX": np.array([1, 10, 10, 20, 20]), "mediation_dml_reg-M5D_continuous_5DX": np.array([1, 3, 3, 5, 5]), diff --git a/src/tests/estimation/test_get_estimation.py b/src/tests/estimation/test_get_estimation.py index 2272f25..f93d014 100644 --- a/src/tests/estimation/test_get_estimation.py +++ b/src/tests/estimation/test_get_estimation.py @@ -79,9 +79,10 @@ def estimator(request): @pytest.fixture def tolerance(estimator, configuration_name): test_name = "{}-{}".format(estimator, configuration_name) - tolerance = DEFAULT_TOLERANCE if test_name in TOLERANCE_FACTOR_DICT.keys(): - tolerance *= TOLERANCE_FACTOR_DICT[test_name] + tolerance = DEFAULT_TOLERANCE * TOLERANCE_FACTOR_DICT[test_name] + else: + tolerance = DEFAULT_TOLERANCE return tolerance From bbc67493599e748fe76be2d1a6a3e872d411ea14 Mon Sep 17 00:00:00 2001 From: judithabk6 Date: Tue, 11 Feb 2025 17:34:18 +0100 Subject: [PATCH 78/84] unused file --- src/tests/utils/test_utils.py | 63 ----------------------------------- 1 file changed, 63 deletions(-) delete mode 100644 src/tests/utils/test_utils.py diff --git a/src/tests/utils/test_utils.py b/src/tests/utils/test_utils.py deleted file mode 100644 index 166446f..0000000 --- a/src/tests/utils/test_utils.py +++ /dev/null @@ -1,63 +0,0 @@ -import pytest -import re -import numpy as np -from numpy.random import default_rng -from scipy.special import expit - -from med_bench.get_simulated_data import simulate_data -from med_bench.utils.utils import _check_input - - -rg = default_rng(5) -n = 5 -dim_x = 3 - -x = rg.standard_normal(n * dim_x).reshape((n, dim_x)) -binary_m_or_t = rg.binomial(1, 0.5, n).reshape(-1, 1) -y = rg.standard_normal(n).reshape(-1, 1) - - -testdata = [ - (x, binary_m_or_t, binary_m_or_t, x, "Multidimensional y (outcome)"), - (y, x, binary_m_or_t, x, "Multidimensional t (exposure)"), - (y, x[0], binary_m_or_t, x, "Only a binary t (exposure)"), - (y, np.vstack([binary_m_or_t, binary_m_or_t]), binary_m_or_t, x, - "same number of observations"), - (y, binary_m_or_t, np.vstack([binary_m_or_t, binary_m_or_t]), x, - "same number of observations"), - (y, binary_m_or_t, binary_m_or_t, np.vstack([x, x]), - "same number of observations"), - # the check should raise when a non-binary mediator is passed while a - # binary mediator is expected (last argument of the input_check function) - (y, binary_m_or_t, x, x, "Multidimensional m (mediator)"), - (y, binary_m_or_t, x[:, 0], x, "a binary one-dimensional m"), - ] -ids = ['outcome dimension', - 'exposure dimension', - 'continuous exposure', - 'number of observations (t)', - 'number of observations (m)', - 'number of observations (x)', - 'mediator dimension', - 'binary mediator'] - -@pytest.mark.parametrize("y, t, m, x, match", testdata, ids=ids) -def test_dim_input(y, t, m, x, match): - with pytest.raises(ValueError, match=re.escape(match)): - _check_input(y, t, m, x, 'binary') - -@pytest.mark.parametrize("y, t, m, x", [(y, binary_m_or_t, binary_m_or_t, x)]) -def test_dim_output(y, t, m, x): - n = len(y) - y_converted, t_converted, m_converted, x_converted = \ - _check_input(y, t, m, x, 'binary') - assert y_converted.shape == (n,) - assert t_converted.shape == (n,) - assert x_converted.shape == x.shape - assert m_converted.shape == m.shape - y_converted, t_converted, m_converted, x_converted = \ - _check_input(y, t, m.ravel(), x[:, 0], 'binary') - assert x_converted.shape == (n, 1) - assert m_converted.shape == (n, 1) - - From 48e3224be8795719e858cf617ba2d70988de3911 Mon Sep 17 00:00:00 2001 From: judithabk6 Date: Tue, 11 Feb 2025 17:37:50 +0100 Subject: [PATCH 79/84] remove utils module from API doc as it is internal --- docs/modules.rst | 7 ------- 1 file changed, 7 deletions(-) diff --git a/docs/modules.rst b/docs/modules.rst index e9833f4..4172470 100644 --- a/docs/modules.rst +++ b/docs/modules.rst @@ -55,13 +55,6 @@ get_simulated_data :show-inheritance: -utils -========== - -.. automodule:: med_bench.utils.utils - :members: - :undoc-members: - :show-inheritance: From 54a0a6c8196a18b5032bf056ed68b417f742cf01 Mon Sep 17 00:00:00 2001 From: judithabk6 Date: Tue, 11 Feb 2025 17:38:03 +0100 Subject: [PATCH 80/84] remove unused code --- src/med_bench/estimation/base.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/med_bench/estimation/base.py b/src/med_bench/estimation/base.py index e799544..b12ba6d 100644 --- a/src/med_bench/estimation/base.py +++ b/src/med_bench/estimation/base.py @@ -1,7 +1,6 @@ from abc import ABCMeta, abstractmethod import numpy as np from sklearn import clone -from sklearn.model_selection import GridSearchCV from med_bench.utils.decorators import fitted @@ -142,7 +141,6 @@ def _fit_treatment_propensity_xm(self, t, m, x): return self - # TODO : Enable any sklearn object as classifier or regressor def _fit_binary_mediator_probability(self, t, m, x): """Fits the nuisance parameter for the density f(M=m|T, X)""" # estimate mediator densities From 2bc29443c5659534550f178f81466ddceb43fdb9 Mon Sep 17 00:00:00 2001 From: judithabk6 Date: Fri, 14 Feb 2025 17:50:32 +0100 Subject: [PATCH 81/84] fix absence of return self in DML estimator --- src/med_bench/estimation/mediation_dml.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/med_bench/estimation/mediation_dml.py b/src/med_bench/estimation/mediation_dml.py index 5ed2ecb..e3f6749 100644 --- a/src/med_bench/estimation/mediation_dml.py +++ b/src/med_bench/estimation/mediation_dml.py @@ -48,6 +48,7 @@ def fit(self, t, m, x, y): if self.verbose: print("Nuisance models fitted") + return self def estimate(self, t, m, x, y): """Estimates causal effect on data""" From c479ee9ff6f6bf4b18697347caf71c7012958539 Mon Sep 17 00:00:00 2001 From: judithabk6 Date: Fri, 14 Feb 2025 18:00:36 +0100 Subject: [PATCH 82/84] fix indentation --- src/med_bench/estimation/mediation_dml.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/med_bench/estimation/mediation_dml.py b/src/med_bench/estimation/mediation_dml.py index e3f6749..0e573f5 100644 --- a/src/med_bench/estimation/mediation_dml.py +++ b/src/med_bench/estimation/mediation_dml.py @@ -48,7 +48,7 @@ def fit(self, t, m, x, y): if self.verbose: print("Nuisance models fitted") - return self + return self def estimate(self, t, m, x, y): """Estimates causal effect on data""" From 7648b579bbba5bc56a3caaf3dfb89044042d7274 Mon Sep 17 00:00:00 2001 From: judithabk6 Date: Sat, 15 Feb 2025 14:27:22 +0100 Subject: [PATCH 83/84] remove workflows to manage R dependencies --- .github/workflows/save-packages-cache.yaml | 50 ---------------- .github/workflows/tests-with-R.yaml | 59 ------------------- .../{tests-without-R.yaml => tests.yaml} | 0 3 files changed, 109 deletions(-) delete mode 100644 .github/workflows/save-packages-cache.yaml delete mode 100644 .github/workflows/tests-with-R.yaml rename .github/workflows/{tests-without-R.yaml => tests.yaml} (100%) diff --git a/.github/workflows/save-packages-cache.yaml b/.github/workflows/save-packages-cache.yaml deleted file mode 100644 index 9e7f0e0..0000000 --- a/.github/workflows/save-packages-cache.yaml +++ /dev/null @@ -1,50 +0,0 @@ -name: cache-R - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - -jobs: - test: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: '3.11' # Specify the Python version you want to use - - - name: Install Package in Editable Mode with Python Dependencies - run: | - python -m pip install --upgrade pip - pip install -e ".[dev]" - - - name: Setup R - uses: r-lib/actions/setup-r@v2 - with: - r-version: '4.3.2' # Use the R version you prefer - - - name: Install R packages - uses: r-lib/actions/setup-r-dependencies@v2 - with: - cache: true - cache-version: 1 - dependencies: 'NA' - install-pandoc: false - packages: | - grf - causalweight - mediation - - - name: Install plmed package - run: | - R -e "pak::pkg_install('ohines/plmed')" - - - name: Install Pytest - run: | - pip install pytest \ No newline at end of file diff --git a/.github/workflows/tests-with-R.yaml b/.github/workflows/tests-with-R.yaml deleted file mode 100644 index 20b15a0..0000000 --- a/.github/workflows/tests-with-R.yaml +++ /dev/null @@ -1,59 +0,0 @@ -name: CI-with-R - -on: - push: - branches: [ main ] - pull_request: - branches: - - main - - develop - -jobs: - test: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: '3.11' # Specify the Python version you want to use - - - name: Install Package in Editable Mode with Python Dependencies - run: | - python -m pip install --upgrade pip - pip install -e ".[dev]" - - - name: Setup R - uses: r-lib/actions/setup-r@v2 - with: - r-version: '4.3.2' # Use the R version you prefer - - - name: Install R packages - uses: r-lib/actions/setup-r-dependencies@v2 - with: - cache: true - cache-version: 1 - dependencies: 'NA' - install-pandoc: false - packages: | - Matrix@1.6-5 - MASS@7.3-60 - grf - causalweight - mediation - - - name: Install plmed package - run: | - R -e "pak::pkg_install('ohines/plmed')" - - - name: Install Pytest - run: | - pip install pytest - - - name: Run tests - run: | - export LD_LIBRARY_PATH=$(python -m rpy2.situation LD_LIBRARY_PATH):${LD_LIBRARY_PATH} - pytest diff --git a/.github/workflows/tests-without-R.yaml b/.github/workflows/tests.yaml similarity index 100% rename from .github/workflows/tests-without-R.yaml rename to .github/workflows/tests.yaml From 95ad55a6f69cd204d3c9adb9eb611f9203fbb17b Mon Sep 17 00:00:00 2001 From: judithabk6 Date: Sat, 15 Feb 2025 14:37:28 +0100 Subject: [PATCH 84/84] rename ci --- .github/workflows/tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index e8fb624..d725899 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -1,4 +1,4 @@ -name: CI-without-R +name: CI on: push: