code: def test_sampler(
      test_instance_idx,
      anchors,
      nb_samples,
      dataset,
      rf_classifier,
      explainer,
  ):
      """
      Test sampler for datasets that contain continuos only or continuous and categorical variables.
      """
  
      # fixture returns a fitted AnchorTabular explainer
      X_test, explainer, predict_fn, predict_type = explainer
      test_dataset = dataset
      test_dataset_name = test_dataset["metadata"]["name"]
  
      # the `explain` call does some more sampler setup before using it so we need to repeat it here
      sampler = explainer.samplers[0]
      sampler.set_instance_label(X_test[test_instance_idx])
      # TODO: the test passes now, but we're not setting other things passed to `explain` like `n_covered_ex`
      #  or calling explainer._build_sampling_lookups. This suggests either the coupling between `sampler` and
      #  `explainer` is too strong or this test should be re-written in a different way.
  
      # test sampler setup is correct
      assert len(explainer.samplers) == 1
      sampler = explainer.samplers[0]
      assert explainer.predictor(
          X_test[test_instance_idx].reshape(1, -1)
      ).shape == (1,)
      assert (
          sampler.train_data.shape
          == sampler.d_train_data.shape
          == test_dataset["X_train"].shape
      )
  
      if test_dataset_name == "adult":
          category_map = test_dataset["metadata"]["category_map"]
          assert len(sampler.categorical_features) == len(
              category_map.keys()
          )
          assert len(sampler.numerical_features) == X_test.shape[
              1
          ] - len(category_map.keys())
      elif test_dataset_name == "iris":
          assert (
              np.unique(sampler.d_train_data)
              == np.array([0.0, 1.0, 2.0, 3.0])
          ).all()
          assert not sampler.categorical_features
          assert len(sampler.numerical_features) == X_test.shape[1]
  
      if predict_type == "proba":
          instance_label = np.argmax(
              predict_fn(X_test[test_instance_idx, :].reshape(1, -1)),
              axis=1,
          )
      else:
          instance_label = predict_fn(
              X_test[test_instance_idx, :].reshape(1, -1)
          )[0]
  
      explainer.instance_label = instance_label
  
      # test sampling function end2end
      train_data = sampler.train_data
      train_data_mean = np.mean(train_data, axis=0)[
          sampler.numerical_features
      ]
      train_data_3std = (
          3 * np.std(train_data, axis=0)[sampler.numerical_features]
      )
      sampler.build_lookups(X_test[test_instance_idx, :])
      n_covered_ex = sampler.n_covered_ex
  
      for anchor in anchors:
          (
              cov_true,
              cov_false,
              labels,
              data,
              coverage,
              anchor_pos,
          ) = sampler((0, anchor), nb_samples)
          assert cov_true.shape[0] <= n_covered_ex
          assert cov_false.shape[0] <= n_covered_ex
          assert len(labels) == nb_samples
          assert len(sampler.enc2feat_idx) == data.shape[1]
          assert coverage != -1
  
          # test lookups dictionary used for sampling
          ord_feats = sampler.ord_lookup.keys()
          cat_feats = sampler.cat_lookup.keys()
          enc_feats = sampler.enc2feat_idx.keys()
          assert (set(ord_feats | set(cat_feats))) == set(enc_feats)
  
          # now test perturbation method ...
          # find out which bins can be sampled for discretized vars and perturb some random data
          (
              allowed_bins,
              allowed_rows,
              unk_feat_vals,
          ) = sampler.get_features_index(anchor)
          raw_data, disc_data, coverage = sampler.perturbation(
              anchor, nb_samples
          )
  
          assert not unk_feat_vals
          assert coverage != -1
          assert raw_data.shape[0] == disc_data.shape[0] == nb_samples
  
          # find the indices of the features in the anchor
          uniq_feat_ids = list(
              OrderedDict.fromkeys(
                  [sampler.enc2feat_idx[enc_idx] for enc_idx in anchor]
              )
          )
          uniq_feat_ids = [
              feat
              for feat in uniq_feat_ids
              if feat not in [f for f, _, _ in unk_feat_vals]
          ]
  
          # find the mapping of feature ids to encoded feature ids
          feat2enc_idx = defaultdict(list)
          for (
              enc_feat_idx,
              orig_feat_id,
          ) in sampler.enc2feat_idx.items():
              feat2enc_idx[orig_feat_id].append(enc_feat_idx)
  
          # find the expected values the sampled features should have
          expected_values = []
          for feat_id in uniq_feat_ids:
              if feat_id in sampler.categorical_features:
                  enc_idx = feat2enc_idx[feat_id][0]
                  val = sampler.cat_lookup[enc_idx]
                  expected_values.append({val})
              else:
                  expected_values.append(allowed_bins[feat_id])
  
      # check that we have replaced features properly with values from the same bin
      # or with the correct value
      for bins, feat_id in zip(expected_values, uniq_feat_ids):
          sampled_bins_uniq = set(np.unique(disc_data[:, feat_id]))
  
          # check that we have replaced features properly with values from the same bin
          assert bins - sampled_bins_uniq == set()
          assert sampled_bins_uniq - bins == set()
          raw_data_mean = np.mean(raw_data, axis=0)[
              sampler.numerical_features
          ]
  
          # check features sampled are in a sensible range for numerical features
          assert (
              train_data_mean + train_data_3std - raw_data_mean > 0
          ).all()
          assert (
              train_data_mean - train_data_3std - raw_data_mean < 0
          ).all()
  
file_path: alibi/alibi/explainers/tests/test_anchor_tabular.py
imports: from collections import OrderedDict, defaultdict
  from copy import deepcopy
  import numpy
  import pytest
  from pytest_lazyfixture import lazy_fixture
  from alibi.api.defaults import DEFAULT_META_ANCHOR, DEFAULT_DATA_ANCHOR
  from alibi.exceptions import NotFittedError, PredictorCallError, PredictorReturnTypeError
  from alibi.explainers import AnchorTabular, DistributedAnchorTabular
  from alibi.explainers.tests.utils import predict_fcn
label_desc: Use image node_id 5 for calling a global function with example usage: test_sampler(test_instance_idx, anchors, nb_samples, dataset, rf_classifier, explainer) without return types