class_docstr: Simple matching estimator for binary treatments based on a distance
  metric.
  
  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,
      **_,
  ):
      # this assumes a binary treatment regime
      self._target_units = target_units
      self._treatment_value = treatment_value
      self._control_value = control_value
      updated_df = pd.concat(
          [
              self._observed_common_causes,
              data[
                  [
                      self._target_estimand.outcome_variable[0],
                      self._target_estimand.treatment_variable[0],
                  ]
              ],
          ],
          axis=1,
      )
      if self.exact_match_cols is not None:
          updated_df = pd.concat(
              [updated_df, data[self.exact_match_cols]], axis=1
          )
      treated = updated_df.loc[
          data[self._target_estimand.treatment_variable[0]] == 1
      ]
      control = updated_df.loc[
          data[self._target_estimand.treatment_variable[0]] == 0
      ]
      numtreatedunits = treated.shape[0]
      numcontrolunits = control.shape[0]
  
      fit_att, fit_atc = False, False
      est = None
      # TODO remove neighbors that are more than a given radius apart
      if target_units == "att":
          fit_att = True
      elif target_units == "atc":
          fit_atc = True
      elif target_units == "ate":
          fit_att = True
          fit_atc = True
      else:
          raise ValueError("Target units string value not supported")
  
      if fit_att:
          # estimate ATT on treated by summing over difference between matched neighbors
          if self.exact_match_cols is None:
              control_neighbors = NearestNeighbors(
                  n_neighbors=self.num_matches_per_unit,
                  metric=self.distance_metric,
                  algorithm="ball_tree",
                  **self.distance_metric_params,
              ).fit(
                  control[self._observed_common_causes.columns].values
              )
              distances, indices = control_neighbors.kneighbors(
                  treated[self._observed_common_causes.columns].values
              )
              self.logger.debug("distances:")
              self.logger.debug(distances)
  
              att = 0
  
              for i in range(numtreatedunits):
                  treated_outcome = treated.iloc[i][
                      self._target_estimand.outcome_variable[0]
                  ].item()
                  control_outcome = np.mean(
                      control.iloc[indices[i]][
                          self._target_estimand.outcome_variable[0]
                      ].values
                  )
                  att += treated_outcome - control_outcome
  
              att /= numtreatedunits
              if target_units == "att":
                  est = att
              elif target_units == "ate":
                  est = att * numtreatedunits
  
              # Return indices in the original dataframe
              self.matched_indices_att = {}
              treated_df_index = treated.index.tolist()
              for i in range(numtreatedunits):
                  self.matched_indices_att[
                      treated_df_index[i]
                  ] = control.iloc[indices[i]].index.tolist()
          else:
              grouped = updated_df.groupby(self.exact_match_cols)
              att = 0
              for name, group in grouped:
                  treated = group.loc[
                      group[self._target_estimand.treatment_variable[0]]
                      == 1
                  ]
                  control = group.loc[
                      group[self._target_estimand.treatment_variable[0]]
                      == 0
                  ]
                  if treated.shape[0] == 0:
                      continue
                  control_neighbors = NearestNeighbors(
                      n_neighbors=self.num_matches_per_unit,
                      metric=self.distance_metric,
                      algorithm="ball_tree",
                      **self.distance_metric_params,
                  ).fit(
                      control[
                          self._observed_common_causes.columns
                      ].values
                  )
                  distances, indices = control_neighbors.kneighbors(
                      treated[
                          self._observed_common_causes.columns
                      ].values
                  )
                  self.logger.debug("distances:")
                  self.logger.debug(distances)
  
                  for i in range(numtreatedunits):
                      treated_outcome = treated.iloc[i][
                          self._target_estimand.outcome_variable[0]
                      ].item()
                      control_outcome = np.mean(
                          control.iloc[indices[i]][
                              self._target_estimand.outcome_variable[0]
                          ].values
                      )
                      att += treated_outcome - control_outcome
                      # self.matched_indices_att[treated_df_index[i]] = control.iloc[indices[i]].index.tolist()
  
              att /= numtreatedunits
  
              if target_units == "att":
                  est = att
              elif target_units == "ate":
                  est = att * numtreatedunits
  
      if fit_atc:
          # Now computing ATC
          treated_neighbors = NearestNeighbors(
              n_neighbors=self.num_matches_per_unit,
              metric=self.distance_metric,
              algorithm="ball_tree",
              **self.distance_metric_params,
          ).fit(treated[self._observed_common_causes.columns].values)
          distances, indices = treated_neighbors.kneighbors(
              control[self._observed_common_causes.columns].values
          )
  
          atc = 0
          for i in range(numcontrolunits):
              control_outcome = control.iloc[i][
                  self._target_estimand.outcome_variable[0]
              ].item()
              treated_outcome = np.mean(
                  treated.iloc[indices[i]][
                      self._target_estimand.outcome_variable[0]
                  ].values
              )
              atc += treated_outcome - control_outcome
  
          atc /= numcontrolunits
  
          if target_units == "atc":
              est = atc
          elif target_units == "ate":
              est += atc * numcontrolunits
              est /= numtreatedunits + numcontrolunits
  
          # Return indices in the original dataframe
          self.matched_indices_atc = {}
          control_df_index = control.index.tolist()
          for i in range(numcontrolunits):
              self.matched_indices_atc[
                  control_df_index[i]
              ] = treated.iloc[indices[i]].index.tolist()
  
      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,
      )
  
      estimate.add_estimator(self)
      return estimate
  
file_path: dowhy/dowhy/causal_estimators/distance_matching_estimator.py
imports: from typing import Any, List, Optional, Union
  import numpy
  import pandas
  from sklearn.neighbors import NearestNeighbors
  from dowhy.causal_estimator import CausalEstimate, CausalEstimator
  from dowhy.causal_identifier import IdentifiedEstimand
label_desc: Use image node_id 3 for calling the DistanceMatchingEstimator obj's underlying member method code with example usage: obj.estimate_effect(data, treatment_value, control_value, target_units) and returns: estimate