正在加载中...

展开本页目录
算法教程TextRank-关键词

TextRank-关键词

No.070 · 在线教程

TextRank-关键词 的真实实现位于 core/textrankkeywordcalculator.py,界面参数入口在 ui/uploadwidget.py,结果导出与复现脚本生成功能在 ui/resultswidget.py。这套代码实现的是关键词提取,不是摘要生成,也…

TextRank-关键词

1. 方法概述

TextRank-关键词 的真实实现位于 core/textrank_keyword_calculator.py,界面参数入口在 ui/upload_widget.py,结果导出与复现脚本生成功能在 ui/results_widget.py。这套代码实现的是关键词提取,不是摘要生成,也不是基于词向量或预训练模型的语义排序。

设输入文档集合为

$$ \mathcal{D}=\{d_i\}_{i=1}^{N} \tag{1} $$

其中单文本模式对应 \(N=1\),批量模式对应 \(N>1\)。程序对每篇文档分别做分词、构图、PageRank 迭代,再输出每篇文档的关键词以及批量聚合结果。

2. 文本读取、语言判定与分词

2.1 输入模式

界面支持两种输入:

  • 单文本:读取 .txt/.md 或直接粘贴文本;
  • 批量:读取 .xlsx/.csv,每行一篇文档。

程序读取文本文件时会依次尝试 utf-8-sigutf-8gb18030gbk 解码,因此并不是只支持 UTF-8。

2.2 语言判定

若参数 language 不是用户手工指定的 zh/en,代码会按是否含有 CJK 字符自动判定:

$$ \mathrm{lang}(d)= \begin{cases} \text{zh}, & d \text{ 中存在中文字符}\\ \text{en}, & \text{otherwise} \end{cases} \tag{2} $$

这里的自动检测逻辑非常直接,本质上是正则判断是否出现 [\u4e00-\u9fff]

2.3 中文与英文分词

记文档 \(d_i\) 的词元序列为

$$ T_i=[t_{i1},t_{i2},\dots,t_{iL_i}] \tag{3} $$

真实实现有三条分支:

  1. 中文且 jieba 可导入时,使用 jieba.lcut(text, cut_all=False)
  2. 中文且启用 use_pos_filter=True 时,尝试用 jieba.posseg.cut() 做词性过滤,仅保留前缀属于 allowed_pos_prefixes 的词;
  3. 中文但 jieba 不可用时,退化为中文连续字串的固定 2-gram 切分

这个兜底分支很重要。它意味着程序在缺失 jieba 的环境下仍能运行,但输出的“词”可能是 词提键词 这种字级片段。results/TextRank-关键词分析结果_20260329_170033.xlsxTokens 工作表就体现了这一点。

英文分词则是正则提取小写 token:

$$ t \in \texttt{[A-Za-z][A-Za-z0-9\_'-]+} \tag{4} $$

之后统一做如下过滤:

  • 清理首尾标点;
  • 删除长度小于 min_token_len 的 token;
  • 删除停用词。

3. 停用词与词性过滤

停用词集合由“内置停用词 + 自定义停用词文件”合并得到:

$$ \mathcal{S}=\mathcal{S}_{\text{builtin}}\cup \mathcal{S}_{\text{custom}} \tag{5} $$

其中:

  • use_builtin_stopwords=True 时,中文与英文分别使用一小组硬编码停用词;
  • stopwords_path 可额外加载文本文件中的自定义停用词;
  • 批量模式下,如果 language="auto",则会对每篇文档单独判断语言,再决定取中文还是英文内置停用词。

如果启用词性过滤,则中文分词结果还要满足:

$$ \mathrm{prefix}(\mathrm{POS}(t)) \in \mathcal{P} \tag{6} $$

其中 \(\mathcal{P}\) 对应参数 allowed_pos_prefixes,界面默认值是 n,v,a。但这个过滤只在 jieba.posseg 可用时才真正生效。

4. 词共现图构建

4.1 图的定义

程序不是调用 networkx 的现成 TextRank,而是自己构造加权无向图。对序列 \(T_i\) 中的位置 \(p\),会把当前词与后面窗口内的词连接。若窗口大小为 \(w\),则共现边权可写成

$$ c_i(u,v)=\sum_{p<q,\ q-p<w}\mathbf{1}(t_{ip}=u,\ t_{iq}=v) \tag{7} $$

随后图边权满足

$$ W_i(u,v)=W_i(v,u)=c_i(u,v) \tag{8} $$

因此这是一张对称加权共现图。边权只是滑动窗口内的共现次数,并没有 TF-IDF、PMI 或别的重标定。

4.2 实现口径

这里的窗口并不是“全句窗口”,而是代码里 for j in range(i + 1, min(len(tokens), i + window_size)) 的局部滑窗。以 window_size=4 为例,词 \(t_i\) 只会和后面最多 3 个位置的词建立连接。

程序同时导出:

  • EdgesTop:按边权降序排列的前若干条共现边;
  • DocumentStats:每篇文档的 n_tokensn_unique_tokensn_edges 等图统计量。

5. PageRank 迭代

5.1 初始化与更新

对图中每个节点 \(u\),程序把初始分数设为 1:

$$ s_u^{(0)}=1 \tag{9} $$

之后按加权 PageRank 形式迭代:

$$ s_u^{(t+1)}=(1-d)+d\sum_{v\in\mathcal{N}(u)} \frac{W_i(v,u)}{\sum_{k\in\mathcal{N}(v)}W_i(v,k)}\,s_v^{(t)} \tag{10} $$

其中 \(d\) 对应参数 damping,默认是 0.85。

需要注意两点:

  1. 这里的实现没有把最终分数正规化为总和为 1 的概率分布;
  2. 输出到 Excel 的 score 是原始迭代结果,只用于排序比较。

5.2 收敛判定

每轮迭代都记录最大绝对变化量:

$$ \Delta^{(t)}=\max_u\left|s_u^{(t+1)}-s_u^{(t)}\right| \tag{11} $$

tol > 0

$$ \Delta^{(t)}<\mathrm{tol} \tag{12} $$

则提前停止;否则最多运行 max_iter 轮。Convergence 工作表会保存每轮的 itermax_deltaDocumentStats 中则汇总 pagerank_convergedpagerank_iters

6. 关键词输出与批量聚合

6.1 单文档关键词

单文档内先按 PageRank 分数降序排序,再截取前 top_k 个关键词:

$$ \mathrm{Rank}_i(u)=\mathrm{OrderDesc}\big(s_u\big) \tag{13} $$

$$ \mathcal{K}_i=\mathrm{TopK}\big(\{(u,s_u)\},\,K\big) \tag{14} $$

这部分结果会输出到:

  • keywords_single(内存结果);
  • KeywordsByDoc(Excel 中带 doc_id 的逐文档关键词表)。

6.2 批量模式的聚合规则

批量模式不是把所有文档拼接后重建一张全局图,而是先独立算出每篇文档的 Top-K,再对同名关键词的分数做求和:

$$ S_{\mathrm{agg}}(u)=\sum_{i=1}^{N} s_i(u) \tag{15} $$

然后再按 \(S_{\mathrm{agg}}(u)\) 排序,得到 KeywordsAggregated

所以这个“聚合关键词榜”表示的是各文档局部 TextRank 分数之和,并不是整个语料的一次全局 TextRank。

7. 输出结果与复现

7.1 Excel 工作表

save_results() 的真实导出工作表为:

  • Parameters
  • DocumentStats
  • KeywordsByDoc
  • KeywordsAggregated
  • InputText
  • Tokens
  • TokenFreq
  • EdgesTop
  • Convergence
  • PageRank
  • Charts

其中后面 6 张“过程表”只针对 step_results["docs"][0],也就是首篇文档的详细中间结果。

7.2 detail_level 的真实行为

calculate() 支持 detail_level in {"all","first","none"}

  • 单文本模式默认 all
  • 批量模式界面默认 first
  • 勾选“批量保留全部中间明细”后才会变成 all

这意味着批量模式默认不会把每篇文档的完整 tokens/edges/pagerank 都常驻内存,而是只保留首篇文档的详细过程,其他文档只保留 graph_statskeywords

7.3 图表与复现脚本

程序只生成一张图:

  • keywords_bar.png:Top 关键词得分横向柱状图。

结果页的“导出复现代码”按钮会生成 repro_textrank_时间戳.py。这个脚本并不是伪代码,而是直接重新调用 TextRankKeywordCalculator.run_analysis(),并复制输入文件到 repro_inputs/ 下,因此可直接复跑同一套核心实现。

8. 实现说明与注意事项

结合代码和真实结果,这个模块有几条需要在论文说明中写清的边界:

  1. 它是基于词共现图 + PageRank 的传统关键词提取,不涉及预训练表示、注意力机制或神经网络。
  2. 中文场景优先使用 jieba,但如果运行环境缺少 jieba,会退化为 2-gram 字片段,关键词质量会明显受影响。
  3. 批量模式的聚合结果是“逐文档分数求和”,不是全语料统一建图。
  4. score 是排序分数,不应直接解释成概率。
  5. 词性过滤、停用词、窗口大小和最小词长,决定了最终图结构与关键词排序,是这套实现里最关键的可调参数。

9. 论文写作模板

可在论文“方法部分”中写为:

“本文采用 TextRank 关键词提取方法对文本内容进行无监督分析。首先,对原始文本执行分词、停用词过滤和词性筛选;其次,根据词项在滑动窗口内的共现关系构建词图,并利用 PageRank 思想迭代计算各候选词的重要性得分;随后,按得分从高到低输出文本关键词及其统计信息;最后,结合关键词结果表和批量汇总输出,对文本主题信息和核心词项分布进行归纳分析。”

10. 单篇终审补充

10.1 图题与表题对齐建议

  • Parameters 表可写为:表X TextRank 参数设置表。
  • DocumentStats 表可写为:表X TextRank 文档统计表。
  • KeywordsByDoc 表可写为:表X TextRank 分文档关键词表。
  • KeywordsAggregated 表可写为:表X TextRank 聚合关键词表。
  • InputText 表可写为:表X TextRank 输入文本表。
  • Tokens 表可写为:表X TextRank 分词结果表。
  • TokenFreq 表可写为:表X TextRank 词频统计表。
  • EdgesTop 表可写为:表X TextRank 高权重边表。
  • Convergence 表可写为:表X TextRank PageRank 收敛过程表。
  • PageRank 表可写为:表X TextRank PageRank 得分表。
  • Charts 表可写为:表X TextRank 图表索引表。
  • keywords_bar.png 建议写为:图X TextRank 关键词得分条形图。

10.2 终审说明

  • 当前代表性结果目录可采用 results/TextRank-关键词分析结果_20260329_170033。其中主工作簿为 TextRank-关键词分析结果_20260329_170033.xlsx,复现脚本为 repro_textrank_20260329_170033.py
  • 当前真实工作表为 Parameters/DocumentStats/KeywordsByDoc/KeywordsAggregated/InputText/Tokens/TokenFreq/EdgesTop/Convergence/PageRank/Charts。论文表题应按这组英文 sheet 名准确落地,不能替换成“主题词分布/训练损失”等不相关术语。
  • 当前稳定实体图文件为 charts/keywords_bar.png。部分结果目录还会出现一份嵌套在同名子目录下的 keywords_bar.png 副本,正文引用时应以 Charts 工作表记录的实际路径为准,避免把副本当成第二张不同图。
  • Tokens/TokenFreq/EdgesTop/Convergence/PageRank 这几张过程表默认只对应首篇文档的详细中间结果,不代表批量模式下每篇文档都完整展开。论文若解释这些表,应明确它们是“首篇文档的过程性证据”。
  • 真实 repro 脚本通过 INPUT_FILE = 'repro_inputs/textrank_input_20260329_170033.txt' 读取输入副本。附录中的复现实验说明应保持这一相对路径口径;若换成批量 CSV 口径,也应在正文中单独说明输入模式发生了变化。

10.3 全量强化补充

  • 当前建议锚定的主结果目录是 具体的算法3/NLP基础/TextRank-关键词/results/TextRank-关键词分析结果_20260329_170033。主工作簿位于 具体的算法3/NLP基础/TextRank-关键词/results/TextRank-关键词分析结果_20260329_170033/TextRank-关键词分析结果_20260329_170033.xlsx
  • 这一本工作簿当前实际工作表为 ParametersDocumentStatsKeywordsByDocKeywordsAggregatedInputTextTokensTokenFreqEdgesTopConvergencePageRankCharts。因此这篇文档的工作表命名必须保持英文原名,不能擅自转写成“关键词结果表”“共现网络表”等中文别名后再声称是导出 sheet 名。
  • 当前主图文件是 具体的算法3/NLP基础/TextRank-关键词/results/TextRank-关键词分析结果_20260329_170033/charts/keywords_bar.png。同一结果目录下还额外存在一套嵌套副本 具体的算法3/NLP基础/TextRank-关键词/results/TextRank-关键词分析结果_20260329_170033/TextRank-关键词分析结果_20260329_170033/charts/keywords_bar.png,并且还带一份嵌套工作簿副本。正文里应把外层目录视作首层主结果,内层同名目录视作结果包复制副本,而不是第二轮独立实验。
  • 当前 repro 脚本是 具体的算法3/NLP基础/TextRank-关键词/results/TextRank-关键词分析结果_20260329_170033/repro_textrank_20260329_170033.py,其真实输入口径为 INPUT_FILE = 'repro_inputs/textrank_input_20260329_170033.txt';对应输入副本位于 具体的算法3/NLP基础/TextRank-关键词/results/TextRank-关键词分析结果_20260329_170033/repro_inputs/textrank_input_20260329_170033.txt
  • 这篇文档要特别强调:TokensTokenFreqEdgesTopConvergencePageRank 仅是首篇文档的过程表,而 KeywordsByDocKeywordsAggregated 才是面向整个输入批次的结果表。否则用户很容易误以为 PageRank 工作表覆盖了所有文档。
  • 因为当前复现脚本确实走 repro_inputs/...txt 单文件口径,所以若后续用户改成批量 CSV 或 Excel 输入模式,得到的结果包结构和 INPUT_FILE 写法会不同。文档里不应把当前这套 txt 复现证据泛化成“所有 TextRank 运行都固定如此”。

11. 软件实现核查补充(2026-07)

  • 当前实现的主结果目录应写作 具体的算法3/NLP基础/TextRank-关键词/results/TextRank-关键词分析结果_20260329_170033,主工作簿以 TextRank-关键词分析结果_20260329_170033.xlsx 为准。
  • 正文应围绕 ParametersDocumentStatsKeywordsByDocKeywordsAggregatedInputTextTokensTokenFreqEdgesTopConvergencePageRankCharts 来写。
  • 图证应对应 charts/keywords_bar.png,并明确这是一张关键词得分条形图,不要写成主题模型或分类图。
  • repro_textrank_20260329_170033.py + repro_inputs/textrank_input_20260329_170033.txt 是标准单文件输入复现口径,正文和附录应与主结果目录分开写。