NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

如何使用 Scikit-learn 实现用于机器学习的文本数据准备

  • 2017-10-31
  • 本文字数:4004 字

    阅读完需:约 13 分钟

在使用文本数据来搭建预测模型前,都需要特殊的准备工作。

文本首先要通过解析来提取单词,这一过程称为词条化。然后单词需要编码为整数或浮点值,作为机器学习算法的输入,称为特征提取(或量化)。

scikit-learn 提供了简单的工具帮助我们对你的文本数据进行词条化和特征提取。

在这篇文章中,你会学到在 Python 中如何使用 scikit-learn 实现用于机器学习的文本数据准备。

在读完这篇文章后,你会了解到:

  • 如何使用 CountVectorizer 将文本的转化成单词频数向量。
  • 如何使用 TfidfVectorizer 提取文本的单词权重向量。
  • 如何使用 HashingVectorizer 将文本映射到特征索引。

让我们开始吧。

“词袋(Bag-of-words)”模型

在使用机器学习算法时,我们不能直接用文本进行运算。相反,我们需要将文本转换成数字。

我们想对文档进行分类时,每个文档作为“输入”,文档的类别标签是我们预测算法的“输出”。算法只能接受数字向量作为输入,所以需要将文档转换成固定长度的数字向量。

机器学习领域有一个简单且有效的模型,适用于文本文档,叫做“词袋”(Bag-of-Words)模型,简称为 BOW。

该模型的简单之处在于,它舍弃了单词中的所有顺序信息,并主要关注文档中单词的出现频率。

这一点可以通过分配给每个单词一个唯一的数字来实现。这样一来,我们看到的任何文档都可以编码成一个固定长度的向量,长度为已知单词所构成的词汇表的长度。该向量中每个位置的值是编码文档中的每个单词出现的次数或频率。

这就是“词袋”模型,我们只关心编码方法,能表示哪些词语在文档中出现了,或者他们在编码文档中出现的频率,而不考虑任何关于顺序的信息。

这个简单的方法有很多种扩展,既可以更好地解释“单词”的含义,也可以定义向量中每个单词的编码方式。

scikit-learn 提供了 3 种可供我们使用的不同方法,我们将简要地看一下每种方法。

CountVectorizer——量化单词数量

CountVectorizer 提供了一种简单的方法,不仅可以将文本文档的数据集转化成词条并建立一个已知单词的词汇表,而且还可以用该词汇表对新文本进行编码。

使用方法如下:

  1. 创建 CountVectorizer 类的一个实例。
  2. 调用 fit() 函数,通过学习从一个或多个文档中得出一个词汇表。
  3. 对一或多个文档应用 transform() 函数,将每个文档编码成一个向量。

编码得到的向量能够返回整个词汇表的长度,以及每个单词在该文档中出现的次数。

由于这些向量含有许多零值,所以我们称之为稀疏的。Python 在 scipy.sparse 库中提供了一种处理这类稀疏向量的有效方法。

调用 transform() 所返回的向量是稀疏向量,你可以将它们转换为 numpy 数组,看起来更直观也更好理解,这一步可以通过调用 toarray() 函数完成。

下面是一个使用 CountVectorizer 来词条化、构造词汇表,以及编码文档的示例。

复制代码
from sklearn.feature_extraction.text import CountVectorizer
# 文本文档列表
text = ["The quick brown fox jumped over the lazy dog."]
# 构造变换函数
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。

可以看出,编码向量是一个稀疏矩阵。最后,我们可以看到以数组形式出现的编码向量,显示出每个单词的出现次数为 1,除了索引号为 7 的单词出现次数为 2。

复制代码
{'dog': 1, 'fox': 2, 'over': 5, 'brown': 0, 'quick': 6, 'the': 7, 'lazy': 4, 'jumped': 3}
(1, 8)
<class 'scipy.sparse.csr.csr_matrix'>
[[1 1 1 1 1 1 1 2]]
{1}

重要的是,该量化方法可以用于含有词汇表中没有出现的单词的文档。这些单词会被忽略掉,然后在得到的向量结果中不会给出出现次数。

下面是一个使用上述的词条化工具对文档进行编码的示例,该文档中含有一个词汇表中的词,以及一个不在词汇表中的词。

复制代码
# 编码其他文档
text2 = ["the puppy"]
vector = vectorizer.transform(text2)
print(vector.toarray())

运行示例,显示出编码稀疏向量的矩阵形式,可以看出词汇表中的单词出现了 1 次,而没在词汇表中的单词完全被忽略了。

[[0 0 0 0 0 0 0 1]]编码的向量可以直接用于机器学习算法。

TfidfVectorizer——计算单词权重

统计单词出现次数是一个很好的切入点,但也是很基础的特征。

简单的次数统计的一个问题在于,有些单词,例如“the”会出现很多次,它们的统计数量对于编码向量没有太大意义。

一个替代方法是统计单词权重,目前最流行的方法是 TF-IDF 。这是一个缩写词,代表“词频 - 逆文档频率”(Term Frequency–Inverse Document Frequency),代表一个词对于一个文档的重要程度。

词频(Term Frequency):指的是某一个给定的词语在一篇文档中出现的次数。
逆文档频率(Inverse Document Frequency):单词在文档中出现的频率越高,IDF 值越低。

撇开数学不说,TF-IDF 给出的是单词权重,会把更有意思的单词标注出来,例如仅在某篇文档中频率很高但不会在所有文档中都频繁出现的词。

TfidfVectorizer 可以词条化文档,学习词汇表以及逆文档频率权重,并且可以编码新文档。或者,如果你已经用 CountVectorizer 学习得到了向量,你可以对它使用 Tfidftransformer 函数,计算逆文档频率并且开始编码文件。

同样的,创建(create)、拟合(fit)以及变换(transform)函数的调用都与 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([text[0]])
# 总结编码文档
print(vector.shape)
print(vector.toarray())

上例中,我们从文档中学到了含有 8 个单词的词汇表,在输出向量中,每个单词都分配了一个唯一的整数索引。

我们计算了词汇表中每个单词的逆文档频率,给观测到的最常出现的单词“the”(索引号为 7)分配了最低的分数 1.0。

最终,第一个文档被编码成一个 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)可能会导致哈希碰撞。在之前的计算机科学课程中,我们介绍过一些启发式算法,可以根据估计的词汇量来选择哈希长度和碰撞概率。

要注意这种量化方法不要求调用函数来对训练数据文件进行拟合。相反,在实例化之后,它可以直接用于编码文档。

复制代码
from sklearn.feature_extraction.text import HashingVectorizer
# 文本文档列表
text = ["The quick brown fox jumped over the lazy dog."]
# 创建变换函数
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. ]]

深度阅读

这一节我们为大家提供了一些关于这篇文章的深度阅读材料。

自然语言处理

scikit-learn

类 API

总结

在这篇教程中,你会学习到如何用 scikit-learn 来准备用于机器学习的文本数据。

我们只是在这些例子中接触了皮毛,我想强调的是这些类有许多设置细节会影响文档词条化的结果,值得我们继续探究。

查看英文原文: How to Prepare Text Data for Machine Learning with scikit-learn

感谢薛命灯对本文的审校。

公众号推荐:

跳进 AI 的奇妙世界,一起探索未来工作的新风貌!想要深入了解 AI 如何成为产业创新的新引擎?好奇哪些城市正成为 AI 人才的新磁场?《中国生成式 AI 开发者洞察 2024》由 InfoQ 研究中心精心打造,为你深度解锁生成式 AI 领域的最新开发者动态。无论你是资深研发者,还是对生成式 AI 充满好奇的新手,这份报告都是你不可错过的知识宝典。欢迎大家扫码关注「AI前线」公众号,回复「开发者洞察」领取。

2017-10-31 17:483622
用户头像

发布了 52 篇内容, 共 28.2 次阅读, 收获喜欢 72 次。

关注

评论

发布
暂无评论
发现更多内容

第五周 技术选型 作业一

应鹏

极客大学架构师训练营 课程作业

架构师训练营第 5 周:技术选型(一)

子青

架构师训练营第五周作业

Shunyi

极客大学架构师训练营

食堂就餐卡系统设计-week1

Mr_No爱学习

食堂就餐卡系统

Xuenqlve

架构师训练营第一周作业-周总结

张浩

【架构师训练营第 1 期 05 周】 作业

Bear

极客大学架构师训练营

架构方法-学习总结笔记

Xuenqlve

week1作业

幸福小子

架构师训练营第 1 期 - 第 5 周 - 学习总结

wgl

极客大学架构师训练营

第五周 作业1

Yangjing

极客大学架构师训练营

5.2分布式缓存架构:常见的缓存实现形式

张荣召

第五周 技术选型(1)学习总结

蓝黑

极客大学架构师训练营

作业

张荣召

AirPods过河,苹果拆桥:被“钞能力”征服的Beats何以至此?

脑极体

5.1分布式缓存架构:架构原理与注意事项

张荣召

架构师训练营 1 期第 5 周:技术选型(一) - 作业

灵霄

极客大学架构师训练营

架构师训练营第5周作业

wanlinwang

极客大学架构师训练营

第一周作业

孤星

架构师训练营第 1 期 -- 第五周学习总结

发酵的死神

极客大学架构师训练营

架构师训练营第五周作业

xs-geek

第五周总结

hash一致性算法

橘子皮嚼着不脆

Week_05 作业

golangboy

极客大学架构师训练营

第 01 周——食堂就餐卡系统设计

Airship

极客大学架构师训练营

架构师训练营第五周 技术选型缓存、消息队列、一致性 hash

郎哲158

学习 极客大学架构师训练营

第 1 周 架构方法 学习总结

心在那片海

第1周作业-学习总结

jingx

第五周作业

fmouse

极客大学架构师训练营

架构师训练营二期 1周总结

月下独酌

极客大学架构师训练营

第一周10/25

张冬冬

总结

如何使用Scikit-learn实现用于机器学习的文本数据准备_语言 & 开发_Jason Brownlee_InfoQ精选文章