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. Similarly, the
  shap interaction values are summed such that they represent the interaction between categorical variables as
  opposed to levels of categorical variables. If the interaction option has been specified during `explain`,
  this method computes the shap values given the interactions prior to creating the response.
  
  Parameters
  ----------
  X
      Instances to be explained.
  shap_output
      If `explain` is callled with ``interactions=True`` then the list contains arrays of dimensionality
      `n_instances x n_features x n_features` of shap interaction values. Otherwise, it contains arrays of
      dimension `n_instances x n_features` representing shap values. 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 is equal to that of
      `shap_output`.
  
  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 `TreeSHAP examples`_ for details.
  
      .. _TreeSHAP examples:
         https://docs.seldon.io/projects/alibi/en/stable/methods/TreeSHAP.html
code: def _build_explanation(
      self,
      X: Union[np.ndarray, pd.DataFrame, "catboost.Pool"],
      shap_output: 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. Similarly, the
      shap interaction values are summed such that they represent the interaction between categorical variables as
      opposed to levels of categorical variables. If the interaction option has been specified during `explain`,
      this method computes the shap values given the interactions prior to creating the response.
  
      Parameters
      ----------
      X
          Instances to be explained.
      shap_output
          If `explain` is callled with ``interactions=True`` then the list contains arrays of dimensionality
          `n_instances x n_features x n_features` of shap interaction values. Otherwise, it contains arrays of
          dimension `n_instances x n_features` representing shap values. 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 is equal to that of
          `shap_output`.
  
      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 `TreeSHAP examples`_ for details.
  
          .. _TreeSHAP examples:
             https://docs.seldon.io/projects/alibi/en/stable/methods/TreeSHAP.html
  
      """
  
      y = kwargs.get("y")
      if y is None:
          y = np.array([])
      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)
  
      # check if interactions were computed
      if len(shap_output[0].shape) == 3:
          shap_interaction_values = shap_output
          # shap values are the sum over all shap interaction values for each instance
          shap_values = [
              interactions.sum(axis=2) for interactions in shap_output
          ]
      else:
          shap_interaction_values = [np.array([])]
          shap_values = shap_output
      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
          if shap_interaction_values[0].size != 0:
              summarised_shap_interactions = []
              for shap_array in shap_interaction_values:
                  summarised_shap_interactions.append(
                      sum_categories(
                          shap_array,
                          cat_vars_start_idx,
                          cat_vars_enc_dim,
                      )
                  )
              shap_interaction_values = summarised_shap_interactions
  
      # NB: Can't get the raw prediction from model when model_output = 'log_loss` as shap library does
      # not support this (issue raised). We may be able to support this if there's a compelling need.
      # NB: raw output of a regression or classification task will not work for pyspark (predict not implemented)
      if self.model_output == "log_loss":
          loss = self._explainer.model.predict(
              X, y, tree_limit=self.tree_limit
          )
          raw_predictions: Any = []
      else:
          loss = []
          raw_predictions = self._explainer.model.predict(
              X, tree_limit=self.tree_limit
          )
          # flatten array of predictions if the trailing dimension is 1
          if raw_predictions.shape[-1] == 1:
              raw_predictions = raw_predictions.squeeze(-1)
  
      # predicted class
      argmax_pred: Any = []
      if self.task != "regression":
          if not isinstance(raw_predictions, list):
              if self.scalar_output:
                  if self.model_output == "raw":
                      probas = expit(raw_predictions)
                  else:
                      probas = raw_predictions
                  argmax_pred = (probas > 0.5).astype(int)
              else:
                  argmax_pred = np.argmax(
                      np.atleast_2d(raw_predictions), axis=1
                  )
  
      importances = rank_by_importance(
          shap_values, feature_names=self.feature_names
      )
  
      if self._explainer.model.model_type == "catboost":
          import catboost  # noqa: F811
  
          if isinstance(X, catboost.Pool):
              X = X.get_features()
      # output explanation dictionary
      data = copy.deepcopy(DEFAULT_DATA_TREE_SHAP)
      data.update(
          shap_values=shap_values,
          shap_interaction_values=shap_interaction_values,
          expected_value=expected_value,
          categorical_names=self.categorical_names,
          feature_names=self.feature_names,
      )
      data["raw"].update(
          raw_prediction=raw_predictions,
          loss=loss,
          prediction=argmax_pred,
          instances=np.array(X),
          labels=y,
          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 10 for calling the TreeShap obj's underlying member method code with example usage: obj._build_explanation(X, shap_output, expected_value) and returns: Explanation