code: def crps(
      X: np.ndarray,
      Y: np.ndarray,
      conditional_sampling_method: Callable[[np.ndarray], np.ndarray],
      num_conditional_samples: int = 100,
      normalize: bool = True,
  ) -> float:
      """Estimates the (normalized) Continuous Ranked Probability Score (CRPS) based on the given data and generation
      process. This is used to check the calibration of a probabilistic prediction.
  
      :param X: Observations of the input features.
      :param Y: Observations of the corresponding target value.
      :param conditional_sampling_method: Method to sample from the conditional given an input sample from X.
      :param num_conditional_samples: Number of samples that should be drawn from the conditional to estimate the CRPS.
      :param normalize: If True, the target values are normalized in the continuous case by the standard deviation of the
                        expected Y values. By this, the CRPS become comparable across different scales.
      :return: The Continuous Ranked Probability Score.
      """
  
      def empirical_crps(generated_Y, observed_y):
          """Estimates \int (F(x) - 1_{x >= y})**2 dx = E[|X - y|] - 1/2 E[|X - X'|]
  
          Here, X is generated_Y and y is observed_y. The X' are another set of generated_Y, however, we can also take
          the difference over all combinations to estimate the expectation.
          """
          generated_Y = generated_Y.reshape(-1)
          observed_y = observed_y.squeeze()
  
          return np.mean(
              np.abs(generated_Y - observed_y)
          ) - 0.5 * np.mean(
              np.abs(np.subtract.outer(generated_Y, generated_Y))
          )
  
      if Y.ndim > 1 and Y.shape[1] > 1:
          raise ValueError("Y has to be one dimensional!")
  
      X = shape_into_2d(X)
      Y = Y.reshape(-1)
  
      crps_values = []
  
      categorical = is_categorical(Y)
      if categorical:
          # In the categorical case, this is equivalent to the Brier score. However, the following formulation allows
          # categorical data with more than two classes.
          all_classes = np.unique(Y)
  
          for x, y in zip(X, Y):
              samples = conditional_sampling_method(
                  repmat(x, num_conditional_samples, 1)
              )
  
              sample_categorical_crps = []
              for cat in all_classes:
                  sample_categorical_crps.append(
                      empirical_crps(
                          (samples == cat).astype(int),
                          np.array(y == cat).astype(int),
                      )
                  )
              crps_values.append(np.mean(sample_categorical_crps))
      else:
          std_Y = 1
  
          if normalize:
              std_Y = np.std(Y)
  
              if std_Y == 0:
                  std_Y = 1
  
          for x, y in zip(X, Y):
              crps_values.append(
                  empirical_crps(
                      conditional_sampling_method(
                          repmat(x, num_conditional_samples, 1)
                      )
                      / std_Y,
                      y / std_Y,
                  )
              )
  
      return float(np.mean(np.array(crps_values)))
  
imports: from dataclasses import dataclass
  from functools import partial
  from typing import Any, Callable, Dict, List, Optional, Tuple
  import networkx
  import numpy
  import pandas
  from joblib import Parallel, delayed
  from numpy.matlib import repmat
  from scipy.stats import mode
  from sklearn.metrics import f1_score, mean_squared_error, r2_score
  from sklearn.model_selection import KFold
  from statsmodels.stats.multitest import multipletests
  from tqdm import tqdm
  from dowhy.gcm import ClassifierFCM, PostNonlinearModel, PredictionModel, ProbabilisticCausalModel, config, draw_samples, kernel_based
  from dowhy.gcm.causal_mechanisms import AdditiveNoiseModel, ConditionalStochasticModel, InvertibleFunctionalCausalModel
  from dowhy.gcm.divergence import auto_estimate_kl_divergence
  from dowhy.gcm.falsify import EvaluationResult, falsify_graph, plot_evaluation_results
  from dowhy.gcm.ml import SklearnRegressionModel, create_hist_gradient_boost_classifier, create_hist_gradient_boost_regressor, create_lasso_regressor, create_linear_regressor, create_logistic_regression_classifier, create_random_forest_classifier, create_random_forest_regressor, create_ridge_regressor
  from dowhy.gcm.ml.classification import create_ada_boost_classifier, create_gaussian_nb_classifier, create_knn_classifier, create_polynom_logistic_regression_classifier
  from dowhy.gcm.ml.regression import create_ada_boost_regressor, create_extra_trees_regressor, create_polynom_regressor
  from dowhy.gcm.stats import quantile_based_fwer
  from dowhy.gcm.util.general import is_categorical, set_random_seed, shape_into_2d
  from dowhy.graph import get_ordered_predecessors, is_root_node
label_desc: Use image node_id 6 for calling a global function with example usage: crps(X, Y, conditional_sampling_method, num_conditional_samples, normalize) and returns: float, unknown