code: def _extract_features(
      features: List[List[List["Features"]]],
      fake_features: List["Features"],
      attribute: Text,
  ) -> Tuple[
      List[np.ndarray],
      Dict[Text, List[List[np.ndarray]]],
      Dict[Text, List[List[scipy.sparse.spmatrix]]],
  ]:
      """Create masks for feature attributes and split into dense and sparse features.
  
      Args:
          features: all features
          fake_features: list of zero features
  
      Returns:
          - a list of attribute masks
          - a map of attribute to dense features
          - a map of attribute to sparse features
      """
      sparse_features = defaultdict(list)
      dense_features = defaultdict(list)
      attribute_masks = []
  
      for list_of_list_of_features in features:
          dialogue_sparse_features = defaultdict(list)
          dialogue_dense_features = defaultdict(list)
  
          # create a mask for every state
          # to capture which turn has which input
          attribute_mask = np.ones(
              len(list_of_list_of_features), np.float32
          )
  
          for i, list_of_features in enumerate(
              list_of_list_of_features
          ):
              if list_of_features is None:
                  # use zero features and set mask to zero
                  attribute_mask[i] = 0
                  list_of_features = fake_features
  
              for feature in list_of_features:
                  # in case of ENTITIES, if the attribute type matches either 'entity',
                  # 'role', or 'group' the features correspond to the tag ids of that
                  # entity type in order to distinguish later on between the different
                  # tag ids, we use the entity type as key
                  if attribute == ENTITIES and feature.attribute in [
                      ENTITY_ATTRIBUTE_TYPE,
                      ENTITY_ATTRIBUTE_GROUP,
                      ENTITY_ATTRIBUTE_ROLE,
                  ]:
                      key = feature.attribute
                  else:
                      key = feature.type
  
                  # all features should have the same types
                  if feature.is_sparse():
                      dialogue_sparse_features[key].append(
                          feature.features
                      )
                  else:
                      dialogue_dense_features[key].append(
                          feature.features
                      )
  
          for key, value in dialogue_sparse_features.items():
              sparse_features[key].append(value)
          for key, value in dialogue_dense_features.items():
              dense_features[key].append(value)
  
          # add additional dimension to attribute mask
          # to get a vector of shape (dialogue length x 1),
          # the batch dim will be added later
          attribute_mask = np.expand_dims(attribute_mask, -1)
          attribute_masks.append(attribute_mask)
  
      return attribute_masks, dense_features, sparse_features
  
imports: import typing
  import copy
  import numpy
  import scipy.sparse
  from collections import defaultdict, OrderedDict
  from typing import List, Optional, Text, Dict, Tuple, Union, Any, DefaultDict, cast
  from rasa.nlu.constants import TOKENS_NAMES
  from rasa.utils.tensorflow.model_data import Data, FeatureArray, ragged_array_to_ndarray
  from rasa.utils.tensorflow.constants import MASK, IDS
  from rasa.shared.nlu.training_data.message import Message
  from rasa.shared.nlu.constants import TEXT, ENTITIES, ENTITY_ATTRIBUTE_TYPE, ENTITY_ATTRIBUTE_GROUP, ENTITY_ATTRIBUTE_ROLE
label_desc: Use image node_id 9 for calling a global function with example usage: _extract_features(features, fake_features, attribute) and returns: attribute_masks,  dense_features,  sparse_features