code: def to_bag_of_terms(
      doclike: types.DocLike,
      *,
      by: SpanGroupByType = "lemma_",
      weighting: WeightingType = "count",
      ngs: Optional[
          int | Collection[int] | types.DocLikeToSpans
      ] = None,
      ents: Optional[bool | types.DocLikeToSpans] = None,
      ncs: Optional[bool | types.DocLikeToSpans] = None,
      dedupe: bool = True,
  ) -> dict[str, int] | dict[str, float]:
      """
      Transform a ``Doc`` or ``Span`` into a bag-of-terms: the set of unique terms therein
      mapped to their absolute, relative, or binary frequencies of occurrence,
      where "terms" may be a combination of n-grams, entities, and/or noun chunks.
  
      Args:
          doclike
          by: Attribute by which spaCy ``Span`` s are grouped before counting,
              as given by ``getattr(token, by)``.
              If "lemma", tokens are counted by their base form w/o inflectional suffixes;
              if "lower", by the lowercase form of the token text;
              if "orth", by the token text exactly as it appears in ``doc``.
              To output keys as strings, simply append an underscore to any of these;
              for example, "lemma_" creates a bag whose keys are token lemmas as strings.
          weighting: Type of weighting to assign to unique terms given by ``by``.
              If "count", weights are the absolute number of occurrences (i.e. counts);
              if "freq", weights are counts normalized by the total token count,
              giving their relative frequency of occurrence;
              if "binary", weights are set equal to 1.
          ngs: N-gram terms to be extracted.
              If one or multiple ints, :func:`textacy.extract.ngrams(doclike, n=ngs)` is
              used to extract terms; if a callable, ``ngs(doclike)`` is used to extract
              terms; if None, no n-gram terms are extracted.
          ents: Entity terms to be extracted.
              If True, :func:`textacy.extract.entities(doclike)` is used to extract terms;
              if a callable, ``ents(doclike)`` is used to extract terms;
              if None, no entity terms are extracted.
          ncs: Noun chunk terms to be extracted.
              If True, :func:`textacy.extract.noun_chunks(doclike)` is used to extract
              terms; if a callable, ``ncs(doclike)`` is used to extract terms;
              if None, no noun chunk terms are extracted.
          dedupe: If True, deduplicate terms whose spans are extracted by multiple types
              (e.g. a span that is both an n-gram and an entity), as identified by
              identical (start, stop) indexes in ``doclike``; otherwise, don't.
  
      Returns:
          Mapping of a unique term id or string (depending on the value of ``by``)
          to its absolute, relative, or binary frequency of occurrence
          (depending on the value of ``weighting``).
  
      See Also:
          :func:`textacy.extract.terms()`
      """
      terms = basics.terms(
          doclike, ngs=ngs, ents=ents, ncs=ncs, dedupe=dedupe
      )
      # spaCy made some awkward changes in the Span API, making it harder to get int ids
      # and adding inconsistencies with equivalent Token API
      # so, here are some hacks to spare users that annoyance
      if by.startswith("lower"):
          bot = cytoolz.recipes.countby(
              lambda span: span.text.lower(), terms
          )
      else:
          by_ = by if by.endswith("_") else f"{by}_"
          bot = cytoolz.recipes.countby(operator.attrgetter(by_), terms)
      # if needed, here we take the term strings and manually convert back to ints
      if not by.endswith("_"):
          ss = doclike.vocab.strings
          bot = {
              ss.add(term_str): weight
              for term_str, weight in bot.items()
          }
      bot = _reweight_bag(weighting, bot, doclike)
      return bot
  
file_path: textacy/src/textacy/extract/bags.py
imports: from __future__ import annotations
  import operator
  from typing import Any, Collection, Literal, Optional, Union
  import cytoolz
  from ..None import errors, types
  from .None import basics
label_desc: Use image node_id 2 for calling a global function with example usage: to_bag_of_terms(doclike) and returns: bot