parameters: (self, X, y=None, name=None)
return_statement: return EBMExplanation(
              "local",
              internal_obj,
              feature_names=term_names,
              feature_types=['categorical' if x == 'nominal' or x == 'ordinal' else x for x in term_types],
              name=gen_name_from_class(self) if name is None else name,
              selector=selector,
          )
docstring: Provides local explanations for provided samples.
  
          Args:
              X: Numpy array for X to explain.
              y: Numpy vector for y to explain.
              name: User-defined explanation name.
  
          Returns:
              An explanation object, visualizing feature-value pairs
              for each sample as horizontal bar charts.
docstring_summary: Provides local explanations for provided samples.
docstring_tokens: Provides local explanations for provided samples .
function: def explain_local(self, X, y=None, name=None):
          """ Provides local explanations for provided samples.
  
          Args:
              X: Numpy array for X to explain.
              y: Numpy vector for y to explain.
              name: User-defined explanation name.
  
          Returns:
              An explanation object, visualizing feature-value pairs
              for each sample as horizontal bar charts.
          """
  
          # Produce feature value pairs for each sample.
          # Values are the model graph score per respective term.
  
          check_is_fitted(self, "has_fitted_")
  
          X, n_samples = clean_X(X)
  
          if y is not None:
              if is_classifier(self):
                  y = clean_vector(y, True, "y")
                  y = np.array([self._class_idx_[el] for el in y], dtype=np.int64)
              else:
                  y = clean_vector(y, False, "y")
  
              if n_samples != len(y):
                  msg = f"X has {n_samples} samples and y has {len(y)} samples"
                  _log.error(msg)
                  raise ValueError(msg)
  
          term_names = self.get_feature_names_out()
          term_types = self.get_feature_types_out()
  
          data_dicts = []
          perf_list = []
          if n_samples == 0:
              X_unified = np.empty((0, len(self.feature_names_in_)), dtype=np.object_)
          else:
              X_unified, _, _ = unify_data2(X, n_samples, self.feature_names_in_, self.feature_types_in_, True)
  
              intercept = self.intercept_
              if not is_classifier(self) or len(self.classes_) <= 2:
                  if isinstance(intercept, np.ndarray) or isinstance(intercept, list):
                      intercept = intercept[0]
  
              for _ in range(n_samples):
                  data_dict = {
                      "type": "univariate",
                      "names": [None] * len(self.term_features_),
                      "scores": [None] * len(self.term_features_),
                      "values": [None] * len(self.term_features_),
                      "extra": {"names": ["Intercept"], "scores": [intercept], "values": [1]},
                  }
                  if is_classifier(self):
                      data_dict["meta"] = {
                          "label_names": self.classes_.tolist()  # Classes should be numpy array, convert to list.
                      }
                  data_dicts.append(data_dict)
  
              for term_idx, binned_data in eval_terms(X, n_samples, self.feature_names_in_, self.feature_types_in_, self.bins_, self.term_features_):
                  scores = self.additive_terms_[term_idx][tuple(binned_data)]
                  feature_idxs = self.term_features_[term_idx]
                  for row_idx in range(n_samples):
                      term_name = term_names[term_idx]
                      data_dicts[row_idx]["names"][term_idx] = term_name
                      data_dicts[row_idx]["scores"][term_idx] = scores[row_idx]
                      if len(feature_idxs) == 1:
                          data_dicts[row_idx]["values"][term_idx] = X_unified[row_idx, feature_idxs[0]]
                      else:
                          data_dicts[row_idx]["values"][term_idx] = ""
  
              scores = ebm_decision_function(
                  X, 
                  n_samples, 
                  self.feature_names_in_, 
                  self.feature_types_in_, 
                  self.bins_, 
                  self.intercept_, 
                  self.additive_terms_, 
                  self.term_features_
              )
  
              if is_classifier(self):
                  # Handle binary classification case -- softmax only works with 0s appended
                  if scores.ndim == 1:
                      scores = np.c_[np.zeros(scores.shape), scores]
  
                  scores = softmax(scores)
  
              perf_dicts = gen_perf_dicts(scores, y, is_classifier(self))
              for row_idx in range(n_samples):
                  perf = None if perf_dicts is None else perf_dicts[row_idx]
                  perf_list.append(perf)
                  data_dicts[row_idx]["perf"] = perf
  
          selector = gen_local_selector(data_dicts, is_classification=is_classifier(self))
  
          additive_terms = remove_last2(self.additive_terms_, self.bin_weights_)
          for term_idx, feature_idxs in enumerate(self.term_features_):
              additive_terms[term_idx] = trim_tensor(additive_terms[term_idx], trim_low=[True] * len(feature_idxs))
  
          internal_obj = {
              "overall": None,
              "specific": data_dicts,
              "mli": [
                  {
                      "explanation_type": "ebm_local",
                      "value": {
                          "scores": additive_terms,
                          "intercept": self.intercept_,
                          "perf": perf_list,
                      },
                  }
              ],
          }
          internal_obj["mli"].append(
              {
                  "explanation_type": "evaluation_dataset",
                  "value": {"dataset_x": X_unified, "dataset_y": y},
              }
          )
  
          return EBMExplanation(
              "local",
              internal_obj,
              feature_names=term_names,
              feature_types=['categorical' if x == 'nominal' or x == 'ordinal' else x for x in term_types],
              name=gen_name_from_class(self) if name is None else name,
              selector=selector,
          )
function_tokens: def explain_local ( self , X , y = None , name = None ) : # Produce feature value pairs for each sample. # Values are the model graph score per respective term. check_is_fitted ( self , "has_fitted_" ) X , n_samples = clean_X ( X ) if y is not None : if is_classifier ( self ) : y = clean_vector ( y , True , "y" ) y = np . array ( [ self . _class_idx_ [ el ] for el in y ] , dtype = np . int64 ) else : y = clean_vector ( y , False , "y" ) if n_samples != len ( y ) : msg = f"X has {n_samples} samples and y has {len(y)} samples" _log . error ( msg ) raise ValueError ( msg ) term_names = self . get_feature_names_out ( ) term_types = self . get_feature_types_out ( ) data_dicts = [ ] perf_list = [ ] if n_samples == 0 : X_unified = np . empty ( ( 0 , len ( self . feature_names_in_ ) ) , dtype = np . object_ ) else : X_unified , _ , _ = unify_data2 ( X , n_samples , self . feature_names_in_ , self . feature_types_in_ , True ) intercept = self . intercept_ if not is_classifier ( self ) or len ( self . classes_ ) <= 2 : if isinstance ( intercept , np . ndarray ) or isinstance ( intercept , list ) : intercept = intercept [ 0 ] for _ in range ( n_samples ) : data_dict = { "type" : "univariate" , "names" : [ None ] * len ( self . term_features_ ) , "scores" : [ None ] * len ( self . term_features_ ) , "values" : [ None ] * len ( self . term_features_ ) , "extra" : { "names" : [ "Intercept" ] , "scores" : [ intercept ] , "values" : [ 1 ] } , } if is_classifier ( self ) : data_dict [ "meta" ] = { "label_names" : self . classes_ . tolist ( ) # Classes should be numpy array, convert to list. } data_dicts . append ( data_dict ) for term_idx , binned_data in eval_terms ( X , n_samples , self . feature_names_in_ , self . feature_types_in_ , self . bins_ , self . term_features_ ) : scores = self . additive_terms_ [ term_idx ] [ tuple ( binned_data ) ] feature_idxs = self . term_features_ [ term_idx ] for row_idx in range ( n_samples ) : term_name = term_names [ term_idx ] data_dicts [ row_idx ] [ "names" ] [ term_idx ] = term_name data_dicts [ row_idx ] [ "scores" ] [ term_idx ] = scores [ row_idx ] if len ( feature_idxs ) == 1 : data_dicts [ row_idx ] [ "values" ] [ term_idx ] = X_unified [ row_idx , feature_idxs [ 0 ] ] else : data_dicts [ row_idx ] [ "values" ] [ term_idx ] = "" scores = ebm_decision_function ( X , n_samples , self . feature_names_in_ , self . feature_types_in_ , self . bins_ , self . intercept_ , self . additive_terms_ , self . term_features_ ) if is_classifier ( self ) : # Handle binary classification case -- softmax only works with 0s appended if scores . ndim == 1 : scores = np . c_ [ np . zeros ( scores . shape ) , scores ] scores = softmax ( scores ) perf_dicts = gen_perf_dicts ( scores , y , is_classifier ( self ) ) for row_idx in range ( n_samples ) : perf = None if perf_dicts is None else perf_dicts [ row_idx ] perf_list . append ( perf ) data_dicts [ row_idx ] [ "perf" ] = perf selector = gen_local_selector ( data_dicts , is_classification = is_classifier ( self ) ) additive_terms = remove_last2 ( self . additive_terms_ , self . bin_weights_ ) for term_idx , feature_idxs in enumerate ( self . term_features_ ) : additive_terms [ term_idx ] = trim_tensor ( additive_terms [ term_idx ] , trim_low = [ True ] * len ( feature_idxs ) ) internal_obj = { "overall" : None , "specific" : data_dicts , "mli" : [ { "explanation_type" : "ebm_local" , "value" : { "scores" : additive_terms , "intercept" : self . intercept_ , "perf" : perf_list , } , } ] , } internal_obj [ "mli" ] . append ( { "explanation_type" : "evaluation_dataset" , "value" : { "dataset_x" : X_unified , "dataset_y" : y } , } ) return EBMExplanation ( "local" , internal_obj , feature_names = term_names , feature_types = [ 'categorical' if x == 'nominal' or x == 'ordinal' else x for x in term_types ] , name = gen_name_from_class ( self ) if name is None else name , selector = selector , )