class_docstr: Vocabulary class that handles parsing and printing composite values such as
  compositional XPOS and universal morphological features (UFeats).
  
  Two key options are `keyed` and `sep`. `sep` specifies the separator used between
  different parts of the composite values, which is `|` for UFeats, for example.
  If `keyed` is `True`, then the incoming value is treated similarly to UFeats, where
  each part is a key/value pair separated by an equal sign (`=`). There are no inherit
  order to the keys, and we sort them alphabetically for serialization and deserialization.
  Whenever a part is absent, its internal value is a special `<EMPTY>` symbol that will
  be treated accordingly when generating the output. If `keyed` is `False`, then the parts
  are treated as positioned values, and `<EMPTY>` is used to pad parts at the end when the
  incoming value is not long enough.
code: def build_vocab(self):
      allunits = [w[self.idx] for sent in self.data for w in sent]
      if self.keyed:
          self._id2unit = dict()
  
          for u in allunits:
              parts = self.unit2parts(u)
              for key in parts:
                  if key not in self._id2unit:
                      self._id2unit[key] = copy(VOCAB_PREFIX)
  
                  # treat multi-valued properties as singletons
                  if parts[key] not in self._id2unit[key]:
                      self._id2unit[key].append(parts[key])
  
          # special handle for the case where upos/xpos/ufeats are always empty
          if len(self._id2unit) == 0:
              self._id2unit["_"] = copy(
                  VOCAB_PREFIX
              )  # use an arbitrary key
  
      else:
          self._id2unit = dict()
  
          allparts = [self.unit2parts(u) for u in allunits]
          maxlen = max([len(p) for p in allparts])
  
          for parts in allparts:
              for i, p in enumerate(parts):
                  if i not in self._id2unit:
                      self._id2unit[i] = copy(VOCAB_PREFIX)
                  if i < len(parts) and p not in self._id2unit[i]:
                      self._id2unit[i].append(p)
  
          # special handle for the case where upos/xpos/ufeats are always empty
          if len(self._id2unit) == 0:
              self._id2unit[0] = copy(
                  VOCAB_PREFIX
              )  # use an arbitrary key
  
      self._id2unit = OrderedDict(
          [(k, self._id2unit[k]) for k in sorted(self._id2unit.keys())]
      )
      self._unit2id = {
          k: {w: i for i, w in enumerate(self._id2unit[k])}
          for k in self._id2unit
      }
  
imports: from copy import copy
  from collections import Counter, OrderedDict
  from collections.abc import Iterable
  import os
  import pickle
label_desc: Use image node_id 5 for calling the CompositeVocab obj's underlying member method code with example usage: obj.build_vocab() without return types