code: def backward_subset_feature_selection(
      train_data: pd.DataFrame,
      param_train_fn: TuningLearnerFnType,
      features_sets: Dict[str, List[str]],
      split_fn: SplitterFnType,
      eval_fn: EvalFnType,
      extractor: ExtractorFnType,
      metric_name: str,
      threshold: float = 0.005,
      num_removed_by_step: int = 3,
      early_stop: int = 2,
      iter_limit: int = 50,
      min_remaining_features: int = 50,
      save_intermediary_fn: SaveIntermediaryFnType = None,
      n_jobs: int = 1,
  ) -> ListLogListType:
      """
      Performs train-evaluation iterations while testing the subsets of features
      to compute statistics about the importance of each feature category
  
      Parameters
      ----------
      train_data : pandas.DataFrame
          A Pandas' DataFrame with training data
  
      param_train_fn : function (pandas.DataFrame, list of str) -> prediction_function, predictions_dataset, logs
          A partially defined learning function that takes a training set and a feature list and
          returns a predict function, a dataset with training predictions and training
          logs.
  
      features_sets: dict of string -> list
          Each String Key on the dict is a subset of columns from the dataset, the function will
          analyse the influence of each group of features on the model performance
  
      split_fn : function pandas.DataFrame ->  list of tuple
          Partially defined split function that takes a dataset and returns
          a list of folds. Each fold is a Tuple of arrays. The fist array in
          each tuple contains training indexes while the second array
          contains validation indexes.
  
      eval_fn : function pandas.DataFrame -> dict
          A partially defined evaluation function that takes a dataset with prediction and
          returns the evaluation logs.
  
      extractor: function str -> float
          A extractor that take a string and returns the value of that string on a dict
  
      metric_name: str
          String with the name of the column that refers to the metric column to be extracted
  
      num_removed_by_step: int (default 3)
          Number of features removed at each iteration
  
      threshold: float (default 0.005)
          Threshold for model performance comparison
  
      early_stop: int (default 2)
          Number of rounds without improvement before stopping process
  
      iter_limit: int (default 50)
          Maximum number of iterations before stopping
  
      min_remaining_features: int (default 50)
          Minimum number of features that should remain in the model,
          combining num_removed_by_step and iter_limit accomplishes the same
          functionality as this parameter.
  
      save_intermediary_fn : function(log) -> save to file
          Partially defined saver function that receives a log result from a
          tuning step and appends it into a file
          Example: save_intermediary_result(save_path='tuning.pkl')
  
      n_jobs : int
          Number of parallel processes to spawn.
  
      Returns
      ----------
      logs: list of list of dict
          A list log-like lists of dictionaries evaluations. Each element of the
          list is validation step of the algorithm.
  
      """
  
      selector_fn = remove_features_subsets(
          extractor=extractor,
          metric_name=metric_name,
          num_removed_by_step=num_removed_by_step,
      )
  
      stop_fn = aggregate_stop_funcs(
          stop_by_no_improvement_parallel(
              extractor=extractor,
              metric_name=metric_name,
              early_stop=early_stop,
              threshold=threshold,
          ),
          stop_by_iter_num(iter_limit=iter_limit),
          stop_by_num_features_parallel(
              extractor=extractor,
              metric_name=metric_name,
              min_num_features=min_remaining_features,
          ),
      )
  
      used_subsets = [features_sets.keys()]
  
      used_features = [
          list(mapcat(lambda key: features_sets[key], subset))
          for subset in used_subsets
      ]
  
      trainers = [
          lambda df: param_train_fn(df, feat) for feat in used_features
      ]
  
      first_val_logs = [
          parallel_validator(
              train_data, split_fn, train_func, eval_fn, n_jobs
          )
          for train_func in trainers
      ]
      logs = [
          [
              dict(log, **{"used_subsets": list(subset)})
              for log, subset in zip(first_val_logs, used_subsets)
          ]
      ]
  
      while not stop_fn(logs):
          curr_log = first(logs)
  
          new_subsets = selector_fn(curr_log)
          new_features = [
              list(mapcat(lambda key: features_sets[key], subset))
              for subset in new_subsets
          ]
  
          trainers = [
              lambda df: param_train_fn(df, feat)
              for feat in new_features
          ]
  
          val_logs = [
              parallel_validator(
                  train_data, split_fn, train_func, eval_fn, n_jobs
              )
              for train_func in trainers
          ]
  
          new_logs = [
              dict(log, **{"used_subsets": subset})
              for log, subset in zip(val_logs, new_subsets)
          ]
  
          if save_intermediary_fn is not None:
              save_intermediary_fn(new_logs)
  
          logs = [new_logs] + logs
  
      return logs
  
file_path: fklearn/src/fklearn/tuning/selectors.py
imports: from typing import Callable, Dict, List
  from toolz.curried import pipe, first, mapcat
  import pandas
  from fklearn.tuning.samplers import remove_features_subsets, remove_by_feature_importance, remove_by_feature_shuffling
  from fklearn.tuning.stoppers import stop_by_num_features, stop_by_num_features_parallel, stop_by_iter_num, stop_by_no_improvement, stop_by_no_improvement_parallel, aggregate_stop_funcs
  from fklearn.validation.validator import parallel_validator
  from fklearn.types import EvalFnType, ExtractorFnType, LearnerReturnType, ListLogListType, LogListType, SplitterFnType, ValidatorReturnType, LogType
label_desc: Use image node_id 3 for calling a global function with example usage: backward_subset_feature_selection(train_data, param_train_fn, features_sets, split_fn, eval_fn, extractor, metric_name, threshold, num_removed_by_step, early_stop, iter_limit, min_remaining_features, save_intermediary_fn, n_jobs) and returns: logs