Top2Vec-主题模型
这个目录虽然命名为 Top2Vec-主题模型,但真实核心实现并不是官方 top2vec 包。项目里的主流程写在:
Top2Vec-主题模型
1. 方法概述
这个目录虽然命名为 Top2Vec-主题模型,但真实核心实现并不是官方 top2vec 包。项目里的主流程写在:
core/top2vec_runner.pycore/text_prep.pyutils/excel_handler.py
而且代码里没有 import top2vec,requirements.txt 和 README.md 也都明确写成 Top2Vec-lite。因此这一模块应理解为一条自定义主题建模流水线:
文本预处理 -> Count/TF-IDF -> TruncatedSVD 文档向量 -> UMAP/PCA 降维 -> HDBSCAN/KMeans 聚类 -> 簇均值主题词输出
设文档集合为
$$ \mathcal{D}=\{d_i\}_{i=1}^{N} \tag{1} $$
其中每个 \(d_i\) 是一篇文本。模块最终输出的是主题簇、每篇文档的簇标签、每个簇的高权重词和主题散点图。
2. 数据预处理与向量化
2.1 文本清洗
load_text_dataset() 会按 DatasetConfig 做预处理,包括:
drop_emptylowercasestrip_punct
规范化后的文本记为
$$ \tilde d_i=\mathrm{Norm}(d_i) \tag{2} $$
若未提供 id_col,则自动使用字符串形式的 \(1,2,\dots,N\) 作为 doc_id。
2.2 analyzer 的自动判定
向量化配置位于 VectorizerConfig,支持:
vectorizer in {"tfidf","count"}analyzer in {"auto","word","char"}
当 analyzer="auto" 时,代码会统计文本集合中含 CJK 字符的文档比例;若比例至少为 0.3,则切到字符级,否则切到词级:
$$ \mathrm{analyzer}= \begin{cases} \text{char}, & \frac{\#\{d_i:\text{含CJK}\}}{N}\ge 0.3\\ \text{word}, & \text{otherwise} \end{cases} \tag{3} $$
这意味着混合语料很容易被自动切到 char 模式。results/top2vec_smoke_20260227_194131/hdbscan_mixed.xlsx 的 Vec_Meta 工作表就显示了这种情况。
2.3 Count / TF-IDF 文档项矩阵
向量化后的文档项矩阵记为
$$ X=\mathrm{Vec}(\tilde d_1,\dots,\tilde d_N)\in\mathbb{R}^{N\times V} \tag{4} $$
其中:
- 若
vectorizer="tfidf",则 \(X\) 是 TF-IDF 矩阵; - 若
vectorizer="count",则 \(X\) 是词频矩阵。
词级模式下,token_pattern 被显式设为 (?u)\b\w+\b,因此单字符词也可以进入词表。字符级模式则直接使用 sklearn 的 analyzer="char",不是自定义中文分词器。
2.4 停用词
停用词模式只有三种:
$$ \mathcal{S}\in\{\varnothing,\ \text{english},\ \text{custom}\} \tag{5} $$
其中 custom 通过 _parse_stopwords() 把文本框中的内容按换行、逗号或空格拆开。若 analyzer="char",停用词仍按字符串条目匹配,因此并不是面向“词”的中文停用词机制。
3. 文档向量与降维
3.1 真实嵌入方式始终是 SVD
虽然 EmbeddingConfig 里存在 method: "lite" | "top2vec",但 run_top2vec() 里并没有根据这个字段分支,实际总是调用 _svd_embeddings()。所以真实文档向量来自 TruncatedSVD,而不是官方 Top2Vec 的联合语义嵌入。
对矩阵 \(X\) 做截断 SVD:
$$ X \approx U_k\Sigma_k V_k^\top \tag{6} $$
文档向量取自
$$ e_i=\mathrm{Normalize}\big((U_k\Sigma_k)_i\big) \tag{7} $$
其中 embedding_dim 只是请求维度,真实维度会被裁剪到 min(n_docs-1, n_features-1, embedding_dim)。导出的 embedding.explained_var_sum 会记录累计解释方差比。
3.2 降维逻辑
得到 \(e_i\) 后,程序再做可选降维。记降维后向量为
$$ r_i=\mathrm{Reduce}(e_i) \tag{8} $$
真实规则是:
- 若
reduce_dim <= 0或reduce_dim >= emb.shape[1],则不降维; - 否则优先尝试
UMAP(metric="cosine"); - 若
umap-learn不可用,再回退到PCA; - 若 PCA 也失败,则保留原向量。
需要注意:Topic_Vis_2D 和散点图并不要求真实降维结果恰好是 2 维,只要 emb_red.shape[1] >= 2,程序就取前两列做可视化。
4. 聚类与主题得分
4.1 聚类标签
主题标签来自对降维后向量 \(r_i\) 的聚类:
$$ z_i=\mathrm{Cluster}(r_i) \tag{9} $$
支持两种方式:
hdbscankmeans
但真实行为还有一个重要兜底:
- 如果请求
hdbscan,只要导入或训练失败,代码就会自动回退到kmeans。
因此 Excel 中的请求参数和实际执行方法可能不同。hdbscan_mixed.xlsx 里 Cluster 工作表仍写着 method=hdbscan,但 Summary 和 Cluster_Meta 已经显示真实执行的是 kmeans。
4.2 主题得分
聚类完成后,代码并不是在降维空间里打分,而是回到原始 SVD 文档向量 \(e_i\) 上,计算每个主题的质心:
$$ c_t=\mathrm{Normalize}\left(\frac{1}{|I_t|}\sum_{i\in I_t} e_i\right) \tag{10} $$
其中 \(I_t=\{i:z_i=t\}\)。文档对所属主题的得分定义为
$$ \mathrm{score}_i=\mathrm{clip}(e_i^\top c_{z_i},-1,1) \tag{11} $$
若 z_i=-1(HDBSCAN 噪声点),则 topic_score=0,并在 Doc_Topic 中写入 is_noise=1。
所以这里的 topic_score 本质上是文档向量与主题质心的余弦相似度,不是官方 Top2Vec 里的语义相似度检索分数。
5. 主题词与主题文档
5.1 主题词生成方式
这一步也不是官方 Top2Vec 的“主题向量附近最近词”。代码做的是:对每个主题簇内文档的向量化表示求均值,再取权重最大的特征。
若主题 \(t\) 的文档集合为 \(I_t\),则主题词权重向量为
$$ \bar x_t=\frac{1}{|I_t|}\sum_{i\in I_t} X_i \tag{12} $$
然后按 \(\bar x_t\) 的分量从大到小取前 top_words 个词。
因此:
- 当
vectorizer="tfidf"时,主题词权重是簇内平均 TF-IDF; - 当
vectorizer="count"时,主题词权重是簇内平均词频。
它更接近“聚类后均值主题词”,而不是 Top2Vec 原论文里基于词向量和主题向量的最近邻检索。
5.2 主题文档
Topic_TopDocs 的生成规则是:对每个主题内部,按 topic_score 从高到低取前 top_docs 篇文档,并保留最多 200 个字符的 text_snippet。
这意味着主题代表文档也是按“文档向量到主题质心的相似度”选出来的。
6. 输出结果与复现
6.1 Excel 工作表
save_results() 的真实导出工作表为:
SummaryDatasetVectorizerEmbeddingClusterOutputData_MetaVec_MetaCluster_MetaTopics_TopWordsDoc_TopicTopic_TopDocsTopic_Vis_2DChartsCharts_Index
其中:
Cluster保存的是请求参数;Cluster_Meta保存的是实际执行的聚类信息;Charts只有一列topic_scatter;Charts_Index则更规范地记录chart_name/file_path/exists。
6.2 图表
导出器只会生成一张图:
Top2Vec_topic_scatter_*.png
图中按 topic 分组把 Topic_Vis_2D 里的 (x,y) 坐标画成散点图。若主题数不超过 15,会显示图例。
6.3 复现脚本
结果页的“导出复现代码”会生成 repro_top2vec_时间戳.py。脚本会:
- 复制原始输入文件到
repro_inputs/ - 用保存下来的
DatasetConfig / VectorizerConfig / EmbeddingConfig / ClusterConfig / OutputConfig - 重新调用
run_top2vec() - 再保存一份
Top2Vec_results_*_repro.xlsx
这说明复现脚本调用的仍然是当前这套 Top2Vec-lite 核心实现。
7. 实现说明与注意事项
结合代码、requirements.txt 和真实结果,这个模块在论文说明中必须写清以下边界:
- 它不是官方 Top2Vec 的文档-词-主题联合嵌入实现,而是一个
Top2Vec-lite近似流程。 EmbeddingConfig.method只是参数字段,当前版本并不会切换到真正的top2vec算法;实际永远走TruncatedSVD。topics_top_words来自簇内文档项向量均值,不是主题向量的最近邻词。- 请求
hdbscan并不保证最终就用 HDBSCAN;失败时会静默回退到kmeans,需要看Cluster_Meta或Summary才知道真实执行方法。 analyzer="auto"在中文占比稍高时会切到字符级;字符级结果可能包含单字符甚至空格特征。hdbscan_mixed.xlsx中Topics_TopWords出现' '、'e'就是这一实现口径的直接体现。
8. 论文写作模板
可在论文“方法部分”中写为:
“本文采用 Top2Vec 风格的主题发现方法对文本语料进行无监督主题挖掘。首先,对文本进行清洗和嵌入表示学习,获得文档向量;其次,通过降维与聚类方法在向量空间中识别潜在主题结构,并进一步提取聚类邻域中的代表性主题词和主题文档;随后,结合主题分布结果、主题词列表和可视化输出对语料主题结构进行解释;最后,形成主题摘要结果,为后续文本内容归纳和主题分析提供依据。”
9. 单篇终审补充
9.1 图题与表题对齐建议
Summary表可写为:表X Top2Vec 主题模型运行摘要表。Dataset表可写为:表X Top2Vec 数据集配置表。Vectorizer表可写为:表X Top2Vec 向量化参数表。Embedding表可写为:表X Top2Vec 嵌入配置表。Cluster表可写为:表X Top2Vec 聚类参数表。Output表可写为:表X Top2Vec 输出摘要表。Data_Meta表可写为:表X Top2Vec 数据元信息表。Vec_Meta表可写为:表X Top2Vec 向量化元信息表。Cluster_Meta表可写为:表X Top2Vec 实际聚类执行信息表。Topics_TopWords表可写为:表X Top2Vec 主题 Top 词表。Doc_Topic表可写为:表X Top2Vec 文档主题归属表。Topic_TopDocs表可写为:表X Top2Vec 主题 Top 文档表。Topic_Vis_2D表可写为:表X Top2Vec 二维主题可视化坐标表。Charts表可写为:表X Top2Vec 图表路径表。Charts_Index表可写为:表X Top2Vec 图表索引与存在性检查表。Top2Vec_topic_scatter_*.png建议写为:图X Top2Vec 主题二维散点图。
9.2 终审说明
- 当前代表性结果目录可采用
results/Top2Vec-主题模型分析结果_20260323_231850。其中主工作簿为Top2Vec_results_20260323_231850.xlsx,复现输出为Top2Vec_results_20260323_231850_repro.xlsx。 - 当前真实工作表为
Summary/Dataset/Vectorizer/Embedding/Cluster/Output/Data_Meta/Vec_Meta/Cluster_Meta/Topics_TopWords/Doc_Topic/Topic_TopDocs/Topic_Vis_2D/Charts/Charts_Index。论文表题应按这组英文 sheet 名落地。 - 当前稳定实体图文件为
Top2Vec_topic_scatter_20260323_231850.png,复现后还会新生成一张Top2Vec_topic_scatter_20260323_231852.png。正文引用散点图时应说明哪一张是主运行图、哪一张是复现图。 - 真实 repro 脚本为
repro_top2vec_20260323_231850.py,并通过SRC_FILE = 'repro_inputs/sample_data.csv'读取输入副本。附录中的复现实验说明应保持repro_inputs/...相对路径口径。 - 当前工程是
Top2Vec-lite近似实现,不是官方 Top2Vec 全流程。论文若使用“Top2Vec”表述,建议在方法细节里补一句说明其实际是“基于降维与聚类的 Top2Vec 风格实现”,避免与官方算法定义混淆。
9.3 全量强化补充
- 当前应锁定的主结果目录是
具体的算法3/NLP基础/Top2Vec-主题模型/results/Top2Vec-主题模型分析结果_20260323_231850。主工作簿为具体的算法3/NLP基础/Top2Vec-主题模型/results/Top2Vec-主题模型分析结果_20260323_231850/Top2Vec_results_20260323_231850.xlsx,复现再生成工作簿为同目录下的Top2Vec_results_20260323_231850_repro.xlsx。 - 这两本工作簿当前实际工作表完全一致,均为
Summary、Dataset、Vectorizer、Embedding、Cluster、Output、Data_Meta、Vec_Meta、Cluster_Meta、Topics_TopWords、Doc_Topic、Topic_TopDocs、Topic_Vis_2D、Charts、Charts_Index。因此这篇文档里应明确区分“首层主结果”和“复现再生结果”,而不是区分两本表的 sheet 结构差异。 - 当前目录内至少存在三张散点图:
Top2Vec_topic_scatter_20260323_231850.png、Top2Vec_topic_scatter_20260323_231852.png、Top2Vec_topic_scatter_20260329_151158.png。因此正文若只写“主运行图与复现图”,还不够严谨;更准确的写法应是以231850对应首层主工作簿,以231852和20260329_151158视为后续复现或再次导出的同目录图像产物。 - 当前 repro 脚本为
具体的算法3/NLP基础/Top2Vec-主题模型/results/Top2Vec-主题模型分析结果_20260323_231850/repro_top2vec_20260323_231850.py,其真实输入口径为SRC_FILE = 'repro_inputs/sample_data.csv';对应输入副本位于首层repro_inputs/sample_data.csv。
10. 软件实现核查补充(2026-07)
- 当前实现的主结果目录应写作
具体的算法3/NLP基础/Top2Vec-主题模型/results/Top2Vec-主题模型分析结果_20260323_231850,主工作簿以Top2Vec_results_20260323_231850.xlsx为准。 - 正文应围绕
Summary、Dataset、Vectorizer、Embedding、Cluster、Output、Data_Meta、Vec_Meta、Cluster_Meta、Topics_TopWords、Doc_Topic、Topic_TopDocs、Topic_Vis_2D、Charts、Charts_Index来写。 - 图证应对应
Top2Vec_topic_scatter_20260323_231850.png及后续复现图,但正文要明确主图和复现图的时间戳差异。 repro_top2vec_20260323_231850.py + repro_inputs/sample_data.csv是标准repro_inputs复现口径,正文和附录应和主结果目录分开说明。