class_docstr: Base class for an estimator of causal effect.
  
  Subclasses implement different estimation methods. All estimation methods are in the package "dowhy.causal_estimators"
class_docstr_tok: ["Base","class","for","an","estimator","of","causal","effect",".","Subclasses","implement","different","estimation","methods",".","All","estimation","methods","are","in","the","package","``","dowhy.causal_estimators","''"]
docstr: Estimate conditional treatment effects. Common method for all estimators that utilizes a specific estimate_effect_fn implemented by each child estimator.
  
  If a numeric effect modifier is provided, it is discretized into quantile bins. If you would like a custom discretization, you can do so yourself: create a new column containing the discretized effect modifier and then include that column's name in the effect_modifier_names argument.
  
  :param data: Pandas dataframe to calculate the conditional effects
  :param estimate_effect_fn: Function that has a single parameter (a data frame) and returns the treatment effect estimate on that data.
  :param effect_modifier_names: Names of effect modifier variables over which the conditional effects will be estimated. If not provided, defaults to the effect modifiers specified during creation of the CausalEstimator object.
  :param num_quantiles: The number of quantiles into which a numeric effect modifier variable is discretized. Does not affect any categorical effect modifiers.
  
  :returns: A (multi-index) dataframe that provides separate effects for each value of the (discretized) effect modifiers.
code: def _estimate_conditional_effects(
      self,
      data: pd.DataFrame,
      estimate_effect_fn,
      effect_modifier_names=None,
      num_quantiles=None,
  ):
      """Estimate conditional treatment effects. Common method for all estimators that utilizes a specific estimate_effect_fn implemented by each child estimator.
  
      If a numeric effect modifier is provided, it is discretized into quantile bins. If you would like a custom discretization, you can do so yourself: create a new column containing the discretized effect modifier and then include that column's name in the effect_modifier_names argument.
  
      :param data: Pandas dataframe to calculate the conditional effects
      :param estimate_effect_fn: Function that has a single parameter (a data frame) and returns the treatment effect estimate on that data.
      :param effect_modifier_names: Names of effect modifier variables over which the conditional effects will be estimated. If not provided, defaults to the effect modifiers specified during creation of the CausalEstimator object.
      :param num_quantiles: The number of quantiles into which a numeric effect modifier variable is discretized. Does not affect any categorical effect modifiers.
  
      :returns: A (multi-index) dataframe that provides separate effects for each value of the (discretized) effect modifiers.
      """
      # Defaulting to class default values if parameters are not provided
      if effect_modifier_names is None:
          effect_modifier_names = self._effect_modifier_names
      if num_quantiles is None:
          num_quantiles = self.num_quantiles_to_discretize_cont_cols
      # Checking that there is at least one effect modifier
      if not effect_modifier_names:
          raise ValueError(
              "At least one effect modifier should be specified to compute conditional effects."
          )
      # Making sure that effect_modifier_names is a list
      effect_modifier_names = parse_state(effect_modifier_names)
      if not all(
          em in self._effect_modifier_names
          for em in effect_modifier_names
      ):
          self.logger.warn(
              "At least one of the provided effect modifiers was not included while fitting the estimator. You may get incorrect results. To resolve, fit the estimator again by providing the updated effect modifiers in estimate_effect()."
          )
      # Making a copy since we are going to be changing effect modifier names
      effect_modifier_names = effect_modifier_names.copy()
      prefix = CausalEstimator.TEMP_CAT_COLUMN_PREFIX
      # For every numeric effect modifier, adding a temp categorical column
      for i in range(len(effect_modifier_names)):
          em = effect_modifier_names[i]
          if pd.api.types.is_numeric_dtype(data[em].dtypes):
              data[prefix + str(em)] = pd.qcut(
                  data[em], num_quantiles, duplicates="drop"
              )
              effect_modifier_names[i] = prefix + str(em)
      # Grouping by effect modifiers and computing effect separately
      by_effect_mods = data.groupby(effect_modifier_names)
      cond_est_fn = lambda x: self._do(
          self._treatment_value, x
      ) - self._do(self._control_value, x)
      conditional_estimates = by_effect_mods.apply(estimate_effect_fn)
      # Deleting the temporary categorical columns
      for em in effect_modifier_names:
          if em.startswith(prefix):
              data.pop(em)
      return conditional_estimates
  
imports: import copy
  import logging
  from collections import namedtuple
  from typing import Dict, List, Optional, Union
  import numpy
  import pandas
  import sympy
  from sklearn.utils import resample
  import dowhy.interpreters
  from dowhy.causal_identifier.identified_estimand import IdentifiedEstimand
  from dowhy.utils.api import parse_state
label_desc: Use image node_id 7 for calling the CausalEstimator obj's underlying member method code with example usage: obj._estimate_conditional_effects(data, estimate_effect_fn, effect_modifier_names, num_quantiles) and returns: conditional_estimates