class_docstr: A sampler that uses an underlying training set to draw records that have a subset of features with
  values specified in an instance to be explained, `X`. 
class_docstr_tok: ["A","sampler","that","uses","an","underlying","training","set","to","draw","records","that","have","a","subset","of","features","with","values","specified","in","an","instance","to","be","explained",",","`","X","`","."]
docstr: Given an anchor, this function finds the row indices in the training set where the feature has
  the same value as the feature in the instance to be explained (for ordinal variables, the row
  indices are those of rows which contain records with feature values in the same bin). The algorithm
  uses both the feature *encoded* ids in anchor and the feature ids in the input data set. The two
  are mapped by `self.enc2feat_idx`.
  
  Parameters
  ----------
  anchor
      The anchor for which the training set row indices are to be retrieved. The ints represent
      encoded feature ids.
  
  Returns
  -------
  allowed_bins
      Maps original feature ids to the bins that the feature should be sampled from given the input anchor.
  allowed_rows
      Maps original feature ids to the training set rows where these features have the same value as the anchor.
  unk_feat_values
      When a categorical variable with the specified value/discretized variable in the specified bin is not found
      in the training set, a tuple is added to `unk_feat_values` to indicate the original feature id, its type
      (``'c'`` = categorical, ``'o'`` = discretized continuous) and the value/bin it should be sampled from.
code: def get_features_index(
      self, anchor: tuple
  ) -> Tuple[
      Dict[int, Set[int]],
      Dict[int, Any],
      List[Tuple[int, str, Union[Any, int]]],
  ]:
      """
      Given an anchor, this function finds the row indices in the training set where the feature has
      the same value as the feature in the instance to be explained (for ordinal variables, the row
      indices are those of rows which contain records with feature values in the same bin). The algorithm
      uses both the feature *encoded* ids in anchor and the feature ids in the input data set. The two
      are mapped by `self.enc2feat_idx`.
  
      Parameters
      ----------
      anchor
          The anchor for which the training set row indices are to be retrieved. The ints represent
          encoded feature ids.
  
      Returns
      -------
      allowed_bins
          Maps original feature ids to the bins that the feature should be sampled from given the input anchor.
      allowed_rows
          Maps original feature ids to the training set rows where these features have the same value as the anchor.
      unk_feat_values
          When a categorical variable with the specified value/discretized variable in the specified bin is not found
          in the training set, a tuple is added to `unk_feat_values` to indicate the original feature id, its type
          (``'c'`` = categorical, ``'o'`` = discretized continuous) and the value/bin it should be sampled from.
      """
  
      # bins one can sample from for each numerical feature (key: feat id)
      allowed_bins: Dict[int, Set[int]] = {}
      # index of database rows (values) for each feature in result (key: feat id)
      allowed_rows: Dict[int, Any[int]] = {}
      # feats for which there are not training records in the desired bin/with that value
      unk_feat_values: List[Tuple[int, str, Optional[int]]] = []
      cat_enc_ids = [
          enc_id
          for enc_id in anchor
          if enc_id in self.cat_lookup.keys()
      ]
      ord_enc_ids = [
          enc_id
          for enc_id in anchor
          if enc_id in self.ord_lookup.keys()
      ]
      if cat_enc_ids:
          cat_feat_vals = [self.cat_lookup[idx] for idx in cat_enc_ids]
          cat_feat_ids = [self.enc2feat_idx[idx] for idx in cat_enc_ids]
          allowed_rows = {
              f_id: self.val2idx[f_id][f_val]
              for f_id, f_val in zip(cat_feat_ids, cat_feat_vals)
          }
          for feat_id, enc_id, val in zip(
              cat_feat_ids, cat_enc_ids, cat_feat_vals
          ):
              if allowed_rows[feat_id].size == 0:
                  unk_feat_values.append((feat_id, "c", val))
                  cat_feat_ids.remove(feat_id)
      ord_feat_ids = [self.enc2feat_idx[idx] for idx in ord_enc_ids]
  
      # determine bins from which ordinal data should be drawn
      for feat_id, enc_id in zip(ord_feat_ids, ord_enc_ids):
          # if encoded indices ref to the same feat, intersect the allowed bins to determine which bins to sample from
          if feat_id not in allowed_bins:
              allowed_bins[feat_id] = self.ord_lookup[enc_id]
          else:
              allowed_bins[feat_id] = allowed_bins[
                  feat_id
              ].intersection(self.ord_lookup[enc_id])
  
      # dict where keys are feature col. ids and values are lists containing row indices in train data which contain
      # data coming from the same bin (or range of bins)
      for (
          feat_id
      ) in (
          allowed_bins
      ):  # NB: should scale since we don't query the whole DB every time!
          allowed_rows[feat_id] = np.concatenate(
              [
                  self.val2idx[feat_id][bin_id]
                  for bin_id in allowed_bins[feat_id]
              ]
          )
          if (
              allowed_rows[feat_id].size == 0
          ):  # no instances in training data are in the specified bins ...
              unk_feat_values.append((feat_id, "o", None))
  
      return allowed_bins, allowed_rows, unk_feat_values
  
imports: import copy
  from collections import OrderedDict, defaultdict
  from itertools import accumulate
  from typing import Any, Callable, DefaultDict, Dict, List, Optional, Set, Tuple, Type, Union
  import numpy
  from alibi.api.defaults import DEFAULT_DATA_ANCHOR, DEFAULT_META_ANCHOR
  from alibi.api.interfaces import Explainer, Explanation, FitMixin
  from alibi.exceptions import NotFittedError, PredictorCallError, PredictorReturnTypeError
  from alibi.utils.discretizer import Discretizer
  from alibi.utils.mapping import ohe_to_ord, ord_to_ohe
  from alibi.utils.wrappers import ArgmaxTransformer
  from .anchor_base import AnchorBaseBeam
  from .anchor_explanation import AnchorExplanation
label_desc: Use image node_id 14 for calling the TabularSampler obj's underlying member method code with example usage: obj.get_features_index(anchor) and returns: allowed_bins,  allowed_rows,  unk_feat_values