(
    doc: Doc,
    *,
    normalize: Optional[str | Callable[[Token], str]] = "lemma",
    include_pos: Optional[str | Collection[str]] = ("NOUN", "PROPN", "ADJ"),
    topn: int | float = 10,
)
return ext_utils.get_filtered_topn_terms(
        sorted_candidate_scores, topn, match_threshold=0.8
    )
Extract key terms from a document using the sCAKE algorithm.

    Args:
        doc: spaCy ``Doc`` from which to extract keyterms. Must be sentence-segmented;
            optionally POS-tagged.
        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 ``Token`` and return a str,
            e.g. :func:`textacy.spacier.utils.get_normalized_text()`.
        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.)
        topn: Number of top-ranked terms to return as key terms.
            If an integer, represents the absolute number; if a float, value
            must be in the interval (0.0, 1.0], which is converted to an int by
            ``int(round(len(candidates) * topn))``

    Returns:
        Sorted list of top ``topn`` key terms and their corresponding scores.

    References:
        Duari, Swagata & Bhatnagar, Vasudha. (2018). sCAKE: Semantic Connectivity
        Aware Keyword Extraction. Information Sciences. 477.
        https://arxiv.org/abs/1811.10831v1
Extract key terms from a document using the sCAKE algorithm.
Extract key terms from a document using the sCAKE algorithm .
def scake(
    doc: Doc,
    *,
    normalize: Optional[str | Callable[[Token], str]] = "lemma",
    include_pos: Optional[str | Collection[str]] = ("NOUN", "PROPN", "ADJ"),
    topn: int | float = 10,
) -> List[Tuple[str, float]]:
    """
    Extract key terms from a document using the sCAKE algorithm.

    Args:
        doc: spaCy ``Doc`` from which to extract keyterms. Must be sentence-segmented;
            optionally POS-tagged.
        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 ``Token`` and return a str,
            e.g. :func:`textacy.spacier.utils.get_normalized_text()`.
        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.)
        topn: Number of top-ranked terms to return as key terms.
            If an integer, represents the absolute number; if a float, value
            must be in the interval (0.0, 1.0], which is converted to an int by
            ``int(round(len(candidates) * topn))``

    Returns:
        Sorted list of top ``topn`` key terms and their corresponding scores.

    References:
        Duari, Swagata & Bhatnagar, Vasudha. (2018). sCAKE: Semantic Connectivity
        Aware Keyword Extraction. Information Sciences. 477.
        https://arxiv.org/abs/1811.10831v1
    """
    # validate / transform args
    include_pos = utils.to_collection(include_pos, str, set)
    if isinstance(topn, float):
        if not 0.0 < topn <= 1.0:
            raise ValueError(
                "topn={} is invalid; "
                "must be an int, or a float between 0.0 and 1.0".format(topn)
            )

    # bail out on empty docs
    if not doc:
        return []

    # build up a graph of good words, edges weighting by adjacent sentence co-occurrence
    cooc_mat: Counter[Tuple[str, str]] = collections.Counter()
    # handle edge case where doc only has 1 sentence
    n_sents = itertoolz.count(doc.sents)
    for window_sents in itertoolz.sliding_window(min(2, n_sents), doc.sents):
        if n_sents == 1:
            window_sents = (window_sents[0], [])
        window_words: Iterable[str] = (
            word
            for word in itertoolz.concat(window_sents)
            if not (word.is_stop or word.is_punct or word.is_space)
            and (not include_pos or word.pos_ in include_pos)
        )
        window_words = ext_utils.terms_to_strings(window_words, normalize)
        cooc_mat.update(
            w1_w2
            for w1_w2 in itertools.combinations(sorted(window_words), 2)
            if w1_w2[0] != w1_w2[1]
        )
    # doc doesn't have any valid words...
    if not cooc_mat:
        return []

    graph = nx.Graph()
    graph.add_edges_from(
        (w1, w2, {"weight": weight}) for (w1, w2), weight in cooc_mat.items()
    )

    word_scores = _compute_word_scores(doc, graph, cooc_mat, normalize)
    if not word_scores:
        return []

    # generate a list of candidate terms
    candidates = _get_candidates(doc, normalize, include_pos)
    if isinstance(topn, float):
        topn = int(round(len(set(candidates)) * topn))
    # rank candidates by aggregating constituent word scores
    candidate_scores = {
        " ".join(candidate): sum(word_scores.get(word, 0.0) for word in candidate)
        for candidate in candidates
    }
    sorted_candidate_scores = sorted(
        candidate_scores.items(), key=itemgetter(1, 0), reverse=True
    )
    return ext_utils.get_filtered_topn_terms(
        sorted_candidate_scores, topn, match_threshold=0.8
    )
def scake ( doc : Doc , * , normalize : Optional [ str | Callable [ [ Token ] , str ] ] = "lemma" , include_pos : Optional [ str | Collection [ str ] ] = ( "NOUN" , "PROPN" , "ADJ" ) , topn : int | float = 10 , ) -> List [ Tuple [ str , float ] ] : # validate / transform args include_pos = utils . to_collection ( include_pos , str , set ) if isinstance ( topn , float ) : if not 0.0 < topn <= 1.0 : raise ValueError ( "topn={} is invalid; " "must be an int, or a float between 0.0 and 1.0" . format ( topn ) ) # bail out on empty docs if not doc : return [ ] # build up a graph of good words, edges weighting by adjacent sentence co-occurrence cooc_mat : Counter [ Tuple [ str , str ] ] = collections . Counter ( ) # handle edge case where doc only has 1 sentence n_sents = itertoolz . count ( doc . sents ) for window_sents in itertoolz . sliding_window ( min ( 2 , n_sents ) , doc . sents ) : if n_sents == 1 : window_sents = ( window_sents [ 0 ] , [ ] ) window_words : Iterable [ str ] = ( word for word in itertoolz . concat ( window_sents ) if not ( word . is_stop or word . is_punct or word . is_space ) and ( not include_pos or word . pos_ in include_pos ) ) window_words = ext_utils . terms_to_strings ( window_words , normalize ) cooc_mat . update ( w1_w2 for w1_w2 in itertools . combinations ( sorted ( window_words ) , 2 ) if w1_w2 [ 0 ] != w1_w2 [ 1 ] ) # doc doesn't have any valid words... if not cooc_mat : return [ ] graph = nx . Graph ( ) graph . add_edges_from ( ( w1 , w2 , { "weight" : weight } ) for ( w1 , w2 ) , weight in cooc_mat . items ( ) ) word_scores = _compute_word_scores ( doc , graph , cooc_mat , normalize ) if not word_scores : return [ ] # generate a list of candidate terms candidates = _get_candidates ( doc , normalize , include_pos ) if isinstance ( topn , float ) : topn = int ( round ( len ( set ( candidates ) ) * topn ) ) # rank candidates by aggregating constituent word scores candidate_scores = { " " . join ( candidate ) : sum ( word_scores . get ( word , 0.0 ) for word in candidate ) for candidate in candidates } sorted_candidate_scores = sorted ( candidate_scores . items ( ) , key = itemgetter ( 1 , 0 ) , reverse = True ) return ext_utils . get_filtered_topn_terms ( sorted_candidate_scores , topn , match_threshold = 0.8 )