用于机器学习的文本有一种最简单的方法,也是最有效且最常用的方法,就是使用词袋表示。使用这种表示方法时,我们舍弃了输入文本中的大部分结构,比如章节、段落、句子和格式,只计算语料库中,只计算语料库中每个单词在每个文本中出现的频次。舍弃结构并仅计算单词出现的次数,这会让脑海中出现将文本表示为"袋"的画面。
对于文档语料库,计算词袋表示包括以下三个步骤:
1、分词。将每个文档划分为出现在其中的单词(称为词例 token),比如按空格和标点划分。
2、构建词表。收集一个词表,里面包含出现在任意文档中的所有词,并对它们进行编号。
3、编码。对于每个文档,计算词表中每个单词在该文档中出现的频次。
在步骤1和步骤2涉及一些细微之处。我们来看一下如何利用scikit-learn来应用词袋处理过程。词袋的输出是包含每个文档中单词计数的一个向量。对于词表中的每个单词,我们都有它在每个文档中出现的次数。也就是说,整个数据集中的每个唯一单词都对应于这中数值表示的一个特征。要注意,原始字符串中的单词顺序与词袋特征表示完全无关。
将词袋应用于玩具数据集:
词袋表示是在CountVectorizer中实现的,它是一个变换器(transformer)。我们首先将它应用于包含两个样本的玩具数据集,来看一下它的工作原理:
python
bards_words=['the fool doth think he is wise','but then wise man knows himself to be a fool']
我们导入CountVectorizer并将其实例化,然后对玩具数据进行拟合,如下所示:
python
bards_words=['the fool doth think he is wise','but then wise man knows himself to be a fool']
vect=CountVectorizer()
vect.fit(bards_words)
拟合CountVectorizer包括训练数据的分词与词表的构建,我们可以通过vocabulary_属性来访问词表:
python
print('词表大小:{}'.format(len(vect.vocabulary_)))
print('词表:{}'.format(vect.vocabulary_))
词表一个包含14个单词,从"be"到"wise"。
我们可以调用transform方法来创建训练数据的词袋表示:
python
bag_of_words=vect.transform(bards_words)
print('词袋表示:{}'.format(repr(bag_of_words)))
词袋表示保存在一个SciPy系数矩阵中,这种数据格式只保存非零元素。这个矩阵的形状为2*13,每行对应于两个数据点之一,每个特征对应于词表中的一个单词。这里使用稀疏矩阵,是因为大多数文档斗志包含次表中的一小部分单词,也就是说特征数组的大部分元素都为0,因为保存0的代价很高,也浪费内存。要想查看稀疏矩阵的实际内容,可以使用toarray方法将其转换为"密集的"NumPy数组(保存所有0元素):
但是这里之所以可行,是因为我们使用的是仅包含13个单词的小型数据集。对于任何真实数据集来说,这将会导致内存报错。
python
print('矩阵实际数组内容:{}'.format(bag_of_words.toarray()))
我们可以看到,每个单词的计数都是0或1.bards_words中的两个字符串都没有包含相同的单词。
我们来看一下如何阅读这些特征向量:第一个字符串被视为第一行,对于词表中第一个单词"be",出现0次,第二个词0次,第三个次1次,以此类推。
访问词表的另一种方法是使用向量器的get_funture_name方法,它将返回一个列表,每个元素对应一个特征:
python
feature_name=vect.get_feature_names_out()
print('特征数量:{}'.format(len(feature_name)))
print('前20个特征:{}'.format(feature_name[:20]))