用scikit-learn的三种词袋(BoW)生成方法为机器学习任务准备文本数据

来源:互联网 发布:淘宝直营店是什么意思 编辑:程序博客网 时间:2024/06/15 04:46

用scikit-learn的三种词袋(BoW)生成方法为机器学习任务准备文本数据

本文为翻译博客,详见: 原文

在使用文本数据建立预测模型之前,需要做特别的数据预处理工作。

文本必须先进行分词(tokenization)操作,然后进行特征提取,即向量化(vectorization)操作,将分词后的词编码成整形或浮点数据作为机器学习算法的输入。

scikit-learn库提供了易用的工具来对文本数据做分词和特征提取。

学完这个教程后,你将会知道:

  • 如何使用CountVectorizer 将文本转化成词统计向量
  • 如何使用TfidfVectorizer 将文本转化成词频向量
  • 如何使用HashingVectorizer 将文本转化成唯一数字向量

Bag-of-Words 模型

在进行模型训练之前,我们需要将文本转化成数字。如果我们对文档进行分类,那么每一个文档都是一个输入,并且有一个对应的输出类别。因为算法都是将数字向量作为输入,所以我们需要将文档转换成指定长度的数字向量。

一种简单有效的模型叫:Bag-of-Words(BoW)模型。这个模型之所以简单,是因为它将单词之间的顺序关系全部丢弃,只关注文档中单词出现的次数。该方法为每个单词分配一个唯一编号,这样一个文档就能够被编码成与已知词汇数量相同长度的向量。向量中每一个位置上的值就是其编号对应单词在文档中出现的次数。

BoW模型有许多优化版本,优化方向包括:1)对词义的更好阐述 2)对向量中每个词的编码方式

scikit-learn库中提供了三种可用的解决方案,下面作简要介绍。

用CountVectorizer统计词频

CountVectorier 不仅提供了一个简单的方法为一系列文本文件进行分词操作,从而用这些已有的词建立一个词汇表,同时还能用这个词汇表对新文档编码。

使用步骤如下:

  1. 创建CountVectorizer 类的一个实例
  2. 调用fit() 函数从一个或多个文件中学习一个词汇表
  3. 调用transform() 函数,将一个文件编码成一个向量

返回一个与词汇表同长的向量,向量中每个位置对应词汇表该位置上的词在当前文件中出现的次数。因为向量中包含很多的0,所以很稀疏,Python在scipy.sparse 包中提供了一个有效的方法处理稀疏向量。

上述步骤3中的transform() 函数返回一个稀疏向量,为了直观理解,我们可以用toarray() 将稀疏向量转化成numpy数组。

下面是用CountVectorizer 进行分词、建立词汇表、编码一个文件的实例。

导入CountVectorizer 库和文件:

from sklearn.feature_extraction.text import CountVectorizertext = ["The quick brown fox jumped over the lazy dog."]

建立词汇表:

# 创建transformvectorizer = CountVectorizer()# 分词并建立词汇表vectorizer.fit(text)# 结果输出print vectorizer.vocabulary_

输出词汇表为:

{u'brown': 0, u'lazy': 4, u'jumped': 3, u'over': 5, u'fox': 2, u'dog': 1, u'quick': 6, u'the': 7}

按照词汇表,对文件进行编码:

vector = vectorizer.transform(text)# 输出编码后的向量信息print vector.shapeprint type(vector)print vector.toarray()

输出为:

(1, 8)<class 'scipy.sparse.csr.csr_matrix'>[[1 1 1 1 1 1 1 2]]

需要重点指出的是,相同的方法可以对包含词汇表之外词汇的文件进行编码,这些词汇表中不存在的词将在返回的向量中被忽略,举个例子:

# 对另一个文件进行编码text2 = ["the puppy"]vector = vectorizer.transform(text2)print vector.toarray()

输出为:

[[0 0 0 0 0 0 0 1]]

只有词汇表中存在的第七个词”the”出现一次被编码了,词汇表中不存在的“puppy”直接被忽略。

用TfidfVectorizer进行词频统计

词数统计是一个好的着手点,但是很基础。简单的词数统计存在一个问题,比如:一些像“the”这样的单词可能出现很多次,虽然在编码的向量中他们对应的数值很大,但并没有什么意义。

一种解决方案是计算词频,TF-IDF 是眼下最流行的词频计算方法,它是“Term Frequency - Inverse Documentation Frequency” 首字母的缩写。

  • Term Frequency :指在一个文件中一个指定单词出现的次数
  • Inverse Document Frequency :它降低在多个文件中均出现的单词的重要性

本文不作数学计算解释,可参考weki 。TF-IDF是词频得分,它更偏重于某个文件中新颖的单词,比如:在一个文件中多次出现,但在其他文件很少出现的单词。

TfidfVectorizer 可以对文件进行分词、学习词汇表、计算词频得分,使你能够编码新文件。如果你已经学习了一个CountVectorizer ,你可以只需用TfidfTransformer 计算inverse document frequency ,然后编码新文件。

TfidfVectorizer的使用步骤和CountVectorizer一样:创建、fit操作、transform操作。

下面是用TfidfVectorizer对3个小文件学习词汇表和inverse document frequencies,然后编码其中一篇文件的例子:

先分词并建立词汇表,计算idf得分。

from sklearn.feature_extraction.text import TfidfVectorizer# 文件列表text = ["The quick brown fox jumped over the lazy dog.",        "The dog.",        "The fox"]# 建立transformvectorizer = TfidfVectorizer()# 分词,建立词汇表vectorizer.fit(text)# 输出结果print vectorizer.vocabulary_print vectorizer.idf_

输出结果:

{u'brown': 0, u'lazy': 4, u'jumped': 3, u'over': 5, u'fox': 2, u'dog': 1, u'quick': 6, u'the': 7}[ 1.69314718  1.28768207  1.28768207  1.69314718  1.69314718  1.69314718  1.69314718  1.        ]

编码其中一个文件:

# 编码文件vector = vectorizer.transform([text[0]])# 输出编码结果print vector.shapeprint vector.toarray()

输出结果:

(1, 8)[[ 0.36388646  0.27674503  0.27674503  0.36388646  0.36388646  0.36388646   0.36388646  0.42983441]]

这些得分向量被规范化到0-1之间,可以直接作为机器学习任务的输入。

用HashingVectorizer进行Hashing操作

词数和词频一般很有用,但这些方法有个限制——词汇表可能很大。

如果词汇表很大,那么就需要大的向量来编码文件,对存储造成压力,进而拖慢算法。

一个聪明的解决方案是对单词进行单向哈希操作,将它们转换成整数。聪明的地方在于不需要词汇表,你可以选择一个指定任意长度的向量。该方法的缺点是哈希是一个单向函数,所以不能将编码好的词变回原来的词(在大多数监督学习任务中没啥影响)。

HashingVectorizer 类步骤是先对词进行hash操作,然后对指定文件进行分词和编码。

下面的例子是使用HashVectorizer对单个文件进行操作。选择一个任意定长为20的向量,这对应了哈希函数的范围,选择的哈希长度太小(比如20)可能导致哈希冲突,这需要我们根据估计的词汇长度计算冲突的可能性,并选择合适的哈希长度。

注意这种向量化方法不需要在训练文件数据上调用fit函数,在实例化之后,它可以直接被用来编码文件。

from sklearn.feature_extraction.text import HashingVectorizer# 文件列表text = ["The quick brown fox jumped over the lazy dog."]# 创建transformvectorizer = HashingVectorizer(n_features=20)# 编码文件vector = vectorizer.transform(text)# 输出编码后的结果print vector.shapeprint vector.toarray()

运行例子,将样本文件编码成一个有20个元素的稀疏数组。

文件编码向量中的值对应于将词数规范化到-1到1之间所得结果,也可以通过改变默认值修改范围。

上例所得结果如下:

(1, 20)[[ 0.          0.          0.          0.          0.          0.33333333   0.         -0.33333333  0.33333333  0.          0.          0.33333333   0.          0.          0.         -0.33333333  0.          0.  -0.66666667  0.        ]]

总结

这个教程讲述了如何用scikit-learn为机器学习任务准备文本数据(文件预处理),只讲了简单的实现方式,有待深挖。

注:该教程不适用中文

原创粉丝点击