code: def sum_categories(
      values: np.ndarray,
      start_idx: Sequence[int],
      enc_feat_dim: Sequence[int],
  ):
      """
      This function is used to reduce specified slices in a two- or three- dimensional array.
  
      For two-dimensional `values` arrays, for each entry in `start_idx`, the function sums the
      following `k` columns where `k` is the corresponding entry in the `enc_feat_dim` sequence.
      The columns whose indices are not in `start_idx` are left unchanged. This arises when the slices
      contain the shap values for each dimension of an encoded categorical variable and a single shap
      value for each variable is desired.
  
      For three-dimensional `values` arrays, the reduction is applied for each rank 2 subarray, first along
      the column dimension and then across the row dimension. This arises when summarising shap interaction values.
      Each rank 2 array is a `E x E` matrix of shap interaction values, where `E` is the dimension of the data after
      one-hot encoding. The result of applying the reduction yields a rank 2 array of dimension `F x F`, where `F` is the
      number of features (i.e., the feature dimension of the data matrix before encoding). By applying this
      transformation, a single value describing the interaction of categorical features i and j and a single value
      describing the interaction of `j` and `i` is returned.
  
      Parameters
      ----------
      values
          A two or three dimensional array to be reduced, as described above.
      start_idx
          The start indices of the columns to be summed.
      enc_feat_dim
          The number of columns to be summed, one for each start index.
  
      Returns
      -------
      new_values
          An array whose columns have been summed according to the entries in `start_idx` and `enc_feat_dim`.
      """
  
      if start_idx is None or enc_feat_dim is None:
          raise ValueError(
              "Both the start indices or the encoding dimension need to be specified!"
          )
  
      if not len(enc_feat_dim) == len(start_idx):
          raise ValueError(
              "The lengths of the sequences of start indices and encodings must be equal!"
          )
  
      n_encoded_levels = sum(enc_feat_dim)
      if n_encoded_levels > values.shape[-1]:
          raise ValueError(
              "The sum of the encoded features dimensions exceeds data dimension!"
          )
  
      if len(values.shape) not in (2, 3):
          raise ValueError(
              f"Shap value summarisation can only be applied to arrays of shap values (dim=2) or shap "
              f"interaction values (dim=3). The array to be summarised had dimension {values.shape}!"
          )
  
      def _get_slices(
          start: Sequence[int],
          dim: Sequence[int],
          arr_trailing_dim: int,
      ) -> List[int]:
          """
          Given start indices, encoding dimensions and the array trailing shape, this function returns
          an array where contiguous numbers are slices. This array is used to reduce along an axis
          only the slices `slice(start[i], start[i] + dim[i], 1)` from an array and leave all other slices
          unchanged.
          """
  
          slices: List[int] = []
          # first columns may not be reduced
          if start[0] > 0:
              slices.extend(tuple(range(start[0])))
  
          # add all slices to reduce
          slices.extend([start[0], start[0] + dim[0]])
          for s_idx, d in zip(start[1:], dim[1:]):
              last_idx = slices[-1]
              # some columns might not be reduced
              if last_idx < s_idx - 1:
                  slices.extend(tuple(range(last_idx + 1, s_idx)))
                  last_idx += s_idx - last_idx - 2
              # handle contiguous slices
              if s_idx == last_idx:
                  slices.append(s_idx + d)
              else:
                  slices.extend((s_idx, s_idx + d))
  
          # avoid index error
          if start[-1] + dim[-1] == arr_trailing_dim:
              slices.pop()
              return slices
  
          # last few columns may not be reduced
          last_idx = slices[-1]
          if last_idx < arr_trailing_dim:
              slices.extend(
                  tuple(range(last_idx + 1, arr_trailing_dim))
              )
  
          return slices
  
      def _reduction(arr, axis, indices=None):
          return np.add.reduceat(arr, indices, axis)
  
      # create array of slices to be reduced
      slices = _get_slices(start_idx, enc_feat_dim, values.shape[-1])
      if len(values.shape) == 3:
          reduction = partial(_reduction, indices=slices)
          return np.apply_over_axes(reduction, values, axes=(2, 1))
      return np.add.reduceat(values, slices, axis=1)
  
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 2 for calling a global function with example usage: sum_categories(values, start_idx, enc_feat_dim) and returns: np, slices, np, np, slices