当前位置:技术分享 > 技术参考 > 正文

如何使用 scikit-learn 为机器学习准备文本数据2018-02-08 13:56:18 | 编辑:hely | 查看: | 评论:0

文本数据需要特殊处理,然后才能开始将其用于预测建模。我们需要解析文本,以删除被称为标记化的单词。然后,这些词还需要被编码为整型或浮点型,以用作机器学习算法的输入,这一过程称为特征提取(或矢量化)。
文本数据需要特殊处理,然后才能开始将其用于预测建模。

我们需要解析文本,以删除被称为标记化的单词。然后,这些词还需要被编码为整型或浮点型,以用作机器学习算法的输入,这一过程称为特征提取(或矢量化)。

scikit-learn 库提供易于使用的工具来对文本数据进行标记和特征提取。

在本教程中,您可以学到如何使用 scikit-learn 为 Python 中的预测建模准备文本数据。

完成本教程后,您可以学到:

  • 如何使用 CountVectorizer 将文本转换为文字计数向量。
  • 如何使用 TfidfVectorizer 将文本转换为词频向量。
  • 如何使用 HashingVectorizer 将文本转换为唯一的整数。

让我们开始吧。

如何使用 scikit-learn 为机器学习准备文本数据 Martin Kelly 的照片,部分权利保留。

 

词袋模型( Bag-of-Words Model )

 

使用机器学习算法时,我们不能直接使用文本。

相反,我们需要将文本转换为数字。

我们可能想对文档进行分类,每一类文档都是“输入”,而类别标签是我们预测算法的“输出”。算法将数字向量作为输入,因此我们需要将文档转换为固定长度的数字向量。

在机器学习中,Bag-of-Words 模型(BoW)是一种简单而有效的让计算机“理解”文本文档的模型。

这个模型非常简单,它移除了单词的诸如词序、语法等顺序信息,只关注文档中该单词的出现情况。

上面这一步可以通过为每个单词分配一个唯一的编码来完成。我们所看到的任何文档都可以被编码为一个固定长度的矢量,其长度为文档中全部已知单词的词汇量。矢量中每个位置的值可以用编码文档中每个单词的出现个数或频率填充。

在词袋模型中,我们只关心编码方案,而编码方案描述了文档中出现了什么单词,以及这些单词在编码文档中出现的频率,而没有任何关于顺序的信息。

有很多方法来扩展这个简单的方法,例如,我们可以想办法更好地解释一个单词的含义,或是更好地规定向量中每个单词的编码方式。

scikit-learn 库提供了3种不同的方案供我们使用,下面简要地介绍一下。

 

使用 CountVectorizer 计算字数

 

CountVectorizer 提供了一个简单的方法,既可以标记文本文档的集合, 也可以生成每个已知单词的索引, 还可以使用这一套索引对新文档进行编码。

下面是一种使用方法:

  1. 实例化一个 CountVectorizer 类。
  2. 调用 fit() 函数以从一个或多个文档中建立索引。
  3. 根据需要在一个或多个文档中调用 transform() 函数,将每个文档编码为一个向量。

最终会返回一个已编码的向量, 其长度为索引的个数,该向量还携带有文档中每个单词出现的次数信息。

包含很多零的向量被称为稀疏向量。Python 的 scipy.sparse 包中提供了一种处理稀疏向量的有效方法。

调用 transform() 返回的向量是稀疏向量,这里可以通过调用 toarray() 函数将它们转换回 numpy 数组以便查看并更好地理解这个过程。

下面是使用 CountVectorizer 标记,构建索引,然后编码文档的示例。

from sklearn.feature_extraction.text import CountVectorizer
# 下面是一个文本文档的列表
text = ["The quick brown fox jumped over the lazy dog."]
# 实例化 CountVectorizer 类
vectorizer = CountVectorizer()
# 标记并建立索引
vectorizer.fit(text)
# 查看结果
print(vectorizer.vocabulary_)
# 编码文档
vector = vectorizer.transform(text)
# 查看编码后的向量
print(vector.shape)
print(type(vector))
print(vector.toarray())

在上面的代码中,如下一行是用来帮助我们访问这个索引并查看标记的结果的:

print(vectorizer.vocabulary_)

我们可以看到,所有的单词默认都是小写字母,标点符号也被忽略了。标记的许多方面都是可以配置的,您可以查看API文档中的所有选项。

运行示例之后,首先输出的是索引,然后输出的是编码文档的结构。我们可以看到索引中有8个词,因此编码向量长度为 8。

从接下来输出的类型中可以看出,编码向量是一个稀疏向量。而最后的输出是编码向量的数组版本,其表达的含义是,索引值为 7 的单词出现次数为 2,其余单词出现次数为 1。

{'dog': 1, 'fox': 2, 'over': 5, 'brown': 0, 'quick': 6, 'the': 7, 'lazy': 4, 'jumped': 3}
(1, 8)
[[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]]

这之后,编码向量就可以直接使用到机器学习算法中了。

 

使用 TfidfVectorizer 统计词频

 

单词计数是一个非常好、非常简单的起点。

不过,简单计数也存在不足。例如,简单计数中像“ the ” 这样的词会出现很多次,在编码的向量中,这样的单词计数会很大,却没有太大意义。

除了统计个数外的另一种方法是计算词频,到目前为止,最流行的方法是TF-IDF。TF-IDF 是 Term Frequency - Inverse Document Frequency 的首字母缩写词,它是分配给每个单词的结果分数的组成部分。

  • 词频(Term Frequency):该值表示给定单词在这份文档中出现的频率。
  • 逆向文件频率(Inverse Document Frequency):该值用于降低其他文档中普遍出现的单词的最终评分。

没有进入数学,TF-IDF是词频分数,可以突出个性化的单词,例如在只在这份文档中频繁出现,但其他文档中较少出现的单词。

TfidfVectorizer 将标记文件、建立索引、求出逆文档频率权重,并允许您编码新的文件。或者,如果您已经有了一个已经训练过的 CountVectorizer,您可以将其与 TfidfTransformer 一起使用,以计算逆文档频率并开始编码文档。

TfidfVectorizer 的实例化、拟合和转换方法和 CountVectorizer 类似。

下面的示例展示了如何是使用 TfidfVectorizer 训练 3 个小文档的索引和逆文档频率,并编码其中一个文档。

from sklearn.feature_extraction.text import TfidfVectorizer
# 下面是一个文本文档的列表
text = ["The quick brown fox jumped over the lazy dog.",
"The dog.",
"The fox"]
# 实例化过程
vectorizer = TfidfVectorizer()
# 标记并建立索引
vectorizer.fit(text)
# 输出以查看结果
print(vectorizer.vocabulary_)
print(vectorizer.idf_)
# 编码文档
vector = vectorizer.transform(text0)
# 查看编码后的向量
print(vector.shape)
print(vector.toarray())

从文档中学习 8 个单词的得到索引,并且每个单词在输出向量中被分配唯一的整数索引值。

计算每个单词的逆文档频率,将最低分数 1.0 分配给最常见的词:索引值为 7 的“the”

最后,第一个文档被编码为一个8元素的稀疏数组,我们可以从结果中的其他单词中查看诸如“the”,“fox”和“dog”等不同值的最终评分。

{'fox': 2, 'lazy': 4, 'dog': 1, 'quick': 6, 'the': 7, 'over': 5, 'brown': 0, 'jumped': 3}
[ 1.69314718 1.28768207 1.28768207 1.69314718 1.69314718 1.69314718
1.69314718 1. ]
(1, 8)
[[ 0.36388646 0.27674503 0.27674503 0.36388646 0.36388646 0.36388646
0.36388646 0.42983441]]

将评分标准化为 0 到 1 之间的值。在这之后,编码过的文档向量即可直接用于大多数机器学习算法中了。

 

使用 HashingVectorizer 建立散列表

 

统计个数和计算频率两种方法虽然非常实用,但是也由其局限性导致词汇量可能变得非常大。

词汇量过大又将导致需要非常大的矢量来编码文档,从而对内存产生很大的要求,同时拖慢算法的速度。

这里有一个巧妙的解决方法,即建立单词的单向散列表,进而将每个单词转换为整数。这么做的优点是不需要专门建立索引,并且你可以将定长向量的长度定为任意值。缺点是散列是一个单向函数,所以没有办法将编码转换回单词(不过这一步对于许多监督学习任务可能并不重要)。

HashingVectorizer 类实现了此方法,使其可用于一致地散列单词,然后根据需要标记和编码文件。

下面的示例演示了用于编码单个文档的 HashingVectorizer。

选择长度为 20 的定长向量。这个长度对应于散列函数的范围,不过例如 20 这样的小值可能导致散列表冲突。回想计算机科学课里相关的知识,这里可以使用试探法,根据估计的词汇量的大小和碰撞概率来挑选哈希长度。

请注意,这个矢量化器不需要调用 fit() 函数来训练数据文档。实例化之后,它可以直接用于编码文档。

from sklearn.feature_extraction.text import HashingVectorizer
# 下面是一个文本文档的列表
text = ["The quick brown fox jumped over the lazy dog."]
# 实例化 HashingVectorizer
vectorizer = HashingVectorizer(n_features=20)
# 编码文档
vector = vectorizer.transform(text)
# 查看编码后的向量
print(vector.shape)
print(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.        ]]
 

进一步探究

 

如果您想进行深入研究,下面提供更多有关该主题的资源。

自然语言处理

sciki-learn

API

 

概要

 

在本教程中,你可以了解如何使用scikit-learn为机器学习准备文本文档。

这些例子只是抓住了表面,但是,这些类有很多配置细节影响着文档的标记,这些都是值得深究的。

 

翻译人:Bay,原文作者:Jason Brownlee

原文链接:https://machinelearningmastery.com/prepare-news-articles-text-summarization/


上一篇:一个Spark缓存的使用示例 HBase跨版本数据迁移总结下一篇:

公众平台

搜索"raincent"或扫描下面的二维码