code: def regressor(
      df: pd.DataFrame,
      config: dict,
      header: str,
      dataset_features: dict,
      validation_df: Optional[pd.DataFrame] = None,
      process_id: Optional[int] = None,
      silent: bool = False,
  ) -> list:
      """
      Train procedure of adaboost gbm regressor
      Args:
          df (pd.DataFrame): train set
          config (dict): configuration sent to fit function
          header (str): output module's header line
          dataset_features (dict): dataframe's columns with datatypes
          validation_df (pd.DataFrame): validation set
          process_id (int): process id of parent trx
          silent (bool): set this to True to make it silent
      Returns:
          result (list): list of built models
      """
      models = []
  
      # we will update decisions in every epoch, this will be used to restore
      epochs = config["epochs"]
      learning_rate = config["learning_rate"]
  
      boosted_from = 0
      boosted_to = 0
  
      base_df = df.copy()
  
      # gbm will manipulate actuals. store its raw version.
      target_values = base_df["Decision"].values
      num_of_instances = target_values.shape[0]
  
      root = 1
      file = "outputs/rules/rules0.py"
      json_file = "outputs/rules/rules0.json"
      functions.createFile(file, header)
      functions.createFile(json_file, "[\n")
  
      Training.buildDecisionTree(
          df,
          root,
          file,
          config,
          dataset_features,
          parent_level=0,
          leaf_id=0,
          parents="root",
      )  # generate rules0
  
      # functions.storeRule(json_file," {}]")
  
      df = base_df.copy()
  
      base_df["Boosted_Prediction"] = 0
  
      # ------------------------------
  
      best_epoch_idx = 0
      best_epoch_loss = 1000000
  
      pbar = tqdm(range(1, epochs + 1), desc="Boosting", disable=silent)
      for index in pbar:
          logger.debug(f"epoch {index} - ")
          loss = 0
  
          # run data(i-1) and rules(i-1), save data1
  
          # dynamic import
          module_name = f"outputs/rules/rules{index - 1}"
          myrules = load_module(module_name)  # rules0
  
          models.append(myrules)
  
          new_data_set = f"outputs/data/data{index}.csv"
          with open(new_data_set, "w", encoding="UTF-8"):
              pass
  
          # ----------------------------------------
  
          df["Epoch"] = index
          df["Prediction"] = df.apply(findPrediction, axis=1)
  
          base_df["Boosted_Prediction"] += df["Prediction"]
  
          loss = (
              (base_df["Boosted_Prediction"] - base_df["Decision"])
              .pow(2)
              .sum()
          )
          current_loss = loss / num_of_instances  # mse
  
          if index == 1:
              boosted_from = current_loss * 1
          elif index == epochs:
              boosted_to = current_loss * 1
              logger.debug(f"Boosted to {boosted_to}")
  
          if current_loss < best_epoch_loss:
              best_epoch_loss = current_loss * 1
              best_epoch_idx = index * 1
  
          df["Decision"] = int(learning_rate) * (
              df["Decision"] - df["Prediction"]
          )
          df = df.drop(columns=["Epoch", "Prediction"])
  
          # ---------------------------------
  
          df.to_csv(new_data_set, index=False)
          # data(i) created
  
          # ---------------------------------
  
          file = "outputs/rules/rules" + str(index) + ".py"
          json_file = "outputs/rules/rules" + str(index) + ".json"
  
          functions.createFile(file, header)
          functions.createFile(json_file, "[\n")
  
          current_df = df.copy()
          Training.buildDecisionTree(
              df,
              root,
              file,
              config,
              dataset_features,
              parent_level=0,
              leaf_id=0,
              parents="root",
              main_process_id=process_id,
          )
  
          # functions.storeRule(json_file," {}]")
  
          df = (
              current_df.copy()
          )  # numeric features require this restoration to apply findDecision function
  
          # rules(i) created
  
          loss = loss / num_of_instances
          logger.debug(f"epoch {index} - loss: {loss}")
          logger.debug(f"loss: {loss}")
          pbar.set_description(
              f"Epoch {index}. Loss: {loss}. Process: "
          )
  
          gc.collect()
  
      # ---------------------------------
  
      if silent is False:
          logger.info(
              f"The best epoch is {best_epoch_idx} with {best_epoch_loss} loss value"
          )
      models = models[0:best_epoch_idx]
      config["epochs"] = best_epoch_idx
  
      if silent is False:
          logger.info(
              f"MSE of {num_of_instances} instances are boosted from {boosted_from}"
              f"to {best_epoch_loss} in {epochs} epochs"
          )
  
      return models
  
file_path: chefboost/chefboost/tuning/gbm.py
imports: import gc
  from typing import Optional, Union
  import pandas
  import numpy
  from tqdm import tqdm
  from chefboost.commons import functions
  from chefboost.training import Training
  from chefboost.commons.logger import Logger
  from chefboost.commons.module import load_module
label_desc: Use image node_id 2 for calling a global function with example usage: regressor(df, config, header, dataset_features, validation_df, process_id, silent) and returns: models