code: def ngrams(
      doclike: types.DocLike,
      n: int | Collection[int],
      *,
      filter_stops: bool = True,
      filter_punct: bool = True,
      filter_nums: bool = False,
      include_pos: Optional[str | Collection[str]] = None,
      exclude_pos: Optional[str | Collection[str]] = None,
      min_freq: int = 1,
  ) -> Iterable[Span]:
      """
      Extract an ordered sequence of n-grams (``n`` consecutive tokens) from a spaCy
      ``Doc`` or ``Span``, for one or multiple ``n`` values, optionally filtering n-grams
      by the types and parts-of-speech of the constituent tokens.
  
      Args:
          doclike
          n: Number of tokens included per n-gram; for example, ``2`` yields bigrams
              and ``3`` yields trigrams. If multiple values are specified, then the
              collections of n-grams are concatenated together; for example, ``(2, 3)``
              yields bigrams and then trigrams.
          filter_stops: If True, remove ngrams that start or end with a stop word.
          filter_punct: If True, remove ngrams that contain any punctuation-only tokens.
          filter_nums: If True, remove ngrams that contain any numbers
              or number-like tokens (e.g. 10, 'ten').
          include_pos: Remove ngrams if any constituent tokens' part-of-speech tags
              ARE NOT included in this param.
          exclude_pos: Remove ngrams if any constituent tokens' part-of-speech tags
              ARE included in this param.
          min_freq: Remove ngrams that occur in ``doclike`` fewer than ``min_freq`` times
  
      Yields:
          Next ngram from ``doclike`` passing all specified filters, in order of appearance
          in the document.
  
      Raises:
          ValueError: if any ``n`` < 1
          TypeError: if ``include_pos`` or ``exclude_pos`` is not a str, a set of str,
              or a falsy value
  
      Note:
          Filtering by part-of-speech tag uses the universal POS tag set; for details,
          check spaCy's docs: https://spacy.io/api/annotation#pos-tagging
      """
      ns_: tuple[int, ...] = utils.to_tuple(n)
      if any(n_ < 1 for n_ in ns_):
          raise ValueError("n must be greater than or equal to 1")
  
      ngrams_: Iterable[Span]
      for n_ in ns_:
          ngrams_ = (
              doclike[i : i + n_] for i in range(len(doclike) - n_ + 1)
          )
          ngrams_ = (
              ng for ng in ngrams_ if not any(w.is_space for w in ng)
          )
          if filter_stops is True:
              ngrams_ = (
                  ng
                  for ng in ngrams_
                  if not ng[0].is_stop and not ng[-1].is_stop
              )
          if filter_punct is True:
              ngrams_ = (
                  ng
                  for ng in ngrams_
                  if not any(w.is_punct for w in ng)
              )
          if filter_nums is True:
              ngrams_ = (
                  ng
                  for ng in ngrams_
                  if not any(w.like_num for w in ng)
              )
          if include_pos:
              include_pos_: set[str] = {
                  pos.upper() for pos in utils.to_set(include_pos)
              }
              ngrams_ = (
                  ng
                  for ng in ngrams_
                  if all(w.pos_ in include_pos_ for w in ng)
              )
          if exclude_pos:
              exclude_pos_: set[str] = {
                  pos.upper() for pos in utils.to_set(exclude_pos)
              }
              ngrams_ = (
                  ng
                  for ng in ngrams_
                  if not any(w.pos_ in exclude_pos_ for w in ng)
              )
          if min_freq > 1:
              ngrams_ = list(ngrams_)
              freqs = itertoolz.frequencies(
                  ng.text.lower() for ng in ngrams_
              )
              ngrams_ = (
                  ng
                  for ng in ngrams_
                  if freqs[ng.text.lower()] >= min_freq
              )
  
          for ngram in ngrams_:
              yield ngram
  
file_path: textacy/src/textacy/extract/basics.py
imports: from __future__ import annotations
  from functools import partial
  from typing import Collection, Iterable, Optional, Union
  from cytoolz import itertoolz
  from spacy.parts_of_speech import DET
  from spacy.tokens import Span, Token
  from ..None import constants, errors, types, utils
label_desc: Use image node_id 2 for calling a global function with example usage: ngrams(doclike, n) without return types