code: def fit(
      df: pd.DataFrame,
      config: Optional[dict] = None,
      target_label: str = "Decision",
      validation_df: Optional[pd.DataFrame] = None,
      silent: bool = False,
  ) -> Dict[str, Any]:
      """
      Build (a) decision tree model(s)
  
      Args:
              df (pandas data frame): Training data frame.
  
              config (dictionary): training configuration. e.g.
  
                      config = {
                              'algorithm' (string): ID3, 'C4.5, CART, CHAID or Regression
                              'enableParallelism' (boolean): False
  
                              'enableGBM' (boolean): True,
                              'epochs' (int): 7,
                              'learning_rate' (int): 1,
  
                              'enableRandomForest' (boolean): True,
                              'num_of_trees' (int): 5,
  
                              'enableAdaboost' (boolean): True,
                              'num_of_weak_classifier' (int): 4
                      }
  
              target_label (str): target label for supervised learning.
                  Default is Decision at the end of dataframe.
  
              validation_df (pandas data frame): validation data frame
                  if nothing is passed to validation data frame, then the function validates
                  built trees for training data frame
  
              silent (bool): set this to True if you do not want to see
                  any informative logs
  
      Returns:
              chefboost model
      """
  
      # ------------------------
  
      process_id = os.getpid()
  
      # ------------------------
      # rename target column name
      if target_label != "Decision":
          # TODO: what if another column name is Decision?
          df = df.rename(columns={target_label: "Decision"})
  
      # if target is not the last column
      if df.columns[-1] != "Decision":
          if "Decision" in df.columns:
              new_column_order = df.columns.drop(
                  "Decision"
              ).tolist() + ["Decision"]
              logger.debug(new_column_order)
              df = df[new_column_order]
          else:
              raise ValueError("Please set the target_label")
  
      # ------------------------
  
      base_df = df.copy()
  
      # ------------------------
  
      target_label = df.columns[len(df.columns) - 1]
  
      # ------------------------
      # handle NaN values
  
      nan_values = []
  
      for column in df.columns:
          if df[column].dtypes != "object":
              min_value = df[column].min()
              idx = df[df[column].isna()].index
  
              nan_value = []
              nan_value.append(column)
  
              if idx.shape[0] > 0:
                  df.loc[idx, column] = min_value - 1
                  nan_value.append(min_value - 1)
                  logger.debug(
                      "NaN values are replaced to {min_value - 1} in column {column}"
                  )
              else:
                  nan_value.append(None)
  
              nan_values.append(nan_value)
  
      # ------------------------
  
      # initialize params and folders
      config = functions.initializeParams(config)
      functions.initializeFolders()
  
      # ------------------------
  
      algorithm = config["algorithm"]
  
      valid_algorithms = ["ID3", "C4.5", "CART", "CHAID", "Regression"]
  
      if algorithm not in valid_algorithms:
          raise ValueError(
              "Invalid algorithm passed. You passed ",
              algorithm,
              " but valid algorithms are ",
              valid_algorithms,
          )
  
      # ------------------------
  
      enableRandomForest = config["enableRandomForest"]
      enableGBM = config["enableGBM"]
      enableAdaboost = config["enableAdaboost"]
      enableParallelism = config["enableParallelism"]
  
      # ------------------------
  
      if enableParallelism == True:
          num_cores = config["num_cores"]
          if silent is False:
              logger.info(
                  f"[INFO]: {num_cores} CPU cores will be allocated in parallel running"
              )
  
          from multiprocessing import set_start_method, freeze_support
  
          set_start_method("spawn", force=True)
          freeze_support()
      # ------------------------
      num_of_columns = df.shape[1]
  
      if algorithm == "Regression":
          if df["Decision"].dtypes == "object":
              raise ValueError(
                  "Regression trees cannot be applied for nominal target values!"
                  "You can either change the algorithm or data set."
              )
  
      if (
          df["Decision"].dtypes != "object"
      ):  # this must be regression tree even if it is not mentioned in algorithm
          if algorithm != "Regression":
              logger.warn(
                  f"You set the algorithm to {algorithm} but the Decision column of your"
                  " data set has non-object type."
                  "That's why, the algorithm is set to Regression to handle the data set."
              )
  
          algorithm = "Regression"
          config["algorithm"] = "Regression"
  
      if enableGBM == True:
          if silent is False:
              logger.info("Gradient Boosting Machines...")
          algorithm = "Regression"
          config["algorithm"] = "Regression"
  
      if enableAdaboost == True:
          # enableParallelism = False
          for j in range(0, num_of_columns):
              column_name = df.columns[j]
              if df[column_name].dtypes == "object":
                  raise ValueError(
                      "Adaboost must be run on numeric data set for both features and target"
                  )
  
      # -------------------------
  
      if silent is False:
          logger.info(f"{algorithm} tree is going to be built...")
  
      # initialize a dictionary. this is going to be used to check features numeric or nominal.
      # numeric features should be transformed to nominal values based on scales.
      dataset_features = {}
  
      header = "def findDecision(obj): #"
  
      num_of_columns = df.shape[1] - 1
      for i in range(0, num_of_columns):
          column_name = df.columns[i]
          dataset_features[column_name] = df[column_name].dtypes
          header += f"obj[{str(i)}]: {column_name}"
  
          if i != num_of_columns - 1:
              header = header + ", "
  
      header = header + "\n"
  
      # ------------------------
  
      begin = time.time()
  
      trees = []
      alphas = []
  
      if enableAdaboost == True:
          trees, alphas = adaboost_clf.apply(
              df,
              config,
              header,
              dataset_features,
              validation_df=validation_df,
              process_id=process_id,
              silent=silent,
          )
  
      elif enableGBM == True:
          if (
              df["Decision"].dtypes == "object"
          ):  # transform classification problem to regression
              trees, alphas = gbm.classifier(
                  df,
                  config,
                  header,
                  dataset_features,
                  validation_df=validation_df,
                  process_id=process_id,
                  silent=silent,
              )
              # classification = True
  
          else:  # regression
              trees = gbm.regressor(
                  df,
                  config,
                  header,
                  dataset_features,
                  validation_df=validation_df,
                  process_id=process_id,
                  silent=silent,
              )
              # classification = False
  
      elif enableRandomForest == True:
          trees = randomforest.apply(
              df,
              config,
              header,
              dataset_features,
              validation_df=validation_df,
              process_id=process_id,
              silent=silent,
          )
      else:  # regular decision tree building
          root = 1
          file = "outputs/rules/rules.py"
          functions.createFile(file, header)
  
          if enableParallelism == True:
              json_file = "outputs/rules/rules.json"
              functions.createFile(json_file, "[\n")
  
          trees = Training.buildDecisionTree(
              df,
              root=root,
              file=file,
              config=config,
              dataset_features=dataset_features,
              parent_level=0,
              leaf_id=0,
              parents="root",
              validation_df=validation_df,
              main_process_id=process_id,
          )
  
      if silent is False:
          logger.info("-------------------------")
          logger.info(f"finished in {time.time() - begin} seconds")
  
      obj = {
          "trees": trees,
          "alphas": alphas,
          "config": config,
          "nan_values": nan_values,
      }
  
      # -----------------------------------------
  
      # train set accuracy
      df = base_df.copy()
      trainset_evaluation = evaluate(
          obj, df, task="train", silent=silent
      )
      obj["evaluation"] = {"train": trainset_evaluation}
  
      # validation set accuracy
      if isinstance(validation_df, pd.DataFrame):
          validationset_evaluation = evaluate(
              obj, validation_df, task="validation", silent=silent
          )
          obj["evaluation"]["validation"] = validationset_evaluation
  
      return obj
  
file_path: chefboost/chefboost/Chefboost.py
imports: import time
  import pickle
  import os
  import json
  from typing import Optional, Dict, Any, Union
  import numpy
  import pandas
  from chefboost.commons import functions, evaluate
  from chefboost.training import Training
  from chefboost.tuning import gbm, adaboost, randomforest
  from chefboost.commons.logger import Logger
label_desc: Use image node_id 1 for calling a global function with example usage: fit(df, config, target_label, validation_df, silent) and returns: obj