code: def findGains(df: pd.DataFrame, config: dict) -> dict:
      """
      Find entropy and gains of each feature in the data frame
      Args:
          df (pd.DataFrame): (sub) train set as data frame
          config (dict): training configuration
      Returns:
          result (dict): gains with respect to the algorithm
      """
      algorithm = config["algorithm"]
      decision_classes = df["Decision"].unique()
  
      # -----------------------------
  
      entropy = 0
  
      if algorithm in ["ID3", "C4.5"]:
          entropy = calculateEntropy(df, config)
  
      columns = df.shape[1]
      instances = df.shape[0]
  
      gains = []
  
      for i in range(0, columns - 1):
          column_name = df.columns[i]
          column_type = df[column_name].dtypes
  
          logger.debug(f"{column_name} -> {column_type}")
  
          if column_type != "object":
              df = Preprocess.processContinuousFeatures(
                  algorithm, df, column_name, entropy, config
              )
  
          classes = df[column_name].value_counts()
  
          splitinfo = 0
          if algorithm in ["ID3", "C4.5"]:
              gain = entropy * 1
          else:
              gain = 0
  
          for j in range(0, len(classes)):
              current_class = classes.keys().tolist()[j]
              logger.debug(f"{column_name} -> {current_class}")
  
              subdataset = df[df[column_name] == current_class]
              logger.debug(subdataset)
  
              subset_instances = subdataset.shape[0]
              class_probability = subset_instances / instances
  
              if algorithm in ["ID3", "C4.5"]:
                  subset_entropy = calculateEntropy(subdataset, config)
                  gain = gain - class_probability * subset_entropy
  
              if algorithm == "C4.5":
                  splitinfo = splitinfo - class_probability * math.log(
                      class_probability, 2
                  )
  
              elif algorithm == "CART":  # GINI index
                  decision_list = (
                      subdataset["Decision"].value_counts().tolist()
                  )
  
                  subgini = 1
  
                  for current_decision in decision_list:
                      subgini = subgini - math.pow(
                          (current_decision / subset_instances), 2
                      )
  
                  gain = gain + (subset_instances / instances) * subgini
  
              elif algorithm == "CHAID":
                  num_of_decisions = len(decision_classes)
  
                  expected = subset_instances / num_of_decisions
  
                  for d in decision_classes:
                      num_of_d = subdataset[
                          subdataset["Decision"] == d
                      ].shape[0]
  
                      chi_square_of_d = math.sqrt(
                          (
                              (num_of_d - expected)
                              * (num_of_d - expected)
                          )
                          / expected
                      )
  
                      gain += chi_square_of_d
  
              elif algorithm == "Regression":
                  subset_stdev = subdataset["Decision"].std(ddof=0)
                  gain = (
                      gain
                      + (subset_instances / instances) * subset_stdev
                  )
  
          # iterating over classes for loop end
          # -------------------------------
  
          if algorithm == "Regression":
              stdev = df["Decision"].std(ddof=0)
              gain = stdev - gain
          if algorithm == "C4.5":
              if splitinfo == 0:
                  splitinfo = 100
                  # this can be if data set consists of 2 rows and current column consists
                  # of 1 class. still decision can be made (decisions for these 2 rows same).
                  # set splitinfo to very large value to make gain ratio very small.
                  # in this way, we won't find this column as the most dominant one.
              gain = gain / splitinfo
  
          # ----------------------------------
  
          gains.append(gain)
  
      # -------------------------------------------------
  
      resp_obj = {}
      resp_obj["gains"] = {}
  
      for idx, feature in enumerate(
          df.columns[0:-1]
      ):  # Decision is always the last column
          logger.debug(f"{idx}, {feature}")
          resp_obj["gains"][feature] = gains[idx]
  
      resp_obj["entropy"] = entropy
  
      return resp_obj
  
imports: import math
  import uuid
  import json
  import copy
  import gc
  from contextlib import closing
  from typing import Optional
  import psutil
  import numpy
  import pandas
  from chefboost.training import Preprocess
  from chefboost.commons import functions
  from chefboost.commons.logger import Logger
  from chefboost.commons.module import load_module
  from chefboost.commons.daemon import CustomPool
label_desc: Use image node_id 3 for calling a global function with example usage: findGains(df, config) and returns: resp_obj