写点什么

如何使用 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

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

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

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

关注

评论

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

如何使用免适配云鹰模组实现多网可切?——实践类

阿里云AIoT

安全 物联网 物联网安全 技术标签

Python报错:ModuleNotFoundError: No module named 'xxx'

Geek_7ubdnf

Python

数维图可视化编辑器超10项功能升级,您的需求就在其中

2D3D前端可视化开发

数据可视化 数字孪生 三维可视化 web3d web组态软件

互联网医疗月度观察:规范化、合法化的网络售药新时代到来

易观分析

互联网医疗

Spring Cloud Alibaba 2022.0.0.0 版本发布啦!

阿里巴巴中间件

阿里云 云原生 Spring Cloud Aliababa

【玩转 Cloud Studio】 Cloud Studio的入门教程

Geek_7ubdnf

studio

如何使用企业账户进行协作?

Towify

智能图像处理:基于边缘去除和迭代式内容矫正的复杂文档图像校正

合合技术团队

图像处理 图像预处理 人工智能’

conda安装报错:PermissionError [Errno 13] Permission denied

Geek_7ubdnf

Python

Linux安装与卸载软件

Geek_7ubdnf

Linux

Vue实现登录功能

Geek_7ubdnf

Vue

微信小程序实验案例:简易成语小词典

TiAmo

小程序 微信小程序

Dubbo 正式支持 Spring 6 & Spring Boot 3

阿里巴巴中间件

spring 阿里云 云原生 Spring Boot dubbo

Python报错:ImportError cannot import name 'imresize'

Geek_7ubdnf

Python

还在自建MQTT物联网平台?快来试试开源MQTT托管型物联网平台——实践类

阿里云AIoT

安全 物联网 物联网安全 技术标签

再获殊荣!图数据库 NebulaGraph 获得 ITPUB 2022 创新产品奖

最新动态

电脑音视频暂停再继续,声音突然变大

Geek_7ubdnf

windows

2022年IAA行业品类年度表现总结

易观分析

视频 IAA

35张图,直观理解Stable Diffusion

OneFlow

人工智能 深度学习 Stable Diffusion

Spring+Vue增删改查实例

Geek_7ubdnf

Vue springboot

浅谈服务接口的高可用设计

京东科技开发者

负载均衡 接口 后端 混沌工程 企业号 1 月 PK 榜

mmdetection训练数据遇到的问题

Geek_7ubdnf

Python 机器学习

粒子滤波 PF(Particle filter)算法

Geek_7ubdnf

机器学习

中移链合约常用开发介绍 (二)多索引表的使用

BSN研习社

10分钟玩转阿里云物联网平台设备接入、管理、运维——实践类

阿里云AIoT

安全 物联网 物联网安全 技术标签

Spring获取Bean的9种方式

小小怪下士

Java spring 程序员 springboot

pip安装报错:UnicodeDecodeError 'utf-8' codec can't decode byte 0xc3 in position 4

Geek_7ubdnf

Python

如何使用滑块实现切换图片功能?

Towify

Win10桌面图标显示问题

Geek_7ubdnf

windows

Serverless 奇点已来,下一个十年将驶向何方?

阿里巴巴中间件

阿里云 Serverless 云原生

2022总结,强风吹拂

程思扬

总结 年终总结 经验分享、

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