code: def on_framework_train_end(self, logs):
      # aggregate predictions from all learners
      # it has two columns: 'prediction', 'target'
      logger.debug("early stopping on framework train end")
      self.best_y_oof = pd.concat(list(self.best_y_predicted.values()))
      self.best_y_oof.sort_index(inplace=True)
      # check for duplicates in index -> repeats of validation
      if np.sum(self.best_y_oof.index.duplicated()):
          # we need to aggregate predictions from multiple repeats
          target_cols = [
              c
              for c in self.best_y_oof.columns
              if "prediction" not in c
          ]
          prediction_cols = [
              c for c in self.best_y_oof.columns if "prediction" in c
          ]
  
          aggs = {}
          for t in target_cols:
              aggs[t] = "first"
          for p in prediction_cols:
              aggs[p] = "mean"
          # aggregate predictions from repeats
          self.best_y_oof = self.best_y_oof.groupby(
              target_cols + prediction_cols, level=0
          ).agg(aggs)
  
      sample_weight = None
      if "sample_weight" in self.best_y_oof.columns:
          sample_weight = self.best_y_oof["sample_weight"]
  
      if "prediction" in self.best_y_oof:
          self.final_loss = self.metric(
              self.best_y_oof[self.target_columns],
              self.best_y_oof["prediction"],
              sample_weight=sample_weight,
          )
      else:
          prediction_cols = [
              c for c in self.best_y_oof.columns if "prediction" in c
          ]
          self.final_loss = self.metric(
              self.best_y_oof[self.target_columns],
              self.best_y_oof[prediction_cols],
              sample_weight=sample_weight,
          )
  
file_path: mljar-supervised/supervised/callbacks/early_stopping.py
imports: import logging
  import os
  import numpy
  import pandas
  from supervised.callbacks.callback import Callback
  from supervised.utils.config import LOG_LEVEL
  from supervised.utils.metric import Metric
  from supervised.utils.config import mem
label_desc: Use image node_id 4 for calling the EarlyStopping obj's underlying member method code with example usage: obj.on_framework_train_end(logs) without return types