docstr: Create an explanation object.  If output summarisation is required and all inputs necessary for this operation
  are passed, the raw shap values are summed first so that a single shap value is returned for each categorical
  variable, as opposed to a shap value per dimension of categorical variable encoding.
  
  Parameters
  ----------
  X
      Instances to be explained.
  shap_values
      Each entry is a `n_instances x n_features array`, and the length of the list equals the dimensionality
      of the predictor output. The rows of each array correspond to the shap values for the instances with
      the corresponding row index in `X`. The length of the list equals the number of model outputs.
  expected_value
      A list containing the expected value of the prediction for each class. Its length should be equal to
      that of `shap_values`.
  
  Returns
  -------
  explanation
      An explanation object containing the shap values and prediction in the `data` field, along with a `meta`
      field containing additional data. See usage at `KernelSHAP examples`_ for details.
  
      .. _KernelSHAP examples:
         https://docs.seldon.io/projects/alibi/en/stable/methods/KernelSHAP.html
code: def _build_explanation(
      self,
      X: Union[np.ndarray, pd.DataFrame, sparse.spmatrix],
      shap_values: List[np.ndarray],
      expected_value: List[float],
      **kwargs,
  ) -> Explanation:
      """
      Create an explanation object.  If output summarisation is required and all inputs necessary for this operation
      are passed, the raw shap values are summed first so that a single shap value is returned for each categorical
      variable, as opposed to a shap value per dimension of categorical variable encoding.
  
      Parameters
      ----------
      X
          Instances to be explained.
      shap_values
          Each entry is a `n_instances x n_features array`, and the length of the list equals the dimensionality
          of the predictor output. The rows of each array correspond to the shap values for the instances with
          the corresponding row index in `X`. The length of the list equals the number of model outputs.
      expected_value
          A list containing the expected value of the prediction for each class. Its length should be equal to
          that of `shap_values`.
  
      Returns
      -------
      explanation
          An explanation object containing the shap values and prediction in the `data` field, along with a `meta`
          field containing additional data. See usage at `KernelSHAP examples`_ for details.
  
          .. _KernelSHAP examples:
             https://docs.seldon.io/projects/alibi/en/stable/methods/KernelSHAP.html
  
      """
  
      # TODO: DEFINE COMPLETE SCHEMA FOR THE METADATA (ONGOING)
      # TODO: Plotting default should be same space as the explanation? How do we figure out what space they
      #  explain in?
  
      cat_vars_start_idx: Sequence[int] = kwargs.get(
          "cat_vars_start_idx", ()
      )
      cat_vars_enc_dim: Sequence[int] = kwargs.get(
          "cat_vars_enc_dim", ()
      )
      summarise_result: bool = kwargs.get("summarise_result", False)
      if summarise_result:
          self._check_result_summarisation(
              summarise_result, cat_vars_start_idx, cat_vars_enc_dim
          )
      if self.summarise_result:
          summarised_shap = []
          for shap_array in shap_values:
              summarised_shap.append(
                  sum_categories(
                      shap_array, cat_vars_start_idx, cat_vars_enc_dim
                  )
              )
          shap_values = summarised_shap
  
      raw_predictions = self._explainer.linkfv(self.predictor(X))
  
      if self.task != "regression":
          argmax_pred = np.argmax(
              np.atleast_2d(raw_predictions), axis=1
          )
      else:
          argmax_pred = []
      importances = rank_by_importance(
          shap_values, feature_names=self.feature_names
      )
  
      if isinstance(X, sparse.spmatrix):
          X = X.toarray()
      else:
          X = np.array(X)
  
      # output explanation dictionary
      data = copy.deepcopy(DEFAULT_DATA_KERNEL_SHAP)
      data.update(
          shap_values=shap_values,
          expected_value=np.array(expected_value),
          categorical_names=self.categorical_names,
          feature_names=self.feature_names,
      )
      data["raw"].update(
          raw_prediction=raw_predictions,
          prediction=argmax_pred,
          instances=X,
          importances=importances,
      )
      self._update_metadata(
          {"summarise_result": self.summarise_result}, params=True
      )
  
      return Explanation(meta=copy.deepcopy(self.meta), data=data)
  
imports: import copy
  import logging
  from functools import partial
  from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Sequence, Tuple, Union
  import numpy
  import pandas
  import shap
  import shap.utils._legacy
  from scipy import sparse
  from scipy.special import expit
  from shap import KernelExplainer
  from alibi.api.defaults import DEFAULT_DATA_KERNEL_SHAP, DEFAULT_DATA_TREE_SHAP, DEFAULT_META_KERNEL_SHAP, DEFAULT_META_TREE_SHAP
  from alibi.api.interfaces import Explainer, Explanation, FitMixin
  from alibi.utils.wrappers import methdispatch
label_desc: Use image node_id 13 for calling the KernelShap obj's underlying member method code with example usage: obj._build_explanation(X, shap_values, expected_value) and returns: Explanation