code: def parent_relevance(
      causal_model: StructuralCausalModel,
      target_node: Any,
      parent_samples: Optional[pd.DataFrame] = None,
      subset_scoring_func: Optional[
          Callable[[np.ndarray, np.ndarray], Union[np.ndarray, float]]
      ] = None,
      num_samples_randomization: int = 5000,
      num_samples_baseline: int = 500,
      max_batch_size: int = 100,
      shapley_config: Optional[ShapleyConfig] = None,
  ) -> Tuple[Dict[Any, Any], np.ndarray]:
      """Estimates the distribution based relevance of the direct parents of the given target_node. This is, the
      relevance of direct parents as input features of the the underlying causal model of target_node. Here, the
      unobserved noise is considered as a direct parent (input) as well. Samples utilized for the estimation are drawn
      from the given causal graph.
  
      By default, the used subset_scoring_func is based on the variance between Y and Y', where Y is the outputs of
      the causal model and Y' the outputs of the models when certain features are randomized. In case of continuous data,
      the feature relevance adds up to Var(Y - Y').
  
      Note: The feature relevance based on the distribution cannot be directly compared with the feature relevance for
      single samples. If this is desired, the set function needs to be defined accordingly.
  
      Related paper:
      Janzing, D., Minorics, L., & Bloebaum, P. (2020).
      Feature relevance quantification in explainable AI: A causal problem.
      In International Conference on Artificial Intelligence and Statistics (pp. 2907-2916). PMLR.
  
      :param causal_model: The fitted structural causal model.
      :param target_node: Node with the causal model of interest.
      :param parent_samples: Samples for the parents of the given target_node. If None is given, new samples are
                             generated based on the graph. These samples are used for randomizing features that are not in the subset.
      :param subset_scoring_func: Set function for estimating the quantity of interest based on the model outcomes. This function
                                  expects two inputs; the outcome of the causal model for some samples if certain features are permuted and the
                                  outcome of the model for the same samples when no features were permuted. The set functions represents the
                                  comparison between the samples, for instance, the variance of deviations. This is then used as the 'characteristic function'
                                  in coalition games when estimating the Shapley values.
      :param num_samples_randomization: Number of samples used as background parent samples for evaluating the set function.
                                        If no parent_samples are given, this represents the number of generated samples from
                                        the joint distribution of the parents and are used for randomizing features that are
                                        not in the subset. Consider increasing this number for more accurate results or reducing it for less memory consumption and faster runtime.
      :param num_samples_baseline: Number of samples on which the set functions are evaluated on. These samples are used as fixed observations for
                                   parents that are in the subset. Consider increasing this number for more accurate results or reducing it for less memory consumption and faster runtime.
      :param max_batch_size: Maximum batch size for estimating multiple predictions at once. This has a significant influence on the
                            overall memory usage. If set to -1, all samples are used in one batch.
      :param shapley_config: :class:`~dowhy.gcm.shapley.ShapleyConfig` for the Shapley estimator.
      :return: There are two return vales. A dictionary with the feature relevance for each direct parent of the given
               target_node and the feature relevance of noise.
      """
      validate_node(causal_model.graph, target_node)
  
      if is_root_node(causal_model.graph, target_node):
          raise ValueError(
              "Cannot compute feature relevance of parents for the target node %s as it is a root node."
              "It does not have parents." % target_node
          )
  
      ordered_predecessors = get_ordered_predecessors(
          causal_model.graph, target_node
      )
  
      if parent_samples is None:
          parent_samples = draw_samples(
              causal_model,
              max(num_samples_randomization, num_samples_baseline),
          )[ordered_predecessors]
  
      if subset_scoring_func is None:
          if isinstance(
              causal_model.causal_mechanism(target_node),
              ProbabilityEstimatorModel,
          ):
              subset_scoring_func = variance_of_matching_values
          else:
              subset_scoring_func = variance_of_deviations
  
      parent_samples = shape_into_2d(
          parent_samples[ordered_predecessors].to_numpy()
      )
      noise_samples = shape_into_2d(
          causal_model.causal_mechanism(target_node).draw_noise_samples(
              parent_samples.shape[0]
          )
      )
      samples_features = np.column_stack(
          [parent_samples.astype(object), noise_samples.astype(object)]
      )
  
      def model(X: np.ndarray) -> np.ndarray:
          return causal_model.causal_mechanism(target_node).evaluate(
              X[:, : -noise_samples.shape[1]],
              X[:, -noise_samples.shape[1] :],
          )
  
      shapley_vales = feature_relevance_distribution(
          model,
          feature_samples=samples_features,
          subset_scoring_func=subset_scoring_func,
          max_num_samples_randomization=num_samples_randomization,
          max_num_baseline_samples=num_samples_baseline,
          max_batch_size=max_batch_size,
          shapley_config=shapley_config,
      )
  
      result = {
          (predecessor, target_node): shapley_vales[i]
          for i, predecessor in enumerate(ordered_predecessors)
      }
  
      return result, shapley_vales[-noise_samples.shape[1] :]
  
file_path: dowhy/dowhy/gcm/feature_relevance.py
imports: from typing import Any, Callable, Dict, Optional, Tuple, Union
  import numpy
  import pandas
  from dowhy.gcm.causal_mechanisms import ProbabilityEstimatorModel
  from dowhy.gcm.causal_models import StructuralCausalModel, validate_node
  from dowhy.gcm.fitting_sampling import draw_samples
  from dowhy.gcm.shapley import ShapleyConfig, estimate_shapley_values
  from dowhy.gcm.stats import marginal_expectation
  from dowhy.gcm.util.general import shape_into_2d, variance_of_deviations, variance_of_matching_values
  from dowhy.graph import get_ordered_predecessors, is_root_node
label_desc: Use image node_id 1 for calling a global function with example usage: parent_relevance(causal_model, target_node, parent_samples, subset_scoring_func, num_samples_randomization, num_samples_baseline, max_batch_size, shapley_config) and returns: result,  shapley_vales, causal_model