code: def extract_features(
      text_dataset: pd.DataFrame,
      target_column: Union[str, List],
      task_type: str,
      dropped_features: Optional[List[str]] = None,
  ):
      """Extract tabular data features from the text dataset.
  
      :param text_dataset: A pandas dataframe containing the text data.
      :type text_dataset: pandas.DataFrame
      :param target_column: The name of the label column or list of columns.
              This is a list of columns for multilabel models.
      :type target_column: str or list[str]
      :param task_type: The type of task to be performed.
      :type task_type: str
      :param dropped_features: The list of features to be dropped.
      :type dropped_features: list[str]
      :return: The list of extracted features and the feature names.
      :rtype: list, list
      """
      results = []
      base_feature_names = [
          "positive_words",
          "negative_words",
          "negation_words",
          "negated_entities",
          "named_persons",
          "sentence_length",
      ]
      single_text_col_tasks = [
          ModelTask.TEXT_CLASSIFICATION,
          ModelTask.MULTILABEL_TEXT_CLASSIFICATION,
      ]
      has_dropped_features = dropped_features is not None
      start_meta_index = 2
      column_names = text_dataset.columns
      if isinstance(target_column, list):
          start_meta_index = len(target_column) + 1
      if task_type in single_text_col_tasks:
          feature_names = base_feature_names
      elif task_type == ModelTask.QUESTION_ANSWERING:
          start_meta_index += 1
          feature_names = []
          prefixes = [
              QuestionAnsweringFields.CONTEXT + "_",
              QuestionAnsweringFields.QUESTION + "_",
          ]
          for prefix in prefixes:
              for feature_name in base_feature_names:
                  feature_names.append(prefix + feature_name)
              feature_names.append(prefix + "average_parse_tree_depth")
              feature_names.append(prefix + "maximum_parse_tree_depth")
          feature_names.append("question_type")
          feature_names.append("context_overlap")
      else:
          raise ValueError("Unknown task type: {}".format(task_type))
      # copy over the metadata column names
      for j in range(start_meta_index, text_dataset.shape[1]):
          if (
              has_dropped_features
              and column_names[j] in dropped_features
          ):
              continue
          feature_names.append(column_names[j])
      if not isinstance(target_column, list):
          target_column = [target_column]
      text_features = text_dataset.drop(target_column, axis=1)
  
      if task_type in single_text_col_tasks:
          sentences = text_features.iloc[:, 0].tolist()
          for i, sentence in tqdm(enumerate(sentences)):
              extracted_features = []
              add_extracted_features_for_sentence(
                  sentence, extracted_features
              )
              # append all other metadata features
              append_metadata_values(
                  start_meta_index,
                  text_dataset,
                  i,
                  extracted_features,
                  has_dropped_features,
                  dropped_features,
                  column_names,
              )
              results.append(extracted_features)
      elif task_type == ModelTask.QUESTION_ANSWERING:
          for i, row in tqdm(text_features.iterrows()):
              extracted_features = []
              add_extracted_features_for_sentence(
                  row[QuestionAnsweringFields.CONTEXT],
                  extracted_features,
                  task_type,
              )
              add_extracted_features_for_sentence(
                  row[QuestionAnsweringFields.QUESTIONS],
                  extracted_features,
                  task_type,
                  sentence_type="QUESTION",
              )
  
              context = row[QuestionAnsweringFields.CONTEXT]
              question = row[QuestionAnsweringFields.QUESTIONS]
              context_overlap = get_context_overlap(
                  context=context, question=question
              )
              extracted_features.append(context_overlap)
              # append all other metadata features
              append_metadata_values(
                  start_meta_index,
                  text_dataset,
                  i,
                  extracted_features,
                  has_dropped_features,
                  dropped_features,
                  column_names,
              )
              results.append(extracted_features)
      else:
          raise ValueError("Unknown task type: {}".format(task_type))
      return results, feature_names
  
file_path: responsible-ai-toolbox/responsibleai_text/responsibleai_text/utils/feature_extractors.py
imports: import re
  from typing import List, Optional, Union
  import pandas
  import spacy
  from negspacy.termsets import termset
  from tqdm import tqdm
  from nlp_feature_extractors import attribute_extractors
  from responsibleai_text.common.constants import ModelTask, QuestionAnsweringFields
label_desc: Use image node_id 1 for calling a global function with example usage: extract_features(text_dataset, target_column, task_type, dropped_features) and returns: results,  feature_names