code: def _get_candidates(
      doc: Doc,
      normalize: Optional[str | Callable[[Span], str]],
      ngrams: tuple[int, ...],
      include_pos: Optional[set[str]],
  ) -> tuple[list[Candidate], Counter[str]]:
      """
      Get n-gram candidate keyterms from ``doc``, with key information for each:
      its normalized text string, position within the doc, number of constituent words,
      and frequency of occurrence.
      """
      min_term_freq = min(max(len(doc) // 1000, 1), 4)
      cand_tuples = list(
          ext_utils.get_ngram_candidates(
              doc, ngrams, include_pos=include_pos
          )
      )
      cand_texts = [
          " ".join(
              ext_utils.terms_to_strings(ctup, normalize or "orth")
          )
          for ctup in cand_tuples
      ]
      cand_counts = collections.Counter(cand_texts)
      candidates = [
          Candidate(
              text=ctext,
              idx=ctup[0].i,
              length=len(ctup),
              count=cand_counts[ctext],
          )
          for ctup, ctext in zip(cand_tuples, cand_texts)
      ]
      if min_term_freq > 1:
          candidates = [
              candidate
              for candidate in candidates
              if candidate.count >= min_term_freq
          ]
      return candidates, cand_counts
  
file_path: textacy/src/textacy/extract/keyterms/sgrank.py
imports: from __future__ import annotations
  import collections
  import itertools
  import math
  from operator import itemgetter
  from typing import Callable, Collection, Counter, Optional
  import networkx
  from spacy.tokens import Doc, Span
  from ...None import utils
  from ..None import utils
label_desc: Use image node_id 2 for calling a global function with example usage: _get_candidates(doc, normalize, ngrams, include_pos) and returns: candidates,  cand_counts