code: def add_permutation_importance(
      fout, model_path, fold_cnt, repeat_cnt
  ):
      # permutation importance
      imp_data = [
          f
          for f in os.listdir(model_path)
          if "_importance.csv" in f and "shap" not in f
      ]
      if not len(imp_data):
          return
  
      df_all = []
      for repeat in range(repeat_cnt):
          repeat_str = f", Repeat {repeat+1}" if repeat_cnt > 1 else ""
          for fold in range(fold_cnt):
              learner_name = construct_learner_name(
                  fold, repeat, repeat_cnt
              )
              fname = learner_name + "_importance.csv"
              if fname in imp_data:
                  df = pd.read_csv(
                      os.path.join(model_path, fname), index_col=0
                  )
                  df.columns = [f"Learner {fold+1}{repeat_str}"]
                  df_all += [df]
  
      df = pd.concat(df_all, axis=1)
  
      df["m"] = df.mean(axis=1)
      df = df.sort_values(by="m", ascending=False)
      df = df.drop("m", axis=1)
  
      # limit to max 25 features in the plot
      ax = df.head(25).plot.barh(figsize=(10, 7))
      ax.invert_yaxis()
      ax.set_xlabel("Mean of feature importance")
      fig = ax.get_figure()
      fig.tight_layout(pad=2.0)
      if df.shape[0] > 25:
          ax.set_title("Top-25 important features")
      else:
          ax.set_title("Feature importance")
  
      fig.savefig(
          os.path.join(model_path, "permutation_importance.png")
      )
      fout.write("\n\n## Permutation-based Importance\n")
      fout.write(
          f"![Permutation-based Importance](permutation_importance.png)"
      )
  
      if "random_feature" in df.index.tolist():
          df["counter"] = 0
          df = df.fillna(
              0
          )  # there might be not-used features between different learners
          max_counter = 0.0
          for col in df.columns:
              if "Learner" not in col:
                  continue
              score = max(0, df[col]["random_feature"]) + 1e-6
              df["counter"] += (df[col] <= score).astype(int)
              max_counter += 1.0
  
          """ version 1
              df["min_score"] = df.min(axis=1)
              df["max_score"] = df.max(axis=1)
              random_feature_score = max(
                  0.0, float(df["max_score"]["random_feature"])
              )  # it should be at least 0
              drop_features = df.index[
                  df["min_score"] < random_feature_score + 1e-6
              ].tolist()
              """
  
          # version 2 - should be better
          threshold = max_counter / 2.0
          drop_features = df.index[df["counter"] >= threshold].tolist()
  
          fname = os.path.join(
              os.path.dirname(model_path), "drop_features.json"
          )
          with open(fname, "w") as fout:
              fout.write(
                  json.dumps(drop_features, indent=4, cls=MLJSONEncoder)
              )
  
          fname = os.path.join(
              os.path.dirname(model_path),
              f"features_scores_threshold_{threshold}.csv",
          )
          df.to_csv(fname, index=False)
  
imports: import copy
  import json
  import logging
  import os
  import time
  import uuid
  import warnings
  import numpy
  import pandas
  from sklearn.metrics import accuracy_score, classification_report, confusion_matrix, f1_score, matthews_corrcoef, mean_absolute_error, mean_absolute_percentage_error, mean_squared_error, precision_score, r2_score, recall_score, roc_auc_score
  from supervised.algorithms.registry import BINARY_CLASSIFICATION, MULTICLASS_CLASSIFICATION, REGRESSION
  from supervised.utils.metric import logloss
  from supervised.utils.config import LOG_LEVEL
  from tabulate import tabulate
  from supervised.fairness.metrics import FairnessMetrics
  from supervised.fairness.report import FairnessReport
  from supervised.fairness.utils import accuracy, false_negative_rate, false_positive_rate, selection_rate, true_negative_rate, true_positive_rate
  from supervised.utils.additional_plots import AdditionalPlots
  from supervised.utils.common import construct_learner_name, get_fold_repeat_cnt
  from supervised.utils.learning_curves import LearningCurves
  from supervised.utils.jsonencoder import MLJSONEncoder
label_desc: Use image node_id 12 for calling the AdditionalMetrics obj's underlying member method code with example usage: obj.add_permutation_importance(fout, model_path, fold_cnt, repeat_cnt) without return types