code: def shap(
      explainer,
      new_observation,
      path,
      keep_distributions,
      B,
      processes,
      random_state,
  ):
      # Now we know the path, so we can calculate contributions
      # set variable indicators
      # start random path
      p = new_observation.shape[1]
  
      if processes == 1:
          result_list = [
              iterate_paths(
                  explainer.predict_function,
                  explainer.model,
                  explainer.data,
                  explainer.label,
                  new_observation,
                  p,
                  b + 1,
                  np.random,
              )
              for b in range(B)
          ]
      else:
          # Create number generator for each iteration
          ss = SeedSequence(random_state)
          generators = [default_rng(s) for s in ss.spawn(B)]
          pool = mp.get_context("spawn").Pool(processes)
          result_list = pool.starmap_async(
              iterate_paths,
              [
                  (
                      explainer.predict_function,
                      explainer.model,
                      explainer.data,
                      explainer.label,
                      new_observation,
                      p,
                      b + 1,
                      generators[b],
                  )
                  for b in range(B)
              ],
          ).get()
          pool.close()
  
      result = pd.concat(result_list)
  
      if path is not None:
          if isinstance(path, str) and path == "average":
              # average over all of the paths
              variable_average = result.pivot(
                  index="variable", columns="B", values="contribution"
              ).mean(axis=1)
              # sort pd.Series by index of abs-sorted pd.Series
              variable_average_sorted = variable_average.reindex(
                  variable_average.abs()
                  .sort_values(ascending=False)
                  .index
              )
              # make the final result - sort and fill with values
              result_average = (
                  result_list[0]
                  .set_index("variable")
                  .reindex(variable_average_sorted.index)
                  .reset_index()
              )
  
              result_average = result_average.assign(
                  contribution=variable_average_sorted.values,
                  B=0,
                  sign=np.sign(variable_average_sorted.values),
              )
  
              result = pd.concat((result, result_average))
          else:
              tmp = get_single_random_path(
                  explainer.predict_function,
                  explainer.model,
                  explainer.data,
                  explainer.label,
                  new_observation,
                  path,
                  0,
              )
  
              result = pd.concat((result, tmp))
  
      if keep_distributions:
          yhats_distributions = calculate_yhats_distributions(explainer)
      else:
          yhats_distributions = None
  
      target_yhat = explainer.predict(new_observation)[
          0
      ]  # only one new_observation allowed
      data_yhat = explainer.predict(explainer.data)
      baseline_yhat = data_yhat.mean()
  
      return result, target_yhat, baseline_yhat, yhats_distributions
  
file_path: DALEX/python/dalex/dalex/predict_explanations/_shap/utils.py
imports: import multiprocessing
  from copy import deepcopy
  from numpy.random import SeedSequence, default_rng
  import numpy
  import pandas
label_desc: Use image node_id 2 for calling a global function with example usage: shap(explainer, new_observation, path, keep_distributions, B, processes, random_state) and returns: result,  target_yhat,  baseline_yhat,  yhats_distributions