class_docstr: Estimate effect of treatment by stratifying the data into bins with
  identical common causes.
  
  Straightforward application of the back-door criterion.
  
  Supports additional parameters as listed below.
code: def estimate_effect(
      self,
      data: pd.DataFrame,
      treatment_value: Any = 1,
      control_value: Any = 0,
      target_units=None,
      **_,
  ):
      self._target_units = target_units
      self._treatment_value = treatment_value
      self._control_value = control_value
      if self.propensity_score_column not in data:
          self.estimate_propensity_score_column(data)
  
      clipped = None
      # Infer the right strata based on clipping threshold
      if self.num_strata == "auto":
          # 0.5 because there are two values for the treatment
          clipping_t = self.clipping_threshold
          num_strata = 0.5 * data.shape[0] / clipping_t
          # To be conservative and allow most strata to be included in the
          # analysis
          strata_found = False
          while not strata_found:
              self.logger.info(
                  "'num_strata' selected as {}".format(num_strata)
              )
              try:
                  clipped = self._get_strata(
                      data,
                      num_strata,
                      self.clipping_threshold,
                  )
                  num_ret_strata = (
                      clipped.groupby(["strata"]).count().reset_index()
                  )
                  # At least 90% of the strata should be included in analysis
                  if num_ret_strata.shape[0] >= 0.5 * num_strata:
                      strata_found = True
                  else:
                      num_strata = int(num_strata / 2)
                      self.logger.info(
                          f"Less than half the strata have at least {self.clipping_threshold} data points. Selecting fewer number of strata."
                      )
                      if num_strata < 2:
                          raise ValueError(
                              "Not enough data to generate at least two strata. This error may be due to a high value of 'clipping_threshold'."
                          )
              except ValueError:
                  self.logger.info(
                      "No strata found with at least {} data points. Selecting fewer number of strata".format(
                          self.clipping_threshold
                      )
                  )
                  num_strata = int(num_strata / 2)
                  if num_strata < 2:
                      raise ValueError(
                          "Not enough data to generate at least two strata. This error may be due to a high value of 'clipping_threshold'."
                      )
      else:
          clipped = self._get_strata(
              data,
              self.num_strata,
              self.clipping_threshold,
          )
  
      # sum weighted outcomes over all strata  (weight by treated population)
      weighted_outcomes = clipped.groupby("strata").agg(
          {
              self._target_estimand.treatment_variable[0]: ["sum"],
              "dbar": ["sum"],
              "d_y": ["sum"],
              "dbar_y": ["sum"],
          }
      )
      weighted_outcomes.columns = [
          "_".join(x)
          for x in weighted_outcomes.columns.to_numpy().ravel()
      ]
      treatment_sum_name = (
          self._target_estimand.treatment_variable[0] + "_sum"
      )
      control_sum_name = "dbar_sum"
  
      weighted_outcomes["d_y_mean"] = (
          weighted_outcomes["d_y_sum"]
          / weighted_outcomes[treatment_sum_name]
      )
      weighted_outcomes["dbar_y_mean"] = (
          weighted_outcomes["dbar_y_sum"]
          / weighted_outcomes["dbar_sum"]
      )
      weighted_outcomes["effect"] = (
          weighted_outcomes["d_y_mean"]
          - weighted_outcomes["dbar_y_mean"]
      )
      total_treatment_population = weighted_outcomes[
          treatment_sum_name
      ].sum()
      total_control_population = weighted_outcomes[
          control_sum_name
      ].sum()
      total_population = (
          total_treatment_population + total_control_population
      )
      self.logger.debug(
          "Total number of data points is {0}, including {1} from treatment and {2} from control.".format(
              total_population,
              total_treatment_population,
              total_control_population,
          )
      )
  
      if target_units == "att":
          est = (
              weighted_outcomes["effect"]
              * weighted_outcomes[treatment_sum_name]
          ).sum() / total_treatment_population
      elif target_units == "atc":
          est = (
              weighted_outcomes["effect"]
              * weighted_outcomes[control_sum_name]
          ).sum() / total_control_population
      elif target_units == "ate":
          est = (
              weighted_outcomes["effect"]
              * (
                  weighted_outcomes[control_sum_name]
                  + weighted_outcomes[treatment_sum_name]
              )
          ).sum() / total_population
      else:
          raise ValueError("Target units string value not supported")
  
      # TODO - how can we add additional information into the returned estimate?
      #        such as how much clipping was done, or per-strata info for debugging?
      estimate = CausalEstimate(
          data=data,
          treatment_name=self._target_estimand.treatment_variable,
          outcome_name=self._target_estimand.outcome_variable,
          estimate=est,
          control_value=control_value,
          treatment_value=treatment_value,
          target_estimand=self._target_estimand,
          realized_estimand_expr=self.symbolic_estimator,
          propensity_scores=data[self.propensity_score_column],
      )
  
      estimate.add_estimator(self)
      return estimate
  
file_path: dowhy/dowhy/causal_estimators/propensity_score_stratification_estimator.py
imports: from typing import Any, List, Optional, Union
  import pandas
  from dowhy.causal_estimator import CausalEstimate, CausalEstimator
  from dowhy.causal_estimators.propensity_score_estimator import PropensityScoreEstimator
  from dowhy.causal_identifier import IdentifiedEstimand
label_desc: Use image node_id 3 for calling the PropensityScoreStratificationEstimator obj's underlying member method code with example usage: obj.estimate_effect(data, treatment_value, control_value, target_units) and returns: estimate