TextRank-关键词
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-sig、utf-8、gb18030、gbk 解码,因此并不是只支持 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} $$
真实实现有三条分支:
- 中文且
jieba可导入时,使用jieba.lcut(text, cut_all=False); - 中文且启用
use_pos_filter=True时,尝试用jieba.posseg.cut()做词性过滤,仅保留前缀属于allowed_pos_prefixes的词; - 中文但
jieba不可用时,退化为中文连续字串的固定 2-gram 切分。
这个兜底分支很重要。它意味着程序在缺失 jieba 的环境下仍能运行,但输出的“词”可能是 词提、键词 这种字级片段。results/TextRank-关键词分析结果_20260329_170033.xlsx 中 Tokens 工作表就体现了这一点。
英文分词则是正则提取小写 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_tokens、n_unique_tokens、n_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 的概率分布;
- 输出到 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 工作表会保存每轮的 iter 与 max_delta,DocumentStats 中则汇总 pagerank_converged 和 pagerank_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() 的真实导出工作表为:
ParametersDocumentStatsKeywordsByDocKeywordsAggregatedInputTextTokensTokenFreqEdgesTopConvergencePageRankCharts
其中后面 6 张“过程表”只针对 step_results["docs"][0],也就是首篇文档的详细中间结果。
7.2 detail_level 的真实行为
calculate() 支持 detail_level in {"all","first","none"}:
- 单文本模式默认
all; - 批量模式界面默认
first; - 勾选“批量保留全部中间明细”后才会变成
all。
这意味着批量模式默认不会把每篇文档的完整 tokens/edges/pagerank 都常驻内存,而是只保留首篇文档的详细过程,其他文档只保留 graph_stats 与 keywords。
7.3 图表与复现脚本
程序只生成一张图:
keywords_bar.png:Top 关键词得分横向柱状图。
结果页的“导出复现代码”按钮会生成 repro_textrank_时间戳.py。这个脚本并不是伪代码,而是直接重新调用 TextRankKeywordCalculator.run_analysis(),并复制输入文件到 repro_inputs/ 下,因此可直接复跑同一套核心实现。
8. 实现说明与注意事项
结合代码和真实结果,这个模块有几条需要在论文说明中写清的边界:
- 它是基于词共现图 + PageRank 的传统关键词提取,不涉及预训练表示、注意力机制或神经网络。
- 中文场景优先使用
jieba,但如果运行环境缺少jieba,会退化为 2-gram 字片段,关键词质量会明显受影响。 - 批量模式的聚合结果是“逐文档分数求和”,不是全语料统一建图。
score是排序分数,不应直接解释成概率。- 词性过滤、停用词、窗口大小和最小词长,决定了最终图结构与关键词排序,是这套实现里最关键的可调参数。
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。 - 这一本工作簿当前实际工作表为
Parameters、DocumentStats、KeywordsByDoc、KeywordsAggregated、InputText、Tokens、TokenFreq、EdgesTop、Convergence、PageRank、Charts。因此这篇文档的工作表命名必须保持英文原名,不能擅自转写成“关键词结果表”“共现网络表”等中文别名后再声称是导出 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。 - 这篇文档要特别强调:
Tokens、TokenFreq、EdgesTop、Convergence、PageRank仅是首篇文档的过程表,而KeywordsByDoc、KeywordsAggregated才是面向整个输入批次的结果表。否则用户很容易误以为PageRank工作表覆盖了所有文档。 - 因为当前复现脚本确实走
repro_inputs/...txt单文件口径,所以若后续用户改成批量 CSV 或 Excel 输入模式,得到的结果包结构和INPUT_FILE写法会不同。文档里不应把当前这套 txt 复现证据泛化成“所有 TextRank 运行都固定如此”。
11. 软件实现核查补充(2026-07)
- 当前实现的主结果目录应写作
具体的算法3/NLP基础/TextRank-关键词/results/TextRank-关键词分析结果_20260329_170033,主工作簿以TextRank-关键词分析结果_20260329_170033.xlsx为准。 - 正文应围绕
Parameters、DocumentStats、KeywordsByDoc、KeywordsAggregated、InputText、Tokens、TokenFreq、EdgesTop、Convergence、PageRank、Charts来写。 - 图证应对应
charts/keywords_bar.png,并明确这是一张关键词得分条形图,不要写成主题模型或分类图。 repro_textrank_20260329_170033.py + repro_inputs/textrank_input_20260329_170033.txt是标准单文件输入复现口径,正文和附录应与主结果目录分开写。