code: def reduce_mem_usage(df):
      """
      #####################################################################
      Greatly indebted to :
      https://www.kaggle.com/arjanso/reducing-dataframe-memory-size-by-65
          for this function to reduce memory usage.
      #####################################################################
      It is a bit slow as it iterate through all the columns of a dataframe and modifies data types
          to reduce memory usage. But it has been shown to reduce memory usage by 65% or so.
      """
      start_mem = df.memory_usage().sum() / 1024**2
      if type(df) == dask.dataframe.core.DataFrame:
          start_mem = start_mem.compute()
      print(
          "    Caution: We will try to reduce the memory usage of dataframe from {:.2f} MB".format(
              start_mem
          )
      )
      cols = df.columns
      if type(df) == dask.dataframe.core.DataFrame:
          cols = cols.tolist()
      datevars = df.select_dtypes(
          include=[np.datetime64]
      ).columns.tolist()
      numvars = df.select_dtypes(include="number").columns.tolist()
      for col in cols:
          col_type = df[col].dtype
          if col in datevars:
              pass
          elif col in numvars:
              c_min = df[col].min()
              c_max = df[col].max()
              if type(df) == dask.dataframe.core.DataFrame:
                  c_min = c_min.compute()
                  c_max = c_max.compute()
              if str(col_type)[:3] == "int":
                  if (
                      c_min > np.iinfo(np.int8).min
                      and c_max < np.iinfo(np.int8).max
                  ):
                      df[col] = df[col].astype(np.int8)
                  elif (
                      c_min > np.iinfo(np.int16).min
                      and c_max < np.iinfo(np.int16).max
                  ):
                      df[col] = df[col].astype(np.int16)
                  elif (
                      c_min > np.iinfo(np.int32).min
                      and c_max < np.iinfo(np.int32).max
                  ):
                      df[col] = df[col].astype(np.int32)
                  elif (
                      c_min > np.iinfo(np.int64).min
                      and c_max < np.iinfo(np.int64).max
                  ):
                      df[col] = df[col].astype(np.int64)
              else:
                  if (
                      c_min > np.finfo(np.float16).min
                      and c_max < np.finfo(np.float16).max
                  ):
                      df[col] = df[col].astype(np.float16)
                  elif (
                      c_min > np.finfo(np.float32).min
                      and c_max < np.finfo(np.float32).max
                  ):
                      df[col] = df[col].astype(np.float32)
                  else:
                      df[col] = df[col].astype(np.float64)
          else:
              df[col] = df[col].astype("category")
  
      #######  Results after memory usage function ###################
      end_mem = df.memory_usage().sum() / 1024**2
      if type(df) == dask.dataframe.core.DataFrame:
          end_mem = end_mem.compute()
      print(
          "    Memory usage after optimization is: {:.2f} MB".format(
              end_mem
          )
      )
      print(
          "        decreased by {:.1f}%".format(
              100 * (start_mem - end_mem) / start_mem
          )
      )
  
      return df
  
imports: from typing import List
  import numpy
  import pandas
  import copy
  import pdb
  from sklearn.model_selection import TimeSeriesSplit
  import dask
  import dask.dataframe
  import datetime
  from datetime import datetime, date, time
label_desc: Use image node_id 14 for calling a global function with example usage: reduce_mem_usage(df) and returns: df