[Scikit-learn教程] 03.01 文本处理:特征提取

1,561 阅读7分钟

欢迎访问集智主站:集智,通向智能时代的引擎



在使用机器学习方法解决实际问题的时候,往往我们所得到的并不是纯粹的数据文件,它们有可能是图片、文本、视频等包含有效信息的复杂数据,这时候就需要我们从这些数据中提取数字特征,以便于我们之后的分析和训练过程。本节将介绍Scikit-learn中可用于文本分类的一些功能,它们包括

  • 从硬盘读取文本内容和分类信息
  • 从文本信息中提取可用于机器学习过程的特征向量

关于具体的使用文本特征进行模型训练、评估和优化过程,我们将在下一节的文章中进行讨论。

获取数据文件

首先来了解我们所要用到的数据集。本文所用到的数据集被称为“20种新闻组”,是一个经常被用来进行机器学习和自然语言处理的数据集。它包含20种新闻类别的近20000篇新闻,其官方简介可参见 http://qwone.com/~jason/20Newsgroups/ 。

我们有多种方式来获取这个数据集,一种简单的方法是使用sclearn的自带函数sklearn.datasets.fetch_20newsgroups。这个函数能自动从网上下载“20种新闻组”的数据并进行读取,示例如下。为了节省计算和处理的时间,我们仅选取20种分类中的四种进行之后的分析工作。

注意:由于数据包体积较大且数据源地址在国外,下述示例运行将比较缓慢,因此不提供运行。

from sklearn.datasets import fetch_20newsgroups
# 选取需要下载的新闻分类
categories = ["alt.atheism", "soc.religion.christian",
              "comp.graphics", "sci.med"]
# 下载并获取训练数据
twenty_train = fetch_20newsgroups(subset="train",
    categories=categories, shuffle=True, random_state=42)
# 显示训练数据的分类
twenty_train.target_names

当然,我们更常用的方法是直接从网络下载我们所需要的数据。我们可以用Python所提供的urllib库来完成数据包的下载工作,并解压。从网络下载文件可以使用urllib.request.urlretrieve这个函数。通常,我们下载到的数据包都是压缩文件,这时候我们可以使用tarfile这个库来完成,如下面的例子所示。

# 从网络下载数据包
from urllib import request
request.urlretrieve("http://jizhi-10061919.cos.myqcloud.com/sklearn/20news-bydate.tar.gz", "data.tar.gz")
# 解压下载的数据包
import tarfile
tar = tarfile.open("data.tar.gz", "r:gz")
tar.extractall()
tar.close()
# 选取需要下载的新闻分类
categories = ['alt.atheism','soc.religion.christian',
              'comp.graphics', 'sci.med']
# 从硬盘获取训练数据
from sklearn.datasets import load_files
twenty_train = load_files('20news-bydate/20news-bydate-train',
        categories=categories,
        load_content = True,
        encoding='latin1',
        decode_error='strict',
        shuffle=True,random_state=42)
# 显示训练数据的分类
print(twenty_train.target_names)

如上所示,数据包下载完成后,我们可以使用sklearn.datasets.load_files来获取数据。我们同样只采集四种分类的文本数据用于分析,并检查所读取文本数据的一些信息以确定数据已被读取。

提取文本特征

无论是什么机器学习方法,都只能针对向量特征(也就是一系列的数字组合)进行分析,因此在读取文本之后,我们要将文本转化为数字化的特征向量。

词袋模型(Bags of words)

提取文本特征最常用的一种方法就是使用词袋模型,其具体表述如下: 为训练集文档中所有出现的词语给予一个固定的数字ID(也就是为所有的词语建立一个由整数进行索引的字典) 对于每一篇文档#i,计算每个词语w出现的次数并将其记录在X[i, j]中作为特征#j的值,j代表词语w在字典中的位置

词袋模型假设每个数据集中存在n_features个不同的单词,而这个数字通常会超过100000。这会带来什么问题呢?考虑一下,如果采样数(也就是文档的个数)为10000,特征以32位浮点数存储,则总的文本特征需要10000\times100000\times4\textrm{bytes}=4\textrm{GB},而这4GB必须全部存储在计算机内存中,这对于现在的计算机而言几乎是不可能的。

幸运的是,上述方法得到的特征数据中大部分特征数值都会是零值,这是因为每篇文档实际上仅使用了几百个不同的词汇。由于这个原因,我们将词袋模型称之为高维度稀疏数据集。我们可以通过仅存储非零特征来大幅节省内存使用量。

scipy.sparse模型正是处理这个过程的一系列数据结构,而它们也得到了scikit-learn的支持。

使用scikit-learn标记文本

一个高效的数据处理模块会包含文本与处理、标记和停词(stopwords,指对句意无影响的虚词,如“的”、“地”等等)过滤等功能,这些功能能够帮助我们将文本数据转换为特征向量,从而建立起数据的特征字典。

CountVectorizer就是一个支持文本中词语计数的函数库,我们可以使用其中的函数来分析文本数据来得到特征向量字典,字典中每一个项目的值代表该词语在全部数据中出现的次数,如下面的例子所示。

from sklearn.feature_extraction.text import CountVectorizer
count_vect = CountVectorizer()
X_train_counts = count_vect.fit_transform(twenty_train.data)
# 打印特征相关信息
print("训练数据共有{0}篇, 词汇计数为{1}个".format(X_train_counts.shape[0], X_train_counts.shape[1]))
# 查看某个词语的计数
count = count_vect.vocabulary_.get(u'algorithm')
print("algorithm的出现次数为{0}".format(count))

从出现次数到频率分析

统计词语的出现次数是个很好的尝试,但这也同样存在一个问题,那就是对于一个词语而言,它在较长篇幅的文章出现的概率往往会比短文章高得多,即便是这两篇文章讨论的是同一个话题,这个现象同样存在。

为了解决这些潜在的差异,我们可以尝试用每个词语在某个文档中出现的次数除以这个文档中总共的词语数目,这样得到的新的特征我们可以称之为tf,也就是词频(Term Frequencies)。

tf基础上的另外一种优化方案是为某些不太重要的词语降低权重,这些词语往往会在很多文档中出现,相对于那些仅在一小部分文档中出现的词语而言,它们对于分类的影响会更细微。

我们把这种词频+权重模型称之为tf-idf,也就是“Term Frequency times Inverse Document Frequency”。下面我们简要介绍它们的数学意义。

tf,即词频,指的是一个词语t_i在某篇文档d_j中中出现的概率,它可以用如下的公式计算:

[math]?$\textrm{tf}_{i,j}=\frac{n_{i,j}}{\sum_kn_{k,j}}?$[/math]

其中n_{i,j}指词语在文件d_j中出现的次数,而[math]$\sum_kn_{k,j}$[/math]指文件d_j中所有词语的出现次数。

idf,即逆向文件频率,指的是一个词语普遍重要性的度量,表示该词语信息量的大小。IDF可以由总文件数目除以包含该词语的文件的数目然后取对数得到:

\textrm{idf}_i=\log \frac {|D|}{| \\{j:t_i\in d_j \\}|}

其中|D|表示数据中的文件总数,| \\{j:t_i\in d_j \\}|表示包含词语t_i的文件数目。

最后则有:

[math]?$\textrm{tfidf}_{i,j}= \textrm{tf}_{i,j}\times \textrm{idf}_i?$[/math]

tftf-idf均可以通过以下的方式得到计算。

from sklearn.feature_extraction.text import TfidfTransformer
# 使用TF-IDF提取文本特征
tf_transformer = TfidfTransformer(use_idf=False).fit(X_train_counts)
X_train_tf = tf_transformer.transform(X_train_counts)
# 查看特征结果
X_train_tf.shape

在上述的代码中,我们首先使用了fit(..)方法来处理原始文本数据然后使用transform(..)方法来将词汇统计数据转换为tf-idf模型。这两部其实可以合并到一起以节省计算过程,我们可以使用如下所示的fit_transform(..)方法来实现这一点。

from sklearn.feature_extraction.text import TfidfTransformer
tfidf_transformer = TfidfTransformer()
X_train_tfidf = tfidf_transformer.fit_transform(X_train_counts)
# 查看特征结果
X_train_tfidf.shape

至此我们就完成了使用tf-idf模型从文本数据提取数据特征的全部过程,我们将在下一节讨论如何使用这些数据特征进行文本分类模型训练、评估和优化过程。


(本篇课程内容来自于Scikit-Learn - Working With Text Data,转载请注明来源。)


推荐阅读

用PaddlePaddle调戏邮件诈骗犯(完结篇)

这评论有毒!——文本分类的一般套路

我做了一个叫“瑟曦”的机器人,可是她动不动就想让格雷果爵士弄死我。