Example #1
0
    def test_nested_fixable_conditional_ignorability(self):
        np.random.seed(0)
        vertices = ['C', 'T', 'Y']
        di_edges = [('C', 'Y'), ('T', 'Y')]
        bi_edges = [('C', 'T')]
        G = ADMG(vertices, di_edges, bi_edges)

        size = 2000
        U1 = np.random.binomial(1, 0.4, size)
        U2 = np.random.uniform(0, 1.5, size)

        C = -1 + 0.4 * U1 + 0.8 * U2 + np.random.normal(0, 1, size)

        p_t = expit(0.2 + 0.2 * U1 + 0.5 * U2)
        T = np.random.binomial(1, p_t, size)

        p_y = expit(1 + 1.5 * T - 0.6 * C)
        Y = np.random.binomial(1, p_y, size)

        data = pd.DataFrame({'C': C, 'T': T, 'Y': Y})

        ace_truth = 1.5

        ace = CausalEffect(G, 'T', 'Y')
        ace_nipw = ace.compute_effect(data, "n-ipw")
        ace_anipw = ace.compute_effect(data, "anipw")

        self.assertTrue(abs(ace_nipw - ace_truth) < TOL)
        self.assertTrue(abs(ace_anipw - ace_truth) < TOL)
Example #2
0
 def compute_individual_treatment_effect(self, df, paths, G, query,
                                         objectives, bug_val, config):
     """This function is used to compute individual treatment effect"""
     from causality.estimation.nonparametric import CausalEffect
     ite = {}
     if query == "best":
         bestval = np.min(df[objectives])
     else:
         bestval = (1 - query) * bug_val
     for path in paths:
         for i in range(0, len(path)):
             if i > 0:
                 if cfg.is_intervenable[path[i]]:
                     index = cfg.index[path[i]]
                     effect = CausalEffect(G, path[i], path[0])
                     max_effect = -20000
                     for val in cfg.path[i]:
                         x = df({path[i]: [val], path[0]: [bestval]})
                         if max_effect < effect.pdf(x):
                             max_effect = effect.pdf(x)
                             ite[path[i]] = [max_effect, val, index]
     # Find the best config options and values
     options = [
         v for _, v in sorted(
             ace.items(), key=lambda item: item[0], reverse=True)
     ][:5]
     for opt in options:
         config[opt[2]] = opt[1]
     return config
Example #3
0
 def compute_path_causal_effect(self, df, paths, G, K):
     """This function is used to compute P_ACE for each path"""
     ace = {}
     print(df)
     for path in paths:
         ace[str(path)] = 0
         for i in range(0, len(path)):
             if i > 0:
                 try:
                     obj = CausalEffect(graph=G,
                                        treatment=path[i],
                                        outcome=path[0])
                     ace[str(path)] += obj.compute_effect(
                         df, "gformula")  # computing the effect
                     print("causal effect of {0} on {1}".format(
                         path[i], path[0]))
                     print("ace = ", ace, "\n")
                 except:
                     continue
     # rank paths and select top K
     paths = {
         k: v
         for k, v in sorted(
             ace.items(), key=lambda item: item[1], reverse=True)
     }[:K]
     return paths
Example #4
0
    def test_nested_fixable_Y_in_DT_continuousZ(self):
        np.random.seed(0)
        vertices = ['C', 'Z1', 'Z2', 'T', 'Y']
        di_edges = [('C', 'T'), ('C', 'Y'), ('Z1', 'Z2'), ('Z2', 'T'),
                    ('T', 'Y')]
        bi_edges = [('Z1', 'T'), ('Z1', 'Y')]
        G = ADMG(vertices, di_edges, bi_edges)

        size = 2000
        U1 = np.random.binomial(1, 0.4, size)
        U2 = np.random.uniform(0, 1.5, size)
        U3 = np.random.binomial(1, 0.3, size)
        U4 = np.random.uniform(0, 0.5, size)

        C = np.random.normal(0, 1, size)
        Z1 = U1 - U2 + 0.5 * U3 + U4 + np.random.normal(1, 1, size)
        Z2 = 0.4 - 0.4 * Z1 + np.random.normal(0, 1, size)

        p_t = expit(0.2 + 0.2 * C + 0.5 * Z2 + U1 - U2)
        T = np.random.binomial(1, p_t, size)

        Y = 1 + T - 0.6 * C + U3 + U4 + np.random.normal(0, 1, size)

        data = pd.DataFrame({'Z1': Z1, 'Z2': Z2, 'C': C, 'T': T, 'Y': Y})

        ace_truth = 1

        ace = CausalEffect(G, 'T', 'Y')
        ace.n_order = ['C', 'Z1', 'Z2', 'T', 'Y']
        ace_nipw = ace.compute_effect(data, "n-ipw")
        ace_anipw = ace.compute_effect(data, "anipw")

        self.assertTrue(abs(ace_nipw - ace_truth) < TOL)
        self.assertTrue(abs(ace_anipw - ace_truth) < TOL)
Example #5
0
    def test_p_fixability_continuousML(self):
        np.random.seed(0)
        vertices = ['C1', 'C2', 'Z1', 'Z2', 'T', 'M', 'L', 'Y']
        di_edges = [('C1', 'T'), ('C1', 'L'), ('C2', 'T'), ('C2', 'M'),
                    ('C2', 'L'), ('C2', 'Y'), ('T', 'M'), ('M', 'L'),
                    ('L', 'Y')]
        bi_edges = [('Z1', 'C1'), ('Z2', 'C2'), ('T', 'L')]
        G = ADMG(vertices, di_edges, bi_edges)

        size = 5000
        U1 = np.random.binomial(1, 0.4, size)
        U2 = np.random.uniform(0, 1.5, size)
        U3 = np.random.binomial(1, 0.6, size)
        U4 = np.random.uniform(-1, 0.2, size)
        U5 = np.random.binomial(1, 0.3, size)
        U6 = np.random.uniform(0.5, 1.5, size)

        p_z1 = expit(0.4 - U1 + U2)
        Z1 = np.random.binomial(1, p_z1, size)

        p_c1 = expit(-0.1 + U1 - U2)
        C1 = np.random.binomial(1, p_c1, size)

        C2 = 1 + U3 - U4 + np.random.normal(0, 1, size)
        Z2 = -0.5 + U3 - U4 + np.random.normal(0, 1, size)

        p_t = expit(0.5 + 0.5 * C1 - 0.4 * C2 - 0.4 * U5 + 0.4 * U6)
        T = np.random.binomial(1, p_t, size)

        M = -0.3 + 0.8 * T - 0.3 * C2 + np.random.normal(0, 1, size)
        L = 0.75 - 1.5 * M - 0.4 * C1 - 0.3 * C2 - 0.4 * U5 + 0.5 * U6 + np.random.normal(
            0, 1, size)
        Y = 1 + 1 * L + C2 + np.random.normal(0, 1, size)

        data = pd.DataFrame({
            'C1': C1,
            'C2': C2,
            'Z1': Z1,
            'Z2': Z2,
            'T': T,
            'M': M,
            'L': L,
            'Y': Y
        })

        # Compute the true ACE = (coefficient of T in M)*(coefficient of M in L)
        ace_truth = -1.2

        ace = CausalEffect(G, 'T', 'Y')
        ace_pipw = ace.compute_effect(data, "p-ipw")
        ace_dipw = ace.compute_effect(data, "d-ipw")

        print(ace_pipw)
        print(ace_dipw)

        self.assertTrue(abs(ace_pipw - ace_truth) < TOL)
        self.assertTrue(abs(ace_dipw - ace_truth) < TOL)
Example #6
0
    def test_p_fixable_continuousY_inML(self):
        np.random.seed(0)
        vertices = ['T', 'M', 'Y']
        di_edges = [('T', 'M'), ('M', 'Y')]
        bi_edges_1 = [('T', 'Y')]
        bi_edges_2 = [('M', 'Y')]

        # First graph: Y \in L (front-door), mb-shielded
        G_1 = ADMG(vertices, di_edges, bi_edges_1)

        # Second graph: Y \in M, not mb-shielded
        G_2 = ADMG(vertices, di_edges, bi_edges_2)

        size = 5000
        U1 = np.random.binomial(1, 0.4, size)
        U2 = np.random.uniform(0, 1.5, size)

        p_t = expit(0.8 + 0.4 * U1 - 0.8 * U2)
        T = np.random.binomial(1, p_t, size)

        M = -0.3 + 0.8 * T + np.random.normal(0, 1, size)
        Y = 1 + 1 * M + 0.5 * U1 + 0.3 * U2 + np.random.normal(0, 1, size)

        data = pd.DataFrame({'T': T, 'M': M, 'Y': Y})

        # Compute the true ACE = (coefficient of T in M)*(coefficient of M in L)
        ace_truth = 0.8

        # Test on the first graph
        ace_1 = CausalEffect(G_1, 'T', 'Y')
        ace_1_pipw, _, _ = ace_1.compute_effect(data, "p-ipw", n_bootstraps=1)
        ace_1_dipw = ace_1.compute_effect(data, "d-ipw")
        ace_1_apipw = ace_1.compute_effect(data, "apipw")
        ace_1_eff = ace_1.compute_effect(data, "eff-apipw")

        self.assertTrue(ace_1.is_mb_shielded)
        self.assertTrue(abs(ace_1_pipw - ace_truth) < TOL)
        self.assertTrue(abs(ace_1_dipw - ace_truth) < TOL)
        self.assertTrue(abs(ace_1_apipw - ace_truth) < TOL)
        self.assertTrue(abs(ace_1_eff - ace_truth) < TOL)

        # Test on the second graph
        ace_2 = CausalEffect(G_2, 'T', 'Y')
        ace_2_pipw = ace_2.compute_effect(data, "p-ipw")
        ace_2_dipw = ace_2.compute_effect(data, "d-ipw")
        ace_2_apipw = ace_2.compute_effect(data, "apipw")

        self.assertFalse(ace_2.is_mb_shielded)
        self.assertTrue(abs(ace_2_pipw - ace_truth) < TOL)
        self.assertTrue(abs(ace_2_dipw - ace_truth) < TOL)
        self.assertTrue(abs(ace_2_apipw - ace_truth) < TOL)
Example #7
0
    def test_a_fixability(self):

        vertices = ['Z1', 'Z2', 'C1', 'C2', 'T', 'M', 'Y', 'D1', 'D2']
        di_edges = [('C1', 'Z1'), ('C1', 'T'), ('C1', 'M'), ('C2', 'Z1'),
                    ('C2', 'T'), ('C2', 'M'), ('Z1', 'Z2'), ('Z2', 'T'),
                    ('T', 'M'), ('M', 'Y'), ('M', 'D1'), ('Y', 'D2'),
                    ('D1', 'D2')]
        bi_edges = [('Z1', 'T'), ('Z2', 'C1'), ('C2', 'Y'), ('D1', 'Y')]
        G = ADMG(vertices, di_edges, bi_edges)

        data = pd.DataFrame()
        ace = CausalEffect(G, 'T', 'Y')

        self.assertFalse(ace.is_mb_shielded)
        self.assertEqual(ace.strategy, "a-fixable")
        with self.assertRaises(RuntimeError):
            ace.compute_effect(data, "eff-aipw")
Example #8
0
    def test_ignorable_model(self):
        np.random.seed(0)
        vertices = ['T', 'Y']
        di_edges = [('T', 'Y')]
        bi_edges = []
        G = ADMG(vertices, di_edges, bi_edges)

        size = 5000
        T = np.random.binomial(1, 0.3, size)

        # First dataset: Continuous Y
        ace_truth_1 = 0.4
        Y_1 = -0.2 + ace_truth_1 * T + np.random.normal(0, 1, size)
        data_1 = pd.DataFrame({'T': T, 'Y': Y_1})

        ace_1 = CausalEffect(G, 'T', 'Y')
        ace_1_ipw = ace_1.compute_effect(data_1, "ipw")
        ace_1_gformula = ace_1.compute_effect(data_1, "gformula")
        ace_1_aipw = ace_1.compute_effect(data_1, "aipw")
        ace_1_eff_aipw = ace_1.compute_effect(data_1, "eff-aipw")

        self.assertTrue(ace_1.is_mb_shielded)
        self.assertEqual(ace_1.strategy, "a-fixable")
        self.assertTrue(abs(ace_1_ipw - ace_truth_1) < TOL)
        self.assertTrue(abs(ace_1_gformula - ace_truth_1) < TOL)
        self.assertTrue(abs(ace_1_aipw - ace_truth_1) < TOL)
        self.assertTrue(abs(ace_1_eff_aipw - ace_truth_1) < TOL)

        # Second dataset: Binary Y
        ace_truth_2 = -0.4
        p_y = expit(0.8 + ace_truth_2 * T)
        Y_2 = np.random.binomial(1, p_y, size)
        data_2 = pd.DataFrame({'T': T, 'Y': Y_2})

        ace_2 = CausalEffect(G, 'T', 'Y')
        ace_2_gformula = ace_2.compute_effect(data_2, "gformula")
        ace_2_aipw = ace_2.compute_effect(data_2, "aipw")

        self.assertTrue(abs(ace_2_gformula - ace_truth_2) < TOL)
        self.assertTrue(abs(ace_2_aipw - ace_truth_2) < TOL)
Example #9
0
    def test_a_fixability_compute_ace(self):
        np.random.seed(0)

        vertices = ['Z1', 'Z2', 'C1', 'C2', 'T', 'M', 'Y']
        di_edges = [('C1', 'Z1'), ('C1', 'T'), ('C1', 'M'), ('C2', 'Z1'),
                    ('C2', 'T'), ('C2', 'M'), ('Z1', 'Z2'), ('Z2', 'T'),
                    ('T', 'M'), ('M', 'Y')]
        bi_edges = [('Z1', 'T'), ('Z2', 'C1'), ('C2', 'Y')]
        G = ADMG(vertices, di_edges, bi_edges)

        size = 2000
        U1 = np.random.binomial(1, 0.4, size)
        U2 = np.random.uniform(0, 1.5, size)
        U3 = np.random.binomial(1, 0.6, size)
        U4 = np.random.uniform(-1, 0.2, size)
        U5 = np.random.binomial(1, 0.3, size)
        U6 = np.random.uniform(0.5, 1.5, size)

        C1 = U3 + U4 + np.random.normal(0, 1, size)
        C2 = U5 * U6 + np.random.normal(0, 1, size)

        p_z1 = expit(0.4 + 0.3 * C1 - 0.4 * C2 - 0.5 * U1 * U2)
        Z1 = np.random.binomial(1, p_z1, size)

        Z2 = 1 + Z1 + U3 + U4 + np.random.normal(0, 1, size)

        p_t1 = expit(0.5 - 0.3 * C1 - 0.4 * C2 + 0.3 * U1 - 0.3 * U2)
        T = np.random.binomial(1, p_t1, size)

        M = 1 + 0.5 * C1 - 0.8 * C2 - 0.5 * T + np.random.normal(0, 1, size)
        Y = 1 + 1 * M + U5 + U6 + np.random.normal(0, 1, size)

        data = pd.DataFrame({
            'C1': C1,
            'C2': C2,
            'Z1': Z1,
            'Z2': Z2,
            'T': T,
            'M': M,
            'Y': Y
        })

        ace_truth = -0.5

        ace = CausalEffect(G, 'T', 'Y')
        ace_ipw = ace.compute_effect(data, "ipw")
        ace_gformula = ace.compute_effect(data, "gformula")
        ace_aipw = ace.compute_effect(data, "aipw")
        ace_eff = ace.compute_effect(data, "eff-aipw")

        self.assertTrue(abs(ace_ipw - ace_truth) < TOL)
        self.assertTrue(abs(ace_gformula - ace_truth) < TOL)
        self.assertTrue(abs(ace_aipw - ace_truth) < TOL)
        self.assertTrue(abs(ace_eff - ace_truth) < TOL)
Example #10
0
    def test_bow_arc(self):
        vertices = ['C', 'T', 'Y']
        di_edges = [('C', 'T'), ('C', 'Y'), ('T', 'Y')]
        bi_edges = [('T', 'Y')]
        G = ADMG(vertices, di_edges, bi_edges)

        data = pd.DataFrame()

        ace = CausalEffect(G, 'T', 'Y')
        self.assertEqual(ace.strategy, "Not ID")
        with self.assertRaises(RuntimeError):
            ace.compute_effect(data, "n-ipw")
        with self.assertRaises(RuntimeError):
            ace.compute_effect(data, "anipw")
Example #11
0
    def test_p_fixable_binaryY_inML(self):
        np.random.seed(0)
        vertices = ['T', 'M', 'Y']
        di_edges = [('T', 'M'), ('M', 'Y')]
        bi_edges_1 = [('T', 'Y')]
        bi_edges_2 = [('M', 'Y')]

        # First graph: Y \in L (front-door)
        G_1 = ADMG(vertices, di_edges, bi_edges_1)

        # Second graph: Y \in M
        G_2 = ADMG(vertices, di_edges, bi_edges_2)

        size = 5000
        U1 = np.random.binomial(1, 0.4, size)
        U2 = np.random.uniform(0, 1.5, size)

        p_t = expit(0.5 - 0.4 * U1 + 0.4 * U2)
        T = np.random.binomial(1, p_t, size)

        M = -0.3 + 0.8 * T + np.random.normal(0, 1, size)

        p_y = expit(-1 + 0.4 * M + 0.5 * U1 + 0.3 * U2)
        Y = np.random.binomial(1, p_y, size)

        data = pd.DataFrame({'T': T, 'M': M, 'Y': Y})

        # Compute the true ACE (log of odds ratio)
        ace_truth = 0.32

        # Test the first graph
        ace_1 = CausalEffect(G_1, 'T', 'Y')
        ace_1_pipw = ace_1.compute_effect(data, "p-ipw")
        ace_1_dipw = ace_1.compute_effect(data, "d-ipw")

        self.assertTrue(abs(ace_1_pipw - ace_truth) < TOL)
        self.assertTrue(abs(ace_1_dipw - ace_truth) < TOL)

        # Test the second graph
        ace_2 = CausalEffect(G_2, 'T', 'Y')
        ace_2_pipw, _, _ = ace_2.compute_effect(data, "p-ipw", n_bootstraps=1)
        ace_2_dipw = ace_2.compute_effect(data, "d-ipw")

        self.assertTrue(abs(ace_2_pipw - ace_truth) < TOL)
        self.assertTrue(abs(ace_2_dipw - ace_truth) < TOL)
Example #12
0
    def test_p_fixability(self):

        # First graph: mb-shielded
        vertices_1 = ['C', 'T', 'M', 'L', 'Y']
        di_edges_1 = [('C', 'T'), ('C', 'M'), ('C', 'L'), ('C', 'Y'),
                      ('T', 'M'), ('M', 'L'), ('M', 'Y'), ('L', 'Y')]
        bi_edges_1 = [('T', 'L'), ('T', 'Y')]
        G_1 = ADMG(vertices_1, di_edges_1, bi_edges_1)

        ace_1 = CausalEffect(G_1, 'T', 'Y')
        self.assertTrue(ace_1.is_mb_shielded)
        self.assertEqual(ace_1.strategy, "p-fixable")

        # Second graph: mb-shielded
        vertices_2 = ['C', 'T', 'M', 'L', 'Y']
        di_edges_2 = [('C', 'T'), ('C', 'M'), ('C', 'L'), ('C', 'Y'),
                      ('T', 'M'), ('M', 'L'), ('T', 'Y'), ('L', 'Y')]
        bi_edges_2 = [('T', 'L'), ('M', 'Y')]
        G_2 = ADMG(vertices_2, di_edges_2, bi_edges_2)

        ace_2 = CausalEffect(G_2, 'T', 'Y')
        self.assertTrue(ace_2.is_mb_shielded)
        self.assertEqual(ace_2.strategy, "p-fixable")

        # Third graph: not mb-shielded
        vertices_3 = ['C1', 'C2', 'Z1', 'Z2', 'T', 'M', 'L', 'Y']
        di_edges_3 = [('C1', 'T'), ('C1', 'L'), ('C2', 'M'), ('C2', 'L'),
                      ('C2', 'Y'), ('T', 'M'), ('M', 'L'), ('L', 'Y')]
        bi_edges_3 = [('Z1', 'C1'), ('Z2', 'C2'), ('T', 'L')]
        G_3 = ADMG(vertices_3, di_edges_3, bi_edges_3)

        data = pd.DataFrame()
        ace_3 = CausalEffect(G_3, 'T', 'Y')

        self.assertFalse(ace_3.is_mb_shielded)
        self.assertEqual(ace_3.strategy, "p-fixable")
        with self.assertRaises(RuntimeError):
            ace_3.compute_effect(data, "eff-apipw")
Example #13
0
    def test_nested_fixability(self):
        np.random.seed(0)
        vertices = ['C1', 'C2', 'T', 'M', 'Z', 'R1', 'R2', 'Y']
        di_edges = [('C1', 'T'), ('C1', 'Y'), ('C2', 'T'), ('C2', 'Y'),
                    ('R2', 'Y'), ('Z', 'T'), ('T', 'R1'), ('T', 'Y'),
                    ('R1', 'M'), ('M', 'Y')]
        bi_edges = [('Z', 'R2'), ('T', 'R2'), ('Z', 'R1'), ('C1', 'M'),
                    ('C1', 'Y'), ('C2', 'M'), ('C2', 'Y')]
        G = ADMG(vertices, di_edges, bi_edges)

        size = 2000
        U1 = np.random.binomial(1, 0.4, size)
        U2 = np.random.uniform(0, 0.5, size)
        U3 = np.random.binomial(1, 0.3, size)
        U4 = np.random.uniform(0, 0.5, size)
        U5 = np.random.binomial(1, 0.4, size)
        U6 = np.random.uniform(0, 1.5, size)
        U7 = np.random.binomial(1, 0.3, size)
        U8 = np.random.uniform(0, 0.5, size)
        U9 = np.random.binomial(1, 0.3, size)
        U10 = np.random.uniform(0, 0.5, size)

        p_r2 = expit(-0.2 + U1 - 0.8 * U2 + U3 + U4)
        R2 = np.random.binomial(1, p_r2, size)

        C1 = U7 - U8 + U9 + U10 + np.random.normal(0, 1, size)
        C2 = U7 - U8 + U9 * U10 + np.random.normal(0, 1, size)
        Z = U1 - U2 - U5 - U6 + np.random.normal(0, 1, size)

        p_t1 = expit(0.8 - 0.5 * C1 + 0.5 * C2 + 0.3 * Z + 0.5 * U3 - 0.4 * U4)
        T = np.random.binomial(1, p_t1, size)

        p_r1 = expit(0.2 + 0.7 * T - 0.6 * U5 - 0.6 * U6)
        R1 = np.random.binomial(1, p_r1, size)

        M = 1 - R1 - U7 + U8 + np.random.normal(0, 1, size)
        Y = 1 + R2 + M + 1 * T + C1 + C2 + U9 + U10 + np.random.normal(
            0, 1, size)

        data = pd.DataFrame({
            'C1': C1,
            'C2': C2,
            'R1': R1,
            'R2': R2,
            'Z': Z,
            'T': T,
            'M': M,
            'Y': Y
        })

        ace_truth = 0.8

        ace = CausalEffect(G, 'T', 'Y')
        ace_nipw = ace.compute_effect(data, "n-ipw")
        ace_anipw = ace.compute_effect(data, "anipw")

        self.assertEqual(ace.strategy, "nested-fixable")
        self.assertTrue(abs(ace_nipw - ace_truth) < TOL)
        self.assertTrue(abs(ace_anipw - ace_truth) < TOL)

        # ensure other methods don't work for this graph
        with self.assertRaises(RuntimeError):
            ace.compute_effect(data, "p-ipw")
        with self.assertRaises(RuntimeError):
            ace.compute_effect(data, "d-ipw")
        with self.assertRaises(RuntimeError):
            ace.compute_effect(data, "apipw")
        with self.assertRaises(RuntimeError):
            ace.compute_effect(data, "eff-apipw")
Example #14
0
    def test_p_fixability_binaryML(self):
        np.random.seed(0)
        vertices = ['C1', 'C2', 'Z1', 'Z2', 'T', 'M', 'L', 'Y']
        di_edges = [('C1', 'T'), ('C1', 'L'), ('C2', 'T'), ('C2', 'M'),
                    ('C2', 'L'), ('C2', 'Y'), ('T', 'M'), ('M', 'L'),
                    ('L', 'Y')]
        bi_edges = [('Z1', 'C1'), ('Z2', 'C2'), ('T', 'L')]
        G = ADMG(vertices, di_edges, bi_edges)

        size = 1000
        U1 = np.random.binomial(1, 0.4, size)
        U2 = np.random.uniform(0, 1.5, size)
        U3 = np.random.binomial(1, 0.6, size)
        U4 = np.random.uniform(-1, 0.2, size)
        U5 = np.random.binomial(1, 0.3, size)
        U6 = np.random.uniform(0.5, 1.5, size)

        p_z1 = expit(0.4 - U1 + U2)
        Z1 = np.random.binomial(1, p_z1, size)

        p_c1 = expit(-0.1 + U1 - U2)  # + 0.5*Z1)
        C1 = np.random.binomial(1, p_c1, size)

        C2 = 1 + U3 - U4 + np.random.normal(0, 1, size)

        Z2 = -0.5 + U3 - U4 + np.random.normal(0, 1, size)

        p_t = expit(0.5 + 0.5 * C1 - 0.4 * C2 - 0.4 * U5 + 0.4 * U6)
        T = np.random.binomial(1, p_t, size)

        p_m = expit(-0.3 + 1.5 * T - 0.3 * C2)
        M = np.random.binomial(1, p_m, size)

        p_l = expit(0.75 - 0.8 * M - 0.4 * C1 - 0.3 * C2 - 0.4 * U5 + 0.5 * U6)
        L = np.random.binomial(1, p_l, size)

        Y = 1 + 1 * L + C2 + np.random.normal(0, 1, size)

        data = pd.DataFrame({
            'C1': C1,
            'C2': C2,
            'Z1': Z1,
            'Z2': Z2,
            'T': T,
            'M': M,
            'L': L,
            'Y': Y
        })

        # Compute the true ACE
        # vertices_hidden = ['C1', 'C2', 'Z1', 'Z2', 'T', 'M', 'L', 'Y', 'U1', 'U2', 'U3', 'U4', 'U5', 'U6']
        # di_edges_hidden = [('C1', 'T'), ('C1', 'L'), ('C2', 'T'), ('C2', 'M'),
        #                    ('C2', 'L'), ('C2', 'Y'), ('T', 'M'), ('M', 'L'), ('L', 'Y'),
        #                    ('U1', 'Z1'), ('U1', 'C1'), ('U2', 'Z1'), ('U2', 'C1'),
        #                    ('U3', 'C2'), ('U3', 'Z2'), ('U4', 'C2'), ('U4', 'Z2'),
        #                    ('U5', 'T'), ('U5', 'L'), ('U6', 'T'), ('U6', 'L')]
        # G_hidden = ADMG(vertices_hidden, di_edges_hidden, [])
        # data_hidden = pd.DataFrame({'C1': C1, 'C2': C2, 'Z1': Z1, 'Z2': Z2, 'T': T, 'M': M, 'L': L, 'Y': Y,
        #                             'U1': U1, 'U2': U2, 'U3': U3, 'U4': U4, 'U5': U5, 'U6': U6})
        # ace_hidden = AverageCausalEffect(G_hidden, 'T', 'Y')
        # ace_hidden_ipw, _, _ = ace_hidden.bootstrap_ace(data_hidden, "ipw")
        # ace_hidden_gformula, _, _ = ace_hidden.bootstrap_ace(data_hidden, "gformula")
        # ace_hidden_aipw, _, _ = ace_hidden.bootstrap_ace(data_hidden, "aipw")
        # ace_hidden_eff, _, _ = ace_hidden.bootstrap_ace(data_hidden, "eff-aipw")
        #
        # print(ace_hidden_ipw)
        # print(ace_hidden_gformula)
        # print(ace_hidden_aipw)
        # print(ace_hidden_eff, "\n")
        ace_truth = -0.07

        ace = CausalEffect(G, 'T', 'Y')
        ace_pipw = ace.compute_effect(data, "p-ipw")
        ace_dipw = ace.compute_effect(data, "d-ipw")
        ace_apipw = ace.compute_effect(data, "apipw")
        ace_eff = ace.compute_effect(data, "eff-apipw")

        self.assertTrue(abs(ace_pipw - ace_truth) < TOL)
        self.assertTrue(abs(ace_dipw - ace_truth) < TOL)
        self.assertTrue(abs(ace_apipw - ace_truth) < TOL)
        self.assertTrue(abs(ace_eff - ace_truth) < TOL)
        with self.assertRaises(RuntimeError):
            ace.compute_effect(data, "ipw")
        with self.assertRaises(RuntimeError):
            ace.compute_effect(data, "gformula")
        with self.assertRaises(RuntimeError):
            ace.compute_effect(data, "aipw")
        with self.assertRaises(RuntimeError):
            ace.compute_effect(data, "eff-aipw")
Example #15
0
    def compute_individual_treatment_effect(self, df, paths, g, query, options,
                                            bug_val, config, cfg,
                                            variable_types):
        """This function is used to compute individual treatment effect"""
        from causality.estimation.nonparametric import CausalEffect
        from causality.estimation.adjustments import AdjustForDirectCauses
        from networkx import DiGraph
        ite = {}
        objectives = options.obj
        option_values = cfg["option_values"][options.hardware]
        adjustment = AdjustForDirectCauses()
        if query == "best":
            bestval = np.min(df[objectives])
        else:
            bestval = (1 - query) * bug_val

        # multi objective treatment effect
        if len(objectives) >= 2:
            m_paths = defaultdict(list)
            multi_paths = []
            for p in paths:
                m_paths[p[-1]].append(p[0])

            for key, _ in m_paths.items():
                cur_p = []
                if len(m_paths[key]) >= 2:
                    indexes = [i for i, v in enumerate(paths) if key in v]
                    for ind in indexes:
                        cur_p.append(paths[ind])
                    paths = [
                        i for j, i in enumerate(paths) if j not in indexes
                    ]
                    multi_paths.append(cur_p)
            # compute treatment effect
            if paths:
                for path in paths:
                    cur_g = DiGraph()
                    cur_g.add_nodes_from(path)
                    cur_g.add_edges_from([(path[j], path[j - 1])
                                          for j in range(len(path) - 1, 0, -1)
                                          ])
                    for i in range(0, len(path)):
                        if i > 0:
                            if cfg["is_intervenable"][path[i]]:
                                admissable_set = adjustment.admissable_set(
                                    cur_g, [path[i]], [path[0]])
                                effect = CausalEffect(
                                    df, [path[i]], [path[0]],
                                    variable_types=variable_types,
                                    admissable_set=list(admissable_set))
                                max_effect = -20000
                                # compute effect for each value for the options
                                for val in option_values[path[i]]:
                                    x = pd.DataFrame({
                                        path[i]: [val],
                                        path[0]: [bestval[path[0]]]
                                    })
                                    cur_effect = effect.pdf(x)
                                    if max_effect < cur_effect:
                                        max_effect = cur_effect
                                        ite[path[i]] = val

            if multi_paths:
                for mp in multi_paths:
                    for path in mp:
                        cur_g = DiGraph()
                        cur_g.add_nodes_from(path)
                        cur_g.add_edges_from([
                            (path[j], path[j - 1])
                            for j in range(len(path) - 1, 0, -1)
                        ])
                        for i in range(0, len(path)):
                            if i > 0:
                                if cfg["is_intervenable"][path[i]]:
                                    if len(objectives) == 2:
                                        admissable_set = adjustment.admissable_set(
                                            cur_g, [path[i]],
                                            [objectives[0], objectives[1]])
                                        effect = CausalEffect(
                                            df, [path[i]],
                                            [objectives[0], objectives[1]],
                                            variable_types=variable_types,
                                            admissable_set=list(
                                                admissable_set))
                                        max_effect = -20000
                                        # compute effect for each value for the options
                                        for val in option_values[path[i]]:
                                            x = pd.DataFrame({
                                                path[i]: [val],
                                                objectives[0]:
                                                [bestval[objectives[0]]],
                                                objectives[1]:
                                                [bestval[objectives[1]]]
                                            })
                                            cur_effect = effect.pdf(x)
                                            if max_effect < cur_effect:
                                                max_effect = cur_effect
                                                ite[path[i]] = val
                                    elif len(objectives) == 3:
                                        admissable_set = adjustment.admissable_set(
                                            cur_g, [path[i]], [
                                                objectives[0], objectives[1],
                                                objectives[2]
                                            ])
                                        effect = CausalEffect(
                                            df, [path[i]], [
                                                objectives[0], objectives[1],
                                                objectives[2]
                                            ],
                                            variable_types=variable_types,
                                            admissable_set=list(
                                                admissable_set))
                                        max_effect = -20000
                                        # compute effect for each value for the options
                                        for val in option_values[path[i]]:
                                            x = pd.DataFrame({
                                                path[i]: [val],
                                                objectives[0]:
                                                [bestval[objectives[0]]],
                                                objectives[1]:
                                                [bestval[objectives[1]]],
                                                objectives[2]:
                                                [bestval[objectives[2]]]
                                            })
                                            cur_effect = effect.pdf(x)
                                            if max_effect < cur_effect:
                                                max_effect = cur_effect
                                                ite[path[i]] = val
                                    else:
                                        print(
                                            "[ERROR]: number of objectives not supported"
                                        )
                                        return

            for option, value in ite.items():
                config[option] = value
                print("-----next configuration-----\n", config)
                return config

        # single objective treatment effect
        for path in paths:
            import time
            start = time.time()
            cur_g = DiGraph()
            cur_g.add_nodes_from(path)
            cur_g.add_edges_from([(path[j], path[j - 1])
                                  for j in range(len(path) - 1, 0, -1)])

            for i in range(0, len(path)):
                if i > 0:

                    if cfg["is_intervenable"][path[i]]:
                        if len(objectives) < 2:

                            admissable_set = adjustment.admissable_set(
                                cur_g, [path[i]], [path[0]])
                            effect = CausalEffect(
                                df, [path[i]], [path[0]],
                                variable_types=variable_types,
                                admissable_set=list(admissable_set))
                            max_effect = -20000
                            # compute effect for each value for the options

                            for val in option_values[path[i]]:

                                x = pd.DataFrame({
                                    path[i]: [val],
                                    path[0]: [bestval]
                                })
                                cur_effect = effect.pdf(x)
                                if max_effect < cur_effect:
                                    max_effect = cur_effect
                                    ite[path[i]] = val
            print(time.time() - start)
        for option, value in ite.items():
            config[option] = value
        print("-----next configuration-----\n", config)
        return config