code: def get_columns(self, usage, columns=None):
          
          columns_excluded = pd.Index([])
          columns_included = self.df.columns
  
          if self.has_target():
              columns_excluded = pd.Index([self.target_column])
  
          if self.has_id():
              columns_excluded = columns_excluded.union(pd.Index([self.id_column]))
  
          if usage == self.INCLUDE:
              try:
                  columns_included = columns_included.intersection(pd.Index(columns))
              except TypeError:
                  pass
          elif usage == self.EXCLUDE:
              try:
                  columns_excluded = columns_excluded.union(pd.Index(columns))
              except TypeError:
                  pass
  
          columns_included = columns_included.difference(columns_excluded)
          return columns_included.intersection(self.df.columns)
docs: Returns a `data_frame.columns`.
          :param usage (str): should be a value from [ALL, INCLUDE, EXCLUDE].
                              this value only makes sense if attr `columns` is also set.
                              otherwise, should be used with default value ALL.
          :param columns: * if `usage` is all, this value is not used.
                          * if `usage` is INCLUDE, the `df` is restricted to the intersection
                            between `columns` and the `df.columns`
                          * if usage is EXCLUDE, returns the `df.columns` excluding these `columns`
          :return: `data_frame` columns, excluding `target_column` and `id_column` if given.
                   `data_frame` columns, including/excluding the `columns` depending on `usage`.