docstr: Get prototypes for each class using the encoder or k-d trees.
  The prototypes are used for the encoder loss term or to calculate the optional trust scores.
  
  Parameters
  ----------
  train_data
      Representative sample from the training data.
  trustscore_kwargs
      Optional arguments to initialize the trust scores method.
  d_type
      Pairwise distance metric used for categorical variables. Currently, ``'abdm'``, ``'mvdm'`` and
      ``'abdm-mvdm'`` are supported. ``'abdm'`` infers context from the other variables while ``'mvdm'`` uses
      the model predictions. ``'abdm-mvdm'`` is a weighted combination of the two metrics.
  w
      Weight on ``'abdm'`` (between 0. and 1.) distance if `d_type` equals ``'abdm-mvdm'``.
  disc_perc
      List with percentiles used in binning of numerical features used for the ``'abdm'``
      and ``'abdm-mvdm'`` pairwise distance measures.
  standardize_cat_vars
      Standardize numerical values of categorical variables if ``True``.
  smooth
      Smoothing exponent between 0 and 1 for the distances. Lower values will smooth the difference in
      distance metric between different features.
  center
      Whether to center the scaled distance measures. If ``False``, the min distance for each feature
      except for the feature with the highest raw max distance will be the lower bound of the
      feature range, but the upper bound will be below the max feature range.
  update_feature_range
      Update feature range with scaled values.
docstr_tok: ["Get","prototypes","for","each","class","using","the","encoder","or","k-d","trees",".","The","prototypes","are","used","for","the","encoder","loss","term","or","to","calculate","the","optional","trust","scores",".","Parameters","--","--","--","--","--","train_data","Representative","sample","from","the","training","data",".","trustscore_kwargs","Optional","arguments","to","initialize","the","trust","scores","method",".","d_type","Pairwise","distance","metric","used","for","categorical","variables",".","Currently",",","``","'abdm","'","``",",","``","'mvdm","'","``","and","``","'abdm-mvdm","'","``","are","supported",".","``","'abdm","'","``","infers","context","from","the","other","variables","while","``","'mvdm","'","``","uses","the","model","predictions",".","``","'abdm-mvdm","'","``","is","a","weighted","combination","of","the","two","metrics",".","w","Weight","on","``","'abdm","'","``","(","between","0.","and","1",".",")","distance","if","`","d_type","`","equals","``","'abdm-mvdm","'","``",".","disc_perc","List","with","percentiles","used","in","binning","of","numerical","features","used","for","the","``","'abdm","'","``","and","``","'abdm-mvdm","'","``","pairwise","distance","measures",".","standardize_cat_vars","Standardize","numerical","values","of","categorical","variables","if","``","True","``",".","smooth","Smoothing","exponent","between","0","and","1","for","the","distances",".","Lower","values","will","smooth","the","difference","in","distance","metric","between","different","features",".","center","Whether","to","center","the","scaled","distance","measures",".","If","``","False","``",",","the","min","distance","for","each","feature","except","for","the","feature","with","the","highest","raw","max","distance","will","be","the","lower","bound","of","the","feature","range",",","but","the","upper","bound","will","be","below","the","max","feature","range",".","update_feature_range","Update","feature","range","with","scaled","values","."]
code: def fit(
      self,
      train_data: np.ndarray,
      trustscore_kwargs: Optional[dict] = None,
      d_type: str = "abdm",
      w: Optional[float] = None,
      disc_perc: Sequence[Union[int, float]] = (25, 50, 75),
      standardize_cat_vars: bool = False,
      smooth: float = 1.0,
      center: bool = True,
      update_feature_range: bool = True,
  ) -> "CounterfactualProto":
      """
      Get prototypes for each class using the encoder or k-d trees.
      The prototypes are used for the encoder loss term or to calculate the optional trust scores.
  
      Parameters
      ----------
      train_data
          Representative sample from the training data.
      trustscore_kwargs
          Optional arguments to initialize the trust scores method.
      d_type
          Pairwise distance metric used for categorical variables. Currently, ``'abdm'``, ``'mvdm'`` and
          ``'abdm-mvdm'`` are supported. ``'abdm'`` infers context from the other variables while ``'mvdm'`` uses
          the model predictions. ``'abdm-mvdm'`` is a weighted combination of the two metrics.
      w
          Weight on ``'abdm'`` (between 0. and 1.) distance if `d_type` equals ``'abdm-mvdm'``.
      disc_perc
          List with percentiles used in binning of numerical features used for the ``'abdm'``
          and ``'abdm-mvdm'`` pairwise distance measures.
      standardize_cat_vars
          Standardize numerical values of categorical variables if ``True``.
      smooth
          Smoothing exponent between 0 and 1 for the distances. Lower values will smooth the difference in
          distance metric between different features.
      center
          Whether to center the scaled distance measures. If ``False``, the min distance for each feature
          except for the feature with the highest raw max distance will be the lower bound of the
          feature range, but the upper bound will be below the max feature range.
      update_feature_range
          Update feature range with scaled values.
      """
      # get params for storage in meta
      params = locals()
      remove = ["self", "train_data"]
      for key in remove:
          params.pop(key)
      # update metadata
      self.meta["params"].update(params)
  
      if self.model:
          preds = np.argmax(self.predict.predict(train_data), axis=1)  # type: ignore
      else:
          preds = np.argmax(self.predict(train_data), axis=1)
  
      self.cat_vars_ord: dict = dict()
      if (
          self.is_cat
      ):  # compute distance metrics for categorical variables
          if self.ohe:  # convert OHE to ordinal encoding
              train_data_ord, self.cat_vars_ord = ohe_to_ord(
                  train_data, self.cat_vars
              )
          else:
              train_data_ord, self.cat_vars_ord = (
                  train_data,
                  self.cat_vars,
              )
  
          # bin numerical features to compute the pairwise distance matrices
          cat_keys = list(self.cat_vars_ord.keys())
          n_ord = train_data_ord.shape[1]
          numerical_feats = [
              feat for feat in range(n_ord) if feat not in cat_keys
          ]
          if d_type in ["abdm", "abdm-mvdm"] and len(cat_keys) != n_ord:
              fnames = [str(_) for _ in range(n_ord)]
              disc = Discretizer(
                  train_data_ord,
                  numerical_feats,
                  fnames,
                  percentiles=disc_perc,
              )
              train_data_bin = disc.discretize(train_data_ord)
              cat_vars_bin = {
                  k: len(disc.feature_intervals[k])
                  for k in range(n_ord)
                  if k not in cat_keys
              }
          else:
              train_data_bin = train_data_ord
              cat_vars_bin = {}
  
          if d_type not in ["abdm", "mvdm", "abdm-mvdm"]:
              raise ValueError(
                  'd_type needs to be "abdm", "mvdm" or "abdm-mvdm". '
                  "{} is not supported.".format(d_type)
              )
  
          # pairwise distances for categorical variables
          if d_type == "abdm":
              d_pair = abdm(
                  train_data_bin, self.cat_vars_ord, cat_vars_bin
              )
          elif d_type == "mvdm":
              d_pair = mvdm(
                  train_data_ord, preds, self.cat_vars_ord, alpha=1
              )
  
          # combined distance measure
          if d_type == "abdm-mvdm":
              if w is None:
                  msg = "Must specify a value for `w` if using d_type='abdm-mvdm'"
                  raise ValueError(msg)
  
              # pairwise distances
              d_abdm = abdm(
                  train_data_bin, self.cat_vars_ord, cat_vars_bin
              )
              d_mvdm = mvdm(
                  train_data_ord, preds, self.cat_vars_ord, alpha=1
              )
  
              # multidim scaled distances
              d_abs_abdm, _ = multidim_scaling(
                  d_abdm,
                  n_components=2,
                  use_metric=True,
                  feature_range=self.feature_range,  # type: ignore[arg-type]
                  standardize_cat_vars=standardize_cat_vars,
                  smooth=smooth,
                  center=center,
                  update_feature_range=False,
              )
  
              d_abs_mvdm, _ = multidim_scaling(
                  d_mvdm,
                  n_components=2,
                  use_metric=True,
                  feature_range=self.feature_range,  # type: ignore[arg-type]
                  standardize_cat_vars=standardize_cat_vars,
                  smooth=smooth,
                  center=center,
                  update_feature_range=False,
              )
  
              # combine abdm and mvdm
              self.d_abs: Dict = {}
              new_feature_range = tuple(
                  [f.copy() for f in self.feature_range]
              )
              for k, v in d_abs_abdm.items():
                  self.d_abs[k] = v * w + d_abs_mvdm[k] * (1 - w)
                  if center:  # center the numerical feature values
                      self.d_abs[k] -= 0.5 * (
                          self.d_abs[k].max() + self.d_abs[k].min()
                      )
                  if update_feature_range:
                      new_feature_range[0][0, k] = self.d_abs[k].min()
                      new_feature_range[1][0, k] = self.d_abs[k].max()
              if update_feature_range:  # assign updated feature range
                  self.feature_range = new_feature_range
          else:  # apply multidimensional scaling for the abdm or mvdm distances
              self.d_abs, self.feature_range = multidim_scaling(
                  d_pair,
                  n_components=2,
                  use_metric=True,
                  feature_range=self.feature_range,  # type: ignore
                  standardize_cat_vars=standardize_cat_vars,
                  smooth=smooth,
                  center=center,
                  update_feature_range=update_feature_range,
              )
  
          # create array used for ragged tensor placeholder
          self.d_abs_ragged: Any = []
          for _, v in self.d_abs.items():
              n_pad = self.max_cat - len(v)
              v_pad = np.pad(v, (0, n_pad), "constant")
              self.d_abs_ragged.append(v_pad)
          self.d_abs_ragged = np.array(self.d_abs_ragged)
  
      if self.enc_model:
          enc_data = self.enc.predict(train_data)  # type: ignore[union-attr]
          self.class_proto: dict = {}
          self.class_enc: dict = {}
          for i in range(self.classes):
              idx = np.where(preds == i)[0]
              self.class_proto[i] = np.expand_dims(
                  np.mean(enc_data[idx], axis=0), axis=0
              )
              self.class_enc[i] = enc_data[idx]
      elif self.use_kdtree:
          logger.warning(
              "No encoder specified. Using k-d trees to represent class prototypes."
          )
          if trustscore_kwargs is not None:
              ts = TrustScore(**trustscore_kwargs)
          else:
              ts = TrustScore()
          if self.is_cat:  # map categorical to numerical data
              train_data = ord_to_num(train_data_ord, self.d_abs)
          ts.fit(train_data, preds, classes=self.classes)
          self.kdtrees = ts.kdtrees
          self.X_by_class = ts.X_kdtree
  
      return self
  
imports: import copy
  import logging
  import sys
  from typing import Any, Callable, Dict, Optional, Sequence, Tuple, Union
  import numpy
  import tensorflow.compat.v1
  from alibi.api.defaults import DEFAULT_DATA_CFP, DEFAULT_META_CFP
  from alibi.api.interfaces import Explainer, Explanation, FitMixin
  from alibi.confidence import TrustScore
  from alibi.utils.discretizer import Discretizer
  from alibi.utils.distance import abdm, multidim_scaling, mvdm
  from alibi.utils.gradients import perturb
  from alibi.utils.mapping import num_to_ord, ohe_to_ord, ohe_to_ord_shape, ord_to_num, ord_to_ohe
  from alibi.utils.tf import argmax_grad, argmin_grad, one_hot_grad, round_grad
label_desc: Use image node_id 2 for calling the CounterfactualProto obj's underlying member method code with example usage: obj.fit(train_data, trustscore_kwargs, d_type, w, disc_perc, standardize_cat_vars, smooth, center, update_feature_range) and returns: self