我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

CountVectorizer被称之为词袋模型,它来自于sklearn,日常用于词频统计。苏南大叔在之前也写过有关CountVectorizer词频统计的文章。不过,现在对CountVectorizer又有了新的理解,所以,这里再次写文章总结对CountVectorizer新的理解。

苏南大叔:利用CountVectorizer词袋模型,如何对中文语料库词频统计? - 词袋模型中文统计
利用CountVectorizer词袋模型,如何对中文语料库词频统计?(图2-1)

苏南大叔的“程序如此灵动”技术博客,记录苏南大叔的代码经验总结。本文测试环境:win10python@3.11.0scikit-learn@1.2.2

语料库分词

如果是英文这种以空格做单词分割的语种,是不需要做这一步分词的处理的。但是,如果是中文这种没有天然空格做分割的语料库,还是需要使用:结巴分词/snownlp/其它分词工具,进行分词处理的。分词结果可以使用空格或者英文逗号或中文逗号进行分割。

参考文章:

下面的代码中,语料库变量是苏南大叔手工分词的结果:

corpus = [
    "老许 是 一只 黑色 猫咪",
    "虎子,是,一只,黑色,狗子",
    "哈吉米,是,一只,黑色,猫咪",
    "老许 非常 可爱",
    "虎子,同样,非常,可爱",
    "哈吉米,也,很,可爱",
]  # 语料库,空格或者中英文逗号分割,都是可以的。

初始化词袋模型

下面出场的是本文的主角CountVectorizer词袋模型,它有很多参数。不过,大多数都暂时用不到。可以直接初始化:

from sklearn.feature_extraction.text import CountVectorizer
cv = CountVectorizer()  # 词袋模型

最常用的就是一个stop_words,停用词列表,可以过滤掉一些无用的词儿,以便于更加精准的了解数据。比如:

from sklearn.feature_extraction.text import CountVectorizer
cv = CountVectorizer(stop_words=["一只", "非常"])  # 词袋模型

然而,经过实际运行会发现:一些单字的词儿(比如语料库中的“是/也/很”),即使没有在stop_words中设置,也会被过滤掉。那么,如果您介意的话,可以通过下面的参数,把这些单字的中文词儿找回来。这个正则表达式,对其它一些非中文语种可能不是很合适。所以,视需求进行修改即可。

from sklearn.feature_extraction.text import CountVectorizer
cv = CountVectorizer(token_pattern="[\u4e00-\u9fa5_a-zA-Z0-9]{1,}")  # 词袋模型

填充数据进行转换

cv_fit = cv.fit_transform(corpus)  # (0, 6) 1   (0, 0) 1

或者下面这样调用,也是可以的,两者等效。

cv.fit(corpus)
cv_fit = cv.transform(corpus)  # (0, 6) 1   (0, 0) 1

特征及词汇表

print(cv.get_feature_names_out(), len(cv.get_feature_names_out())) 
# 模型默认认为:单字的词儿,无法构成feature特征
# ['一只' '可爱' '同样' '哈吉米' '狗子' '猫咪' '老许' '虎子' '非常' '黑色'] 10

print(cv.vocabulary_, len(cv.vocabulary_))
# 词汇表就是:{特征:索引}
# {'老许': 6, '一只': 0, '黑色': 9, '猫咪': 5, '虎子': 7, '狗子': 4, '哈吉米': 3, '非常': 8, '可爱': 1, '同样': 2} 10

从结果可以看到,这个结果是自动过滤了那些单字的词儿(token)的。所以,可能的原因是:

  • 设置了停用词stop_words,包含了目标词汇。
  • 没有设置token_pattern,没有把目标词汇包含进来。
print(cv.get_stop_words())

stop_words是自己设置的,为啥还要再求解一次呢?没有设置的话,返回None,也就是大家通常上理解的Null

cv_fit 格式及类型

print(cv_fit,type(cv_fit))            # (0, 6)  1  (0, 0) 1  <class 'scipy.sparse._csr.csr_matrix'>

输出:

  (0, 6)        1
  (0, 0)        1
  (0, 9)        1
  (0, 5)        1
  (1, 0)        1
  (1, 9)        1
  (1, 7)        1
  (1, 4)        1
  (2, 0)        1
  (2, 9)        1
  (2, 5)        1
  (2, 3)        1
  (3, 6)        1
  (3, 8)        1
  (3, 1)        1
  (4, 7)        1
  (4, 8)        1
  (4, 1)        1
  (4, 2)        1
  (5, 3)        1
  (5, 1)        1 <class 'scipy.sparse._csr.csr_matrix'>

对于cv_fit的输出的正确理解,还是需要结合词汇表cv.vocabulary_的结果的。词汇表cv.vocabulary_输出是:

{'老许': 6, '一只': 0, '黑色': 9, '猫咪': 5, '虎子': 7, '狗子': 4, '哈吉米': 3, '非常': 8, '可爱': 1, '同样': 2}
  • 其格式是:(语料库的id,词汇表的索引) 当前语料库id里面,该词汇出现了几次
  • cv_fit类型是一个没见过的新类型:<class 'scipy.sparse._csr.csr_matrix'>

例如,cv_fit的条目(2, 0) 1

  • 2表示语料库索引为2的语料(就是第三条语料),"哈吉米,是,一只,黑色,猫咪"。
  • 0根据词汇表可以知道:是“一只”。
  • 1,就是表示“一只”这个token在"哈吉米,是,一只,黑色,猫咪"语料中,出现了一次。

cv_fit.toarray()

下面的就是苏南大叔自己写的分析代码了,主要功能就是对官方函数输出的结果,再组合解释了一下。
cv_fit.toarray()是每条语料化身为词汇表索引的结果,对应索引位置上显示计数值。

print(cv_fit.toarray())               # [[1 0 0 0 0 1 1 0 0 1] [1 0 0 0 1 0 0 1 0 1]]

[1 0 0 0 0 1 1 0 0 1]翻译回来的预料是:一只,,,,,猫咪,老许,,,黑色
1表示:对应的词儿是出现的词儿出现了一次。0表述没有出现。
所以,它可能另外的表现形式是:[2,0,3,5,6,1]这样其它的数字组合。

print(cv_fit.toarray().sum(axis=0))   # 每个词在所有文档中的词频 [3 3 1 2 1 2 2 2 2 3]

如果把数据理解到excel里面,就很好理解cv_fit.toarray().sum(axis=0),就是账单方向的求和。

  • 数据表的每行是第一条语料库。
  • 数据表的每列是词汇表里面的每个词汇(token)。

数据分析最终结果

_cnt = cv_fit.toarray().sum(axis=0)
_dic = cv.vocabulary_

res = {v: k for k, v in _dic.items()}
res2 = [(k, res[k]) for k in sorted(res.keys())]
# print(res)
# print(res2)

for key, value in res2:
    print(value, ",词频是:", _cnt[key])

输出:

一只 ,词频是: 3
可爱 ,词频是: 3
同样 ,词频是: 1
哈吉米 ,词频是: 2
狗子 ,词频是: 1
猫咪 ,词频是: 2
老许 ,词频是: 2
虎子 ,词频是: 2
非常 ,词频是: 2
黑色 ,词频是: 3

这里涉及了下面两篇文章:

完整代码

这是付费可看内容,收费5元。

苏南大叔:利用CountVectorizer词袋模型,如何对中文语料库词频统计? - 词频统计代码
利用CountVectorizer词袋模型,如何对中文语料库词频统计?(图2-2)

可能存在的问题 .get_feature_names_out()

cv.get_feature_names_out(),在老版本里面,其函数原型是:cv.get_feature_names()

所以,如果还使用以前的文章里面的代码的话,会得到如下错误提示信息:

AttributeError: 'CountVectorizer' object has no attribute 'get_feature_names'. Did you mean: 'get_feature_names_out'?

解决方案就是:给get_feature_names()函数换个名字,换成get_feature_names_out()

结语

苏南大叔的更多sklearn机器学习的经验文章,请点击下面的链接:

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   python    sklearn