文本预处理:词袋模型与向量化
一般对文本预处理或者叫做特征提取,首先是要分词,分词之后就是向量化,也就是训练词向量(其实就是将词和词频对应起来,做成矩阵向量的形式)。下面我们要讲的就是向量化。
1 词袋模型
讲向量化之前,先讲一下词袋模型(Bag of Words,BoW)。词袋模型假设我们不考虑文本中词与词之间的上下文关系,仅仅考虑所有词的权重,而权重与词在文本中出现的频率有关。
词袋模型首先会进行分词,之后,通过统计每个词在文本中出现的次数就可以得到该文本基于词的特征,再将各个文本的词和对应的词频放在一起,就是我们所说的向量化。向量化之后,一般也会使用TF-IDF进行特征的权重修正,再将特征进行标准化等等一些的特征工程手段,就可以将数据带入机器学习算法中进行分类和聚类了。
总结起来,词袋模型就是三板斧:
- 分词(tokenizing)
- 统计修订词特征值(counting,或者就记住TF-IDF)
- 标准化(normalizing)
当然,词袋模型有很大的局限,仅仅考虑了词频,忽略了上下文关系,丢失一部分语义。但是在大多数时候,如果我们的目的是分类聚类,词袋模型的表现还是很好的。
2 向量化
在词袋模型的统计词频这一步,我们会得到该文本所有词的词频,有了词频,我们就能用词向量来表示该文本了。我们直接用中的类做演示,这个类可以帮我们完成文本的词频统计和向量化。且看代码:
from sklearn.feature_extraction.text import CountVectorizer
vectorizer = CountVectorizer()
corpus = [
'This is the first document.',
'This is the second second document.',
'And the third one.',
'Is this the first document?',
]
print(vectorizer.fit_transform(corpus))
输出如下:个文本的词频已经统计出来了,左边括号里第个数字代表文本的序号,第个数字代表这个词在词表中的序号,注意词的序号是基于所有文档的。第个数字就是这个词的词频了。
(0, 1) 1
(0, 2) 1
(0, 6) 1
(0, 3) 1
(0, 8) 1
(1, 5) 2
(1, 1) 1
(1, 6) 1
(1, 3) 1
(1, 8) 1
(2, 4) 1
(2, 7) 1
(2, 0) 1
(2, 6) 1
(3, 1) 1
(3, 2) 1
(3, 6) 1
(3, 3) 1
(3, 8) 1
这里面有些东西还是需要再详细解释一下的。
我们进一步看看每个文本的词向量和各个特征代表的词:
print(vectorizer.get_feature_names())
print(vectorizer.fit_transform(corpus).toarray())
"""
['and', 'document', 'first', 'is', 'one', 'second', 'the', 'third', 'this']
[[0 1 1 1 0 0 1 0 1]
[0 1 0 1 0 2 1 0 1]
[1 0 0 0 1 0 1 1 0]
[0 1 1 1 0 0 1 0 1]]
"""
我们可以看到一共有个词,也就是说每个文本都被表示成了维的特征向量,每一维的向量依次对应这个个词。另外需要注意一点:英文文本在经过处理的时候会有去除停用词的操作,比如这个单词代表“我”,是英文的停用词,不参与词频的统计。
将文本做了词频统计后,我们通常会通过TF-IDF进行词特征值权重修正,这个下一篇博客再写。
向量化方法很好用,也很直接,但是在有些场景下很难使用。比如分词后的词汇表非常大,达到万以上,此时如果直接使用向量化的方法,将对应的样本的特征矩阵载入内存,内存就有可能爆掉。这种情况我们应该怎么办呢?第一反应自然就是对特征进行降维,Hash Trick就是非常常用的文本特征降维方法。
3 Hash Trick
在特征处理中,经常利用笛卡尔乘积的方法来构造组合特征,这个方法简单,会使特征数量爆炸式增长。比如一个可以取个不同值的类别特征与一个可以取个不同值的类别特征做笛卡尔乘积,就能构造出个组合特征。在大规模文本中,特征的维度对应着分词后词表的大小,所以维度自然而然地爆炸了,这时候就需要降维了。
Hash Trick是一种简单地降维方法,它的目标是把原始的高维特征向量压缩成较低维的特征向量,且尽量不损失原始特征的表达能力。
=====================================================
推荐阅读