CountVectorizer提取n-gram时sum_words及词频取值逻辑疑问
核心原理解答
直接拆解你疑问的两个核心对象逻辑,顺着代码执行流就能理清楚:
1. 为什么从vec.vocabulary_里拿不到词频
vec.vocabulary_本质是个位置映射字典,它从设计上就不存储任何计数信息:
- 字典的键是语料中提取到的所有目标n-gram词项
- 字典的值是该词项在词袋特征矩阵中对应的列编号
- 这个列编号是fit阶段按规则分配的位置标记,和词出现多少次没有任何关系,你直接取这个值当然得不到词频结果。
举个最简单的例子,如果语料里只出现两个bigram:"natural language"、"processing task",fit后vocabulary_可能输出{"natural language":1, "processing task":0},这里的0和1只是列位置,完全不代表出现次数。
2. sum_words矩阵存储的内容
逐行对应代码逻辑看矩阵的变化:
vec.transform(corpus)输出的bag_of_words是形状为(语料文档总数, 所有n-gram词项总数)的稀疏矩阵:- 每1行对应corpus里的1条输入文本
- 每1列对应
vocabulary_里的1个固定词项 - 矩阵中坐标
(i,j)的数值,代表第j个词项在第i条文本里的出现次数
bag_of_words.sum(axis=0)是沿着行方向做累加,也就是把所有文档中同一列(同一个词项)的出现次数加总,得到的sum_words是形状为(1, 词项总数)的单行矩阵:- 矩阵唯一一行(第0行)的第j列数值,就是第j个词项在整个语料中的总出现次数
- 因为是单行矩阵,取数时必须写
sum_words[0, idx]:第一个索引固定取第0行,第二个索引用vocabulary_里拿到的列编号idx,就能精准取到对应词的总频次。
3. 你困惑的列表推导式逻辑
[(word, sum_words[0, idx]) for word, idx in vec.vocabulary_.items()]
这段做的事情非常直接:遍历所有「词项-列编号」的映射对,拿着列编号去总频次矩阵里查对应词的全语料出现次数,最终组装成(词, 总频次)格式的元组列表,后续只要按频次倒序排序、切片取前n个,就能得到Top n-gram结果。
注意:必须使用
vocabulary_返回的idx取数,这个索引是和矩阵列一一绑定的,自行传入的索引会导致词和频次错位,得到完全错误的结果。
内容的提问来源于stack exchange,提问作者Edvard
相关产品推荐
相关产品推荐

