Exemple #1
0
    def estimate_effect(self,
                        identified_estimand,
                        method_name=None,
                        test_significance=None,
                        evaluate_effect_strength=True,
                        method_params=None):
        """Estimate the identified causal effect.

        If method_name is provided, uses the provided method. Else, finds a
        suitable method to be used.

        :param identified_estimand: a probability expression
            that represents the effect to be estimated. Output of
            CausalModel.identify_effect method
        :param method_name: (optional) name of the estimation method to be used.
        :returns: an instance of the CausalEstimate class, containing the causal effect estimate
            and other method-dependent information

        """
        if method_name is None:
            pass
        else:
            str_arr = method_name.split(".")
            identifier_name = str_arr[0]
            estimator_name = str_arr[1]
            identified_estimand.set_identifier_method(identifier_name)
            causal_estimator_class = causal_estimators.get_class_object(
                estimator_name + "_estimator")

        # Check if estimator's target estimand is identified
        if identified_estimand.estimands[identifier_name] is None:
            self.logger.warning(
                "No valid identified estimand for using instrumental variables method"
            )
            estimate = CausalEstimate(None, None, None)
        else:
            causal_estimator = causal_estimator_class(
                self._data,
                identified_estimand,
                self._treatment,
                self._outcome,
                test_significance=test_significance,
                evaluate_effect_strength=evaluate_effect_strength,
                params=method_params)
            estimate = causal_estimator.estimate_effect()
            estimate.add_params(
                estimand_type=identified_estimand.estimand_type,
                estimator_class=causal_estimator_class)
        return estimate
Exemple #2
0
    def do(self, x, identified_estimand, method_name=None, method_params=None):
        """Do operator for estimating values of the outcome after intervening on treatment.


        :param identified_estimand: a probability expression
            that represents the effect to be estimated. Output of
            CausalModel.identify_effect method
        :param method_name: any of the estimation method to be used. See docs for estimate_effect method for a list of supported estimation methods.
        :param method_params: Dictionary containing any method-specific parameters. These are passed directly to the estimating method.

        :returns: an instance of the CausalEstimate class, containing the causal effect estimate
            and other method-dependent information

        """
        if method_name is None:
            pass
        else:
            str_arr = method_name.split(".", maxsplit=1)
            print(str_arr)
            identifier_name = str_arr[0]
            estimator_name = str_arr[1]
            identified_estimand.set_identifier_method(identifier_name)
            causal_estimator_class = causal_estimators.get_class_object(
                estimator_name + "_estimator")

        # Check if estimator's target estimand is identified
        if identified_estimand.estimands[identifier_name] is None:
            self.logger.warning(
                "No valid identified estimand for using instrumental variables method"
            )
            estimate = CausalEstimate(None, None, None, None, None)
        else:
            causal_estimator = causal_estimator_class(self._data,
                                                      identified_estimand,
                                                      self._treatment,
                                                      self._outcome,
                                                      test_significance=False,
                                                      params=method_params)
            try:
                estimate = causal_estimator.do(x)
            except NotImplementedError:
                self.logger.error(
                    'Do Operation not implemented or not supported for this estimator.'
                )
                raise NotImplementedError
        return estimate
Exemple #3
0
    def do(self, x, identified_estimand, method_name=None, method_params=None):
        """Estimate the identified causal effect.

        If method_name is provided, uses the provided method. Else, finds a
        suitable method to be used.

        :param identified_estimand: a probability expression
            that represents the effect to be estimated. Output of
            CausalModel.identify_effect method
        :param method_name: (optional) name of the estimation method to be used.
        :returns: an instance of the CausalEstimate class, containing the causal effect estimate
            and other method-dependent information

        """
        if method_name is None:
            pass
        else:
            str_arr = method_name.split(".", maxsplit=1)
            print(str_arr)
            identifier_name = str_arr[0]
            estimator_name = str_arr[1]
            identified_estimand.set_identifier_method(identifier_name)
            causal_estimator_class = causal_estimators.get_class_object(
                estimator_name + "_estimator")

        # Check if estimator's target estimand is identified
        if identified_estimand.estimands[identifier_name] is None:
            self.logger.warning(
                "No valid identified estimand for using instrumental variables method"
            )
            estimate = CausalEstimate(None, None, None)
        else:
            causal_estimator = causal_estimator_class(self._data,
                                                      identified_estimand,
                                                      self._treatment,
                                                      self._outcome,
                                                      test_significance=False,
                                                      params=method_params)
            try:
                estimate = causal_estimator.do(x)
            except NotImplementedError:
                self.logger.error(
                    'Do Operation not implemented or not supported for this estimator.'
                )
                raise NotImplementedError
        return estimate
Exemple #4
0
    def estimate_effect(self,
                        identified_estimand,
                        method_name=None,
                        control_value=0,
                        treatment_value=1,
                        test_significance=None,
                        evaluate_effect_strength=False,
                        confidence_intervals=False,
                        target_units="ate",
                        effect_modifiers=None,
                        method_params=None):
        """Estimate the identified causal effect.

        Currently requires an explicit method name to be specified. Method names follow the convention of identification method followed by the specific estimation method: "[backdoor/iv].estimation_method_name". Following methods are supported.
            * Propensity Score Matching: "backdoor.propensity_score_matching"
            * Propensity Score Stratification: "backdoor.propensity_score_stratification"
            * Propensity Score-based Inverse Weighting: "backdoor.propensity_score_weighting"
            * Linear Regression: "backdoor.linear_regression"
            * Generalized Linear Models (e.g., logistic regression): "backdoor.generalized_linear_model"
            * Instrumental Variables: "iv.instrumental_variable"
            * Regression Discontinuity: "iv.regression_discontinuity"

        In addition, you can directly call any of the EconML estimation methods. The convention is "backdoor.econml.path-to-estimator-class". For example, for the double machine learning estimator ("DML" class) that is located inside "dml" module of EconML, you can use the method name, "backdoor.econml.dml.DML". CausalML estimators can also be called. See `this demo notebook <https://microsoft.github.io/dowhy/example_notebooks/dowhy-conditional-treatment-effects.html>`_.


        :param identified_estimand: a probability expression
            that represents the effect to be estimated. Output of
            CausalModel.identify_effect method
        :param method_name: name of the estimation method to be used.
        :param control_value: Value of the treatment in the control group, for effect estimation.  If treatment is multi-variate, this can be a list.
        :param treatment_value: Value of the treatment in the treated group, for effect estimation. If treatment is multi-variate, this can be a list.
        :param test_significance: Binary flag on whether to additionally do a statistical signficance test for the estimate.
        :param evaluate_effect_strength: (Experimental) Binary flag on whether to estimate the relative strength of the treatment's effect. This measure can be used to compare different treatments for the same outcome (by running this method with different treatments sequentially).
        :param confidence_intervals: (Experimental) Binary flag indicating whether confidence intervals should be computed.
        :param target_units: (Experimental) The units for which the treatment effect should be estimated. This can be of three types. (1) a string for common specifications of target units (namely, "ate", "att" and "atc"), (2) a lambda function that can be used as an index for the data (pandas DataFrame), or (3) a new DataFrame that contains values of the effect_modifiers and effect will be estimated only for this new data.
        :param effect_modifiers: Names of effect modifier variables can be (optionally) specified here too, since they do not affect identification. If None, the effect_modifiers from the CausalModel are used.
        :param method_params: Dictionary containing any method-specific parameters. These are passed directly to the estimating method. See the docs for each estimation method for allowed method-specific params.

        :returns: An instance of the CausalEstimate class, containing the causal effect estimate
            and other method-dependent information

        """
        if effect_modifiers is None:
            effect_modifiers = self._effect_modifiers

        if method_name is None:
            #TODO add propensity score as default backdoor method, iv as default iv method, add an informational message to show which method has been selected.
            pass
        else:
            # TODO add dowhy as a prefix to all dowhy estimators
            num_components = len(method_name.split("."))
            str_arr = method_name.split(".", maxsplit=1)
            identifier_name = str_arr[0]
            estimator_name = str_arr[1]
            identified_estimand.set_identifier_method(identifier_name)
            # This is done as all dowhy estimators have two parts and external ones have two or more parts
            if num_components > 2:
                estimator_package = estimator_name.split(".")[0]
                if estimator_package == 'dowhy':  # For updated dowhy methods
                    estimator_method = estimator_name.split(".", maxsplit=1)[
                        1]  # discard dowhy from the full package name
                    causal_estimator_class = causal_estimators.get_class_object(
                        estimator_method + "_estimator")
                else:
                    third_party_estimator_package = estimator_package
                    causal_estimator_class = causal_estimators.get_class_object(
                        third_party_estimator_package)
                    if method_params is None:
                        method_params = {}
                    # Define the third-party estimation method to be used
                    method_params["_" + third_party_estimator_package +
                                  "_methodname"] = estimator_name
            else:  # For older dowhy methods
                # Process the dowhy estimators
                causal_estimator_class = causal_estimators.get_class_object(
                    estimator_name + "_estimator")

        # Check if estimator's target estimand is identified
        if identified_estimand.estimands[identifier_name] is None:
            self.logger.warning("No valid identified estimand available.")
            estimate = CausalEstimate(None,
                                      None,
                                      None,
                                      control_value=control_value,
                                      treatment_value=treatment_value)
        else:
            causal_estimator = causal_estimator_class(
                self._data,
                identified_estimand,
                self._treatment,
                self._outcome,  #names of treatment and outcome
                control_value=control_value,
                treatment_value=treatment_value,
                test_significance=test_significance,
                evaluate_effect_strength=evaluate_effect_strength,
                confidence_intervals=confidence_intervals,
                target_units=target_units,
                effect_modifiers=effect_modifiers,
                params=method_params)
            estimate = causal_estimator.estimate_effect()
            # Store parameters inside estimate object for refutation methods
            # TODO: This add_params needs to move to the estimator class
            # inside estimate_effect and estimate_conditional_effect
            estimate.add_params(
                estimand_type=identified_estimand.estimand_type,
                estimator_class=causal_estimator_class,
                test_significance=test_significance,
                evaluate_effect_strength=evaluate_effect_strength,
                confidence_intervals=confidence_intervals,
                target_units=target_units,
                effect_modifiers=effect_modifiers,
                method_params=method_params)
        return estimate
Exemple #5
0
    def estimate_effect(self, identified_estimand, method_name=None,
                        control_value = 0,
                        treatment_value = 1,
                        test_significance=None, evaluate_effect_strength=False,
                        confidence_intervals=False,
                        target_units="ate", effect_modifiers=None,
                        method_params=None):
        """Estimate the identified causal effect.

        If method_name is provided, uses the provided method. Else, finds a
        suitable method to be used.

        :param identified_estimand: a probability expression
            that represents the effect to be estimated. Output of
            CausalModel.identify_effect method
        :param method_name: (optional) name of the estimation method to be used.
        :returns: an instance of the CausalEstimate class, containing the causal effect estimate
            and other method-dependent information

        """
        if effect_modifiers is None:
            effect_modifiers = self._effect_modifiers

        if method_name is None:
            #TODO add propensity score as default backdoor method, iv as default iv method, add an informational message to show which method has been selected.
            pass
        else:
            str_arr = method_name.split(".", maxsplit=1)
            identifier_name = str_arr[0]
            estimator_name = str_arr[1]
            identified_estimand.set_identifier_method(identifier_name)
            if estimator_name.startswith("econml"):
                causal_estimator_class =causal_estimators.get_class_object("econml_cate_estimator")
                if method_params is None:
                    method_params = {}
                method_params["_econml_methodname"] = estimator_name
            else:
                causal_estimator_class = causal_estimators.get_class_object(estimator_name + "_estimator")

        # Check if estimator's target estimand is identified
        if identified_estimand.estimands[identifier_name] is None:
            self.logger.warning("No valid identified estimand for using instrumental variables method")
            estimate = CausalEstimate(None, None, None)
        else:
            causal_estimator = causal_estimator_class(
                self._data,
                identified_estimand,
                self._treatment, self._outcome, #names of treatment and outcome
                control_value = control_value,
                treatment_value = treatment_value,
                test_significance=test_significance,
                evaluate_effect_strength=evaluate_effect_strength,
                confidence_intervals = confidence_intervals,
                target_units = target_units,
                effect_modifiers = effect_modifiers,
                params=method_params
            )
            estimate = causal_estimator.estimate_effect()
            # Store parameters inside estimate object for refutation methods
            estimate.add_params(
                estimand_type=identified_estimand.estimand_type,
                estimator_class=causal_estimator_class,
                test_significance=test_significance,
                evaluate_effect_strength=evaluate_effect_strength,
                confidence_intervals=confidence_intervals,
                target_units=target_units,
                effect_modifiers=effect_modifiers,
                method_params=method_params
            )
        return estimate
Exemple #6
0
    def do(self,
           x,
           identified_estimand,
           method_name=None,
           fit_estimator=True,
           method_params=None):
        """Do operator for estimating values of the outcome after intervening on treatment.

        :param x: interventional value of the treatment variable
        :param identified_estimand: a probability expression
            that represents the effect to be estimated. Output of
            CausalModel.identify_effect method
        :param method_name: any of the estimation method to be used. See docs for estimate_effect method for a list of supported estimation methods.
        :param fit_estimator: Boolean flag on whether to fit the estimator.
        Setting it to False is useful to compute the do-operation on new data using a previously fitted estimator.
        :param method_params: Dictionary containing any method-specific parameters. These are passed directly to the estimating method.

        :returns: an instance of the CausalEstimate class, containing the causal effect estimate
            and other method-dependent information

        """
        if method_name is None:
            pass
        else:
            str_arr = method_name.split(".", maxsplit=1)
            identifier_name = str_arr[0]
            estimator_name = str_arr[1]
            identified_estimand.set_identifier_method(identifier_name)
            causal_estimator_class = causal_estimators.get_class_object(
                estimator_name + "_estimator")

        # Check if estimator's target estimand is identified
        if identified_estimand.estimands[identifier_name] is None:
            self.logger.warning(
                "No valid identified estimand for using instrumental variables method"
            )
            estimate = CausalEstimate(None, None, None, None, None)
        else:
            if fit_estimator:
                # Note that while the name of the variable is the same,
                # "self.causal_estimator", this estimator takes in less
                # parameters than the same from the
                # estimate_effect code. It is not advisable to use the
                # estimator from this function to call estimate_effect
                # with fit_estimator=False.
                self.causal_estimator = causal_estimator_class(
                    self._data,
                    identified_estimand,
                    self._treatment,
                    self._outcome,
                    test_significance=False,
                    params=method_params)
            else:
                # Estimator had been computed in a previous call
                assert self.causal_estimator is not None
            try:
                estimate = self.causal_estimator.do(x)
            except NotImplementedError:
                self.logger.error(
                    'Do Operation not implemented or not supported for this estimator.'
                )
                raise NotImplementedError
        return estimate
Exemple #7
0
    def estimate_effect(self, identified_estimand, method_name=None,
                        control_value = 0,
                        treatment_value = 1,
                        test_significance=None, evaluate_effect_strength=False,
                        confidence_intervals=False,
                        target_units="ate", effect_modifiers=None,
                        method_params=None):
        """Estimate the identified causal effect.

        Currently requires an explicit method name to be specified.

        :param identified_estimand: a probability expression
            that represents the effect to be estimated. Output of
            CausalModel.identify_effect method
        :param method_name: (optional) name of the estimation method to be used.
        :param control_value: Value of the treatment in the control group, for effect estimation.  If treatment is multi-variate, this can be a list.
        :param treatment_value: Value of the treatment in the treated group, for effect estimation. If treatment is multi-variate, this can be a list.
        :param test_significance: Binary flag on whether to additionally do a statistical signficance test for the estimate.
        :param evaluate_effect_strength: (Experimental) Binary flag on whether to estimate the relative strength of the treatment's effect. This measure can be used to compare different treatments for the same outcome (by running this method with different treatments sequentially).
        :param confidence_intervals: (Experimental) Binary flag indicating whether confidence intervals should be computed.
        :param target_units: (Experimental) The units for which the treatment effect should be estimated. This can be a string for common specifications of target units (namely, "ate", "att" and "atc"). It can also be a lambda function that can be used as an index for the data (pandas DataFrame). Alternatively, it can be a new DataFrame that contains values of the effect_modifiers and effect will be estimated only for this new data.
        :param effect_modifiers: Effect modifiers can be (optionally) specified here too, since they do not affect identification. If None, the effect_modifiers from the CausalModel are used.
        :param method_params: Dictionary containing any method-specific parameters. These are passed directly to the estimating method.

        :returns: An instance of the CausalEstimate class, containing the causal effect estimate
            and other method-dependent information

        """
        if effect_modifiers is None:
            effect_modifiers = self._effect_modifiers

        if method_name is None:
            #TODO add propensity score as default backdoor method, iv as default iv method, add an informational message to show which method has been selected.
            pass
        else:
            str_arr = method_name.split(".", maxsplit=1)
            identifier_name = str_arr[0]
            estimator_name = str_arr[1]
            identified_estimand.set_identifier_method(identifier_name)
            if estimator_name.startswith("econml"):
                causal_estimator_class =causal_estimators.get_class_object("econml_cate_estimator")
                if method_params is None:
                    method_params = {}
                method_params["_econml_methodname"] = estimator_name
            else:
                causal_estimator_class = causal_estimators.get_class_object(estimator_name + "_estimator")

        # Check if estimator's target estimand is identified
        if identified_estimand.estimands[identifier_name] is None:
            self.logger.warning("No valid identified estimand for using instrumental variables method")
            estimate = CausalEstimate(None, None, None)
        else:
            causal_estimator = causal_estimator_class(
                self._data,
                identified_estimand,
                self._treatment, self._outcome, #names of treatment and outcome
                control_value = control_value,
                treatment_value = treatment_value,
                test_significance=test_significance,
                evaluate_effect_strength=evaluate_effect_strength,
                confidence_intervals = confidence_intervals,
                target_units = target_units,
                effect_modifiers = effect_modifiers,
                params=method_params
            )
            estimate = causal_estimator.estimate_effect()
            # Store parameters inside estimate object for refutation methods
            estimate.add_params(
                estimand_type=identified_estimand.estimand_type,
                estimator_class=causal_estimator_class,
                test_significance=test_significance,
                evaluate_effect_strength=evaluate_effect_strength,
                confidence_intervals=confidence_intervals,
                target_units=target_units,
                effect_modifiers=effect_modifiers,
                method_params=method_params
            )
        return estimate