class_docstr: Represents the categorical functional causal model of the form
      Y = f(X, N),
  where X is the input (typically, direct causal parents of Y) and the noise N here is uniform on [0, 1]. The model
  is mostly based on a standard classification model that outputs probabilities. In order to generate a new random
  sample given an input x, the return value y is uniformly sampled based on the class probabilities p(y | x). Here,
  the noise is used to make this sampling process deterministic by using the cumulative distribution functions defined
  by the given inputs.
class_docstr_tok: ["Represents","the","categorical","functional","causal","model","of","the","form","Y","=","f","(","X",",","N",")",",","where","X","is","the","input","(","typically",",","direct","causal","parents","of","Y",")","and","the","noise","N","here","is","uniform","on","[","0",",","1","]",".","The","model","is","mostly","based","on","a","standard","classification","model","that","outputs","probabilities",".","In","order","to","generate","a","new","random","sample","given","an","input","x",",","the","return","value","y","is","uniformly","sampled","based","on","the","class","probabilities","p","(","y","|","x",")",".","Here",",","the","noise","is","used","to","make","this","sampling","process","deterministic","by","using","the","cumulative","distribution","functions","defined","by","the","given","inputs","."]
docstr: Evaluates the model Y = f(X, N), where X are the parent_samples and N the noise_samples. Here, the
  cumulative distribution functions are defined by the parent_samples. For instance, lets say we have 2
  classes, n = 0.7 and an input x with p(y = 0| x) = 0.6 and p(y = 1| x) = 0.4, then we get y = 1 as a return
  value. This is because p(y = 0| x) < n <= 1.0, i.e. n falls into the bucket that is spanned by p(y = 1| x).
  
  :param parent_samples: Samples from the inputs X.
  :param noise_samples: Samples from the noise on [0, 1].
  :return: Class labels Y based on the inputs and noise.
docstr_tok: ["Evaluates","the","model","Y","=","f","(","X",",","N",")",",","where","X","are","the","parent_samples","and","N","the","noise_samples",".","Here",",","the","cumulative","distribution","functions","are","defined","by","the","parent_samples",".","For","instance",",","lets","say","we","have","2","classes",",","n","=","0.7","and","an","input","x","with","p","(","y","=","0|","x",")","=","0.6","and","p","(","y","=","1|","x",")","=","0.4",",","then","we","get","y","=","1","as","a","return","value",".","This","is","because","p","(","y","=","0|","x",")","<","n","<","=","1.0",",","i.e",".","n","falls","into","the","bucket","that","is","spanned","by","p","(","y","=","1|","x",")",".",":","param","parent_samples",":","Samples","from","the","inputs","X.",":","param","noise_samples",":","Samples","from","the","noise","on","[","0",",","1","]",".",":","return",":","Class","labels","Y","based","on","the","inputs","and","noise","."]
code: def evaluate(
      self, parent_samples: np.ndarray, noise_samples: np.ndarray
  ) -> np.ndarray:
      """Evaluates the model Y = f(X, N), where X are the parent_samples and N the noise_samples. Here, the
      cumulative distribution functions are defined by the parent_samples. For instance, lets say we have 2
      classes, n = 0.7 and an input x with p(y = 0| x) = 0.6 and p(y = 1| x) = 0.4, then we get y = 1 as a return
      value. This is because p(y = 0| x) < n <= 1.0, i.e. n falls into the bucket that is spanned by p(y = 1| x).
  
      :param parent_samples: Samples from the inputs X.
      :param noise_samples: Samples from the noise on [0, 1].
      :return: Class labels Y based on the inputs and noise.
      """
      noise_samples = shape_into_2d(noise_samples)
      indices = np.argmax(
          np.cumsum(self.estimate_probabilities(parent_samples), axis=1)
          >= noise_samples,
          axis=1,
      )
  
      # Looks for the first index where the cumulative sum of the probabilities is larger than the threshold.
      # Note that if there are multiple indices with the same maximum value (as in this case here), the argmax
      # function returns the first index.
      return shape_into_2d(np.array(self.get_class_names(indices)))
  
imports: import copy
  from abc import ABC, abstractmethod
  from typing import List, Optional
  import numpy
  from dowhy.gcm.ml import ClassificationModel, PredictionModel
  from dowhy.gcm.ml.regression import InvertibleFunction, SklearnRegressionModel
  from dowhy.gcm.util.general import is_categorical, is_discrete, shape_into_2d
label_desc: Use image node_id 3 for calling the ClassifierFCM obj's underlying member method code with example usage: obj.evaluate(parent_samples, noise_samples) and returns: shape_into_2d