code: def bin_wise_jaccard(
      fold_errors: pd.DataFrame,
      fold_bins: pd.DataFrame,
      num_bins: int,
      num_bins_quantiles: int,
      targets: list,
      uncertainty_key: str,
      combine_middle_bins: bool,
  ) -> dict:
      """
      Helper function for evaluate_jaccard. Calculates the Jaccard Index statistics for each quantile bin and target.
  
      If combine_middle_bins is True, then the middle bins are combined into one bin. e.g. if num_bins_quantiles = 10,
      it will return 3 bins: 1, 2-9, 10.
      You may find the first bin and the last bin are the most accurate, so combining the middle bins may be useful.
  
      Args:
          fold_errors (Pandas Dataframe): Pandas Dataframe of errors for this fold.
          fold_bins (Pandas Dataframe): Pandas Dataframe of predicted quantile bins for this fold.
          num_bins (int): Number of quantile bins,
          targets (list) list of targets to measure uncertainty estimation,
          uncertainty_key (string): Name of uncertainty type to calculate accuracy for,
  
  
      Returns:
          [Dict]: Dict with JI statistics.
  
      Raises:
          None.
  
      Example:
          >>> bin_wise_jaccard(fold_errors, fold_bins, 10, 5, [0,1], 'S-MHA', True)
      """
  
      all_target_jacc: List[float] = []
      all_qs_jacc: List[List[float]] = [[] for x in range(num_bins)]
  
      all_qs_jacc_concat_targets_sep: List[List[List[float]]] = [
          [[] for y in range(num_bins)] for x in range(len(targets))
      ]
  
      all_target_recall: List[float] = []
      all_qs_recall: List[List[float]] = [[] for x in range(num_bins)]
  
      all_target_precision: List[float] = []
      all_qs_precision: List[List[float]] = [
          [] for x in range(num_bins)
      ]
  
      for i, target_idx in enumerate(targets):
          true_errors_ti = fold_errors[
              (fold_errors["target_idx"] == target_idx)
          ][["uid", uncertainty_key + " Error"]]
          pred_bins_ti = fold_bins[
              (fold_errors["target_idx"] == target_idx)
          ][["uid", uncertainty_key + " Uncertainty bins"]]
  
          # Zip to dictionary
          true_errors_ti = dict(
              zip(
                  true_errors_ti.uid,
                  true_errors_ti[uncertainty_key + " Error"],
              )
          )
          pred_bins_ti = dict(
              zip(
                  pred_bins_ti.uid,
                  pred_bins_ti[uncertainty_key + " Uncertainty bins"],
              )
          )
  
          pred_bins_keys = []
          pred_bins_errors = []
  
          # This is saving them from best quantile of predictions to worst quantile of predictions in terms of uncertainty
          for j in range(num_bins):
              inner_list = list(
                  [
                      key
                      for key, val in pred_bins_ti.items()
                      if str(j) == str(val)
                  ]
              )
              inner_list_errors = []
  
              for id_ in inner_list:
                  inner_list_errors.append(
                      list(
                          [
                              val
                              for key, val in true_errors_ti.items()
                              if str(key) == str(id_)
                          ]
                      )[0]
                  )
  
              pred_bins_errors.append(inner_list_errors)
              pred_bins_keys.append(inner_list)
  
          # Get the true error quantiles
          sorted_errors = [
              v
              for k, v in sorted(
                  true_errors_ti.items(), key=lambda item: item[1]
              )
          ]
  
          quantiles = np.arange(
              1 / num_bins_quantiles, 1, 1 / num_bins_quantiles
          )[: num_bins_quantiles - 1]
          quantile_thresholds = [
              np.quantile(sorted_errors, q) for q in quantiles
          ]
  
          # If we are combining the middle bins, combine the middle lists into 1 list.
  
          if combine_middle_bins:
              quantile_thresholds = [
                  quantile_thresholds[0],
                  quantile_thresholds[-1],
              ]
  
          errors_groups = []
          key_groups = []
  
          for q in range(len(quantile_thresholds) + 1):
              inner_list_e = []
              inner_list_id = []
              for i_te, (id_, error) in enumerate(
                  true_errors_ti.items()
              ):
                  if q == 0:
                      lower = 0
                      upper = quantile_thresholds[q]
  
                      if error <= upper:
                          inner_list_e.append(error)
                          inner_list_id.append(id_)
  
                  elif q < len(quantile_thresholds):
                      lower = quantile_thresholds[q - 1]
                      upper = quantile_thresholds[q]
  
                      if error <= upper and error > lower:
                          inner_list_e.append(error)
                          inner_list_id.append(id_)
  
                  else:
                      lower = quantile_thresholds[q - 1]
                      upper = 999999999999999999999999999999
  
                      if error > lower:
                          inner_list_e.append(error)
                          inner_list_id.append(id_)
  
              errors_groups.append(inner_list_e)
              key_groups.append(inner_list_id)
  
          # flip them so they go from B5 to B1
          pred_bins_keys = pred_bins_keys[::-1]
          pred_bins_errors = pred_bins_errors[::-1]
          errors_groups = errors_groups[::-1]
          key_groups = key_groups[::-1]
  
          # Now for each bin, get the jaccard similarity
          inner_jaccard_sims = []
          inner_recalls = []
          inner_precisions = []
          for bin in range(num_bins):
              pred_b_keys = pred_bins_keys[bin]
              gt_bins_keys = key_groups[bin]
  
              j_sim = jaccard_similarity(pred_b_keys, gt_bins_keys)
              all_qs_jacc[bin].append(j_sim)
              all_qs_jacc_concat_targets_sep[i][bin].append(j_sim)
  
              inner_jaccard_sims.append(j_sim)
  
              # If quantile threshold is the same as the last quantile threshold,
              # the GT set is empty (rare, but can happen if distribution of errors is quite uniform).
              if len(gt_bins_keys) == 0:
                  recall = 1.0
                  precision = 0.0
              else:
                  recall = sum(
                      el in gt_bins_keys for el in pred_b_keys
                  ) / len(gt_bins_keys)
  
                  if len(pred_b_keys) == 0 and len(gt_bins_keys) > 0:
                      precision = 0.0
                  else:
                      precision = sum(
                          1 for x in pred_b_keys if x in gt_bins_keys
                      ) / len(pred_b_keys)
  
              inner_recalls.append(recall)
              inner_precisions.append(precision)
              all_qs_recall[bin].append(recall)
              all_qs_precision[bin].append(precision)
  
          all_target_jacc.append(np.mean(inner_jaccard_sims))
          all_target_recall.append(np.mean(inner_recalls))
          all_target_precision.append(np.mean(inner_precisions))
  
      return {
          "mean all targets": np.mean(all_target_jacc),
          "mean all bins": [np.mean(x) for x in all_qs_jacc],
          "all bins": all_qs_jacc,
          "mean all targets recall": np.mean(all_target_recall),
          "mean all bins recall": [np.mean(x) for x in all_qs_recall],
          "all bins recall": all_qs_recall,
          "mean all targets precision": np.mean(all_target_precision),
          "mean all bins precision": [
              np.mean(x) for x in all_qs_precision
          ],
          "all bins precision": all_qs_precision,
          "all bins concatenated targets seperated": all_qs_jacc_concat_targets_sep,
      }
  
file_path: pykale/kale/evaluate/uncertainty_metrics.py
imports: from typing import Dict, List
  import numpy
  import pandas
  from kale.evaluate.similarity_metrics import jaccard_similarity
  from kale.prepdata.string_transform import strip_for_bound
label_desc: Use image node_id 6 for calling a global function with example usage: bin_wise_jaccard(fold_errors, fold_bins, num_bins, num_bins_quantiles, targets, uncertainty_key, combine_middle_bins) and returns: dict