code: def sgrank(
      doc: Doc,
      *,
      normalize: Optional[str | Callable[[Span], str]] = "lemma",
      ngrams: int | Collection[int] = (1, 2, 3, 4, 5, 6),
      include_pos: Optional[str | Collection[str]] = (
          "NOUN",
          "PROPN",
          "ADJ",
      ),
      window_size: int = 1500,
      topn: int | float = 10,
      idf: Optional[dict[str, float]] = None,
  ) -> list[tuple[str, float]]:
      """
      Extract key terms from a document using the SGRank algorithm.
  
      Args:
          doc: spaCy ``Doc`` from which to extract keyterms.
          normalize: If "lemma", lemmatize terms; if "lower", lowercase terms; if None,
              use the form of terms as they appeared in ``doc``; if a callable,
              must accept a ``Span`` and return a str,
              e.g. :func:`textacy.spacier.utils.get_normalized_text()`
          ngrams: n of which n-grams to include. For example, ``(1, 2, 3, 4, 5, 6)`` (default)
              includes all ngrams from 1 to 6; `2` if only bigrams are wanted
          include_pos: One or more POS tags with which to filter for good candidate keyterms.
              If None, include tokens of all POS tags
              (which also allows keyterm extraction from docs without POS-tagging.)
          window_size: Size of sliding window in which term co-occurrences are determined
              to occur. Note: Larger values may dramatically increase runtime, owing to
              the larger number of co-occurrence combinations that must be counted.
          topn: Number of top-ranked terms to return as keyterms.
              If int, represents the absolute number; if float, must be in the open interval
              (0.0, 1.0), and is converted to an integer by ``int(round(len(candidates) * topn))``
          idf: Mapping of ``normalize(term)`` to inverse document frequency
              for re-weighting of unigrams (n-grams with n > 1 have df assumed = 1).
              Results are typically better with idf information.
  
      Returns:
          Sorted list of top ``topn`` key terms and their corresponding SGRank scores
  
      Raises:
          ValueError: if ``topn`` is a float but not in (0.0, 1.0] or ``window_size`` < 2
  
      References:
          Danesh, Sumner, and Martin. "SGRank: Combining Statistical and Graphical
          Methods to Improve the State of the Art in Unsupervised Keyphrase Extraction."
          Lexical and Computational Semantics (* SEM 2015) (2015): 117.
      """
      # validate / transform args
      ngrams: tuple[int, ...] = utils.to_tuple(ngrams)
      include_pos: Optional[set[str]] = (
          utils.to_set(include_pos) if include_pos else None
      )
      if window_size < 2:
          raise ValueError("`window_size` must be >= 2")
      if isinstance(topn, float):
          if not 0.0 < topn <= 1.0:
              raise ValueError(
                  "`topn` must be an int, or a float between 0.0 and 1.0"
              )
  
      n_toks = len(doc)
      window_size = min(n_toks, window_size)
      # bail out on (nearly) empty docs
      if n_toks < 2:
          return []
  
      candidates, candidate_counts = _get_candidates(
          doc, normalize, ngrams, include_pos
      )
      # scale float topn based on total number of initial candidates
      if isinstance(topn, float):
          topn = int(round(len(candidate_counts) * topn))
      candidates, unique_candidates = _prefilter_candidates(
          candidates, candidate_counts, topn, idf
      )
  
      term_weights = _compute_term_weights(
          candidates, candidate_counts, unique_candidates, n_toks, idf
      )
      # filter terms to only those with positive weights
      candidates = [
          cand for cand in candidates if term_weights[cand.text] > 0
      ]
      edge_weights = _compute_edge_weights(
          candidates, term_weights, window_size, n_toks
      )
  
      # build the weighted directed graph from edges, rank nodes by pagerank
      graph = nx.DiGraph()
      graph.add_edges_from(edge_weights)
      term_ranks = nx_pagerank(graph, alpha=0.85, weight="weight")
      sorted_term_ranks = sorted(
          term_ranks.items(), key=itemgetter(1, 0), reverse=True
      )
  
      return ext_utils.get_filtered_topn_terms(
          sorted_term_ranks, topn, match_threshold=0.8
      )
  
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 1 for calling a global function with example usage: sgrank(doc) and returns: ext_utils, list