code: def fit(self, oofs, y, sample_weight=None, sensitive_features=None):
      logger.debug("Ensemble.fit")
      self.sensitive_features = sensitive_features
      start_time = time.time()
      selected_algs_cnt = 0  # number of selected algorithms
      self.best_algs = []  # selected algoritms indices from each loop
  
      total_prediction_time = 0
      best_sum = None  # sum of best algorihtms
      for j in range(len(oofs)):  # iterate over all solutions
          min_score = self.metric.get_maximum()
          best_model = None
          # try to add some algorithm to the best_sum to minimize metric
          for model_name in oofs.keys():
              if (
                  self._max_single_prediction_time
                  and model_name in self.model_prediction_time
              ):
                  if (
                      total_prediction_time
                      + self.model_prediction_time[model_name]
                      > self._max_single_prediction_time
                  ):
                      continue
              # skip unfair models
              if (
                  self._fairness_metric is not None
                  and not self.models_map[model_name].is_fair()
              ):
                  continue
              y_ens = self._get_mean(oofs[model_name], best_sum, j + 1)
              score = self.metric(y, y_ens, sample_weight)
              if self.metric.improvement(
                  previous=min_score, current=score
              ):
                  min_score = score
                  best_model = model_name
  
          if best_model is None:
              continue
          # there is improvement, save it
          # save scores for plotting learning curve
          # if we optimize negative, then we need to multiply by -1.0
          # to save correct values in the learning curve
          sign = (
              -1.0
              if Metric.optimize_negative(self.metric.name)
              else 1.0
          )
          self._scores += [sign * min_score]
  
          if self.metric.improvement(
              previous=self.best_loss, current=min_score
          ):
              self.best_loss = min_score
              selected_algs_cnt = j
  
          self.best_algs.append(best_model)  # save the best algoritm
          # update best_sum value
          best_sum = (
              oofs[best_model]
              if best_sum is None
              else best_sum + oofs[best_model]
          )
          if j == selected_algs_cnt:
              self.total_best_sum = copy.deepcopy(best_sum)
  
          # update prediction time estimate
          if self._max_single_prediction_time is not None:
              total_prediction_time = np.sum(
                  [
                      self.model_prediction_time[name]
                      for name in np.unique(self.best_algs)
                  ]
              )
      # end of main loop #
  
      if not self.best_algs:
          raise NotTrainedException("Ensemble wasn't fitted.")
  
      # keep oof predictions of ensemble
      self.total_best_sum /= float(selected_algs_cnt + 1)
      self.best_algs = self.best_algs[: (selected_algs_cnt + 1)]
  
      logger.debug("Selected models for ensemble:")
      for model_name in np.unique(self.best_algs):
          self.selected_models += [
              {
                  "model": self.models_map[model_name],
                  "repeat": float(self.best_algs.count(model_name)),
              }
          ]
          logger.debug(
              f"{model_name} {self.best_algs.count(model_name)}"
          )
  
      self._additional_metrics = self.get_additional_metrics()
  
      self.train_time = time.time() - start_time
  
imports: import copy
  import json
  import logging
  import operator
  import os
  import time
  import uuid
  import numpy
  import pandas
  from supervised.algorithms.algorithm import BaseAlgorithm
  from supervised.algorithms.registry import BINARY_CLASSIFICATION, MULTICLASS_CLASSIFICATION, REGRESSION
  from supervised.exceptions import NotTrainedException
  from supervised.model_framework import ModelFramework
  from supervised.utils.additional_metrics import AdditionalMetrics
  from supervised.utils.config import LOG_LEVEL
  from supervised.utils.metric import Metric
  from supervised.utils.jsonencoder import MLJSONEncoder
  import matplotlib.pyplot
  from tabulate import tabulate
  from supervised.utils.learning_curves import LearningCurves
label_desc: Use image node_id 21 for calling the Ensemble obj's underlying member method code with example usage: obj.fit(oofs, y, sample_weight, sensitive_features) without return types