深入浅出Python机器学习13——文本数据处理

文本数据的特征提取、中文分词及词袋模型
  • 使用 CountVectorizer 对文本进行特征提取

       之前接触数据的特征大概可以分为两类:一类是用来表示数值的连续特征;另一类是表示样本所在分类的类型特征。而在自然语言处理的领域中,我们会接触到第三类数据类型——文本数据。
       文本数据在计算机中往往被存储为字符串类型(string),在不同场景中,文本数据的长度差异会非常大,这也使得文本数据的处理方式与数值型数据的处理方式完全不同。而文本的处理尤其困难,因为在一个句子当中,中文的词与词之间没有边界,也就是说,中文不像英文那样,在每个词之间有空格作为分界线,这就要求我们在处理中文文本的时候,需要先进行分词处理。例如下面这个例子:
En
       可以看到,这句话明明有13个单词,而程序告诉我们只有11个。可以发现 “ I ” 和 “ a ” 没有统计。因为这两个单词只有一个字母。下面看看中文的情况:
cn
       可以看到,程序无法对中文语句进行分词,它把整句话当作一个词,这是中文与英文不同,中文之间没有分隔符。

  • 使用分词工具对中文文本进行分词

       安装 “ 结巴分词 ”,

 	sudo pip install jieba

jieba
       通过结巴分词,中文句子中插入了空格作为分界线,再用 CountVectozier 对其进行特征抽取,
jieba-words
       经过了分词工具的处理, CountVectorizer 已经可以从中文文本中提取出若干个整型数值,并生成一个字典。
       接下来,我们要用这个字典将文本的特征进行表达出来,以便用于训练模型。

  • 使用词袋模型将文本数据转为数组

       在上面实验中, CountVectorizer 给每个词编码为一个从 0 到 5的整型数。经过这样的处理之后,我们可以使用一个稀疏矩阵(sparse matrix)对这个文本进行表示。
spare matrix
       可以看出,原来的那句话被转化为一个 1 行 3 的稀疏矩阵,类型为 64位整型数值,其中有 3 个元素。
       看看 3 个元素都是啥:
element
       这里显示的是,在这一句话中,我们通过分词工具拆分的 3 个单词在这句话中出现的次数。

       下面换一句话试试,看看发生的变化:
test-jieba
       结巴分词讲句子拆解,然后再使用 CountVettorizer 将这句文本进行转化。
test-result
       同样是 1X3 的矩阵,不过第一个元素变为 0,也就是说 “ 一个男孩 ” 没有出现在句子中。
       上面这种用数组表示一句话中,单词出现次数的方法,被称为 “ 词袋模型 ” (bag-of-words)。这种方法是忽略一个文本的词序和语法,仅仅将它看作一个词的集合。这种方法啊对于自然语言进行了简化,以便于机器可以读取并且进行模型的训练。但是词袋模型也具有一定的局限性,下面继续对文本型数据进行优化处理。

对文本数据进一步进行优化处理
  • 使用 n_Gram 改善词袋模型

       虽然用词袋模型可以简化自然语言,利于机器学习算法建模,但是它的劣势也很明显——由于词袋模型把句子看作单词的简单集合,那么单词出现的顺序就被无视了,这样一来包含同样单词的不同的句子就被判成一样的了。
1、文本数据的特征表达
       句子打乱顺序之后:
2、打乱顺序后的文本特征
       看出两个句子不一样,但是结果是一样的。
       要解决这个问题,我们可以对 CountVevtorizer 中的 ngram_range 参数进行调节。n_Gram 是大词汇连续文本或语音识别中常用的一种语言模型,它是利于上下文相邻的搭配信息来进行文本数据转换的,其中 n 代表一个整型数值,例如 n=2 时,模型称为 bi-Gram,意思是 n-Gram 会对相邻的两个单词进行配对;而 n=3 时,模型称为 tri-Gram,也就是会对 3 个相邻的单词进行配对。
       下面演示如何在 CountVertoize 中调节 n-Gram 函数,来进行词袋模型的优化:
3、调整n-Gram参数后的数据处理结果
       这里,CountVertorizer 的 ngram_range 参数调节为 (2,2),意思是进行组合的单词数量的下限是 2, 上限也是 2.也就是说,我们限制 CountVectorizer 将句子中相邻的两个单词进行组合,如上面所看到的结果。
       再试着改变句子的顺序。
4、调整顺序后的文本数据特征
       在调整了 CountVectorizer 的 ngram_range 参数之后,机器不再认为这两句是一个意思。

  • 使用 tf-idf 模型对文本数据进行处理

       tf-idf 全称为 “ term-frequency-inverse document frequency ”,一般翻译为 “ 词频-逆向文件频率 ”。它是一种用来评估某个词对于一个语料库中某一份文件的重要程度,如果某个词在某个文件中出现的次数非常高,但在其他文件中出现的次数很少,那么 tf-idf 就会认为这个词能够很好地将文件进行区分,重要程度就会较高,反之则认为该单词的重要程度较低。
       tf-idf 的公式如下:
       首先计算 tf 值:

t f = n i , j ∑ k n k , j tf = \frac{n_{i,j}}{\sum_{k}n_{k,j}} tf=knk,jni,j

式子中: n i , j n_{i,j} ni,j 表示某个词在语料中某个文件内出现的次数; ∑ k n k , j \sum_{k}n_{k,j} knk,j 表示的是该文件中所有单词出现的次数之和。
       而在 scikit-learn 中,idf 的计算公式如下:

i d f = l o g ( N + 1 N w + 1 ) + 1 idf = log( \frac{N+1}{N_w+1})+1 idf=log(Nw+1N+1)+1

       式中: N N N 代表的是语料库文件的总数; N w N_w Nw 代表的是语料库中包含上述单词的文件数量。
       那么最终计算 tf-idf 值的公式就是:

t f − i d f = t f × i d f tf-idf = tf \times idf tfidf=tf×idf

       可能在别的地方看到的 tf-idf 计算公式不一样,这是正常的,因为 itf-idf 的计算公式本身有很多种变体。

       在 scikit-learn 中,有两个类使用了 tf-idf 方法,其中一个是 TfidfTransformer,它用来将 CountVectorizer 从文本中提取的特征矩阵进行转化;另一个是 TfidfVectorizer,它和 CountVectorizer 的用法相同的——简单理解的话,它相当于把 CountVectorizer 和 TfidfTransformer 所有的工作整合到了一起。
       为了进一步介绍 TfidfVectorizer 的用法,以及它和 CountVectorizer 的区别,我们下面使用一个相对复杂的数据集,也是一个非常经典的用于进行自然语言处理的案例,就是 IMDB 电影评论数据集。这个数据集是由 Stanford 研究人员创建的,包括 100 000 条 IMDB 网站用户对于不同电影的评论,每条评论被标注为 “ 正面 ”(Positive)或者 “ 负面 ”(Negtive)两种类型。如果用户在 IMDB 网站上给某个电影的评分大于或等于 6,那么他的评论将标注为 “ 正面 ”,否则被标注为 “ 负面 ”。
       创建者已经将数据集拆分成了训练集和测试集,分别有 25000 条数据,并且放在了不同的文件夹中,正面评论放在 “ pos ” 文件夹中,负面放在了 “ neg ” 文件夹中,还有 50000 条没有进行分类的数据集,可以用来进行无监督学习的实验。但是该数据集是英文的,对于中文自然语言处理来讲不合适。
       下载链接:

	http://ai.stanford.edu/~amaas/data/sentiment/

       在该文件夹的 “ train ” 文件夹中还有一个 “ unsup ” 的子文件夹,存放的是不含分类标注的用于无监督学习的数据。
       为了减少数据载入时间,这里抽取了正面和负面各 50 个数据来训练模型:
6、训练集文件数量和某条影评内容
       可以看到整个训练集有 100 个样本。通过打印第 22 个样本,可以发现有很多 <br /> 的符号,这是在网页中用来分行的符号。为了不让它影响机器学习的模型,将其用空格代替:
7、将文本中的分行符号去掉
       运行上述程序之后,<br /> 符号就会被空格代替。接下来载入测试集:
8、测试数据集文件数量
       可以看到测试集的样本数为 100,同时也把测试集中的 <br /> 符号用空格代替了。进一步对文本数据进行特征提取:9、训练集的特征数量和最后10个特征
       训练的特征有 3942 个,同时也打印出了最后 10 个特征名称。下面使用监督学习算法来进行交叉验证评分,观察模型是否能较好地拟合训练集数据。
10、训练数据集的模型交叉验证平均分
       使用了 LinearSVC 算法进行建模后,得到的模型平均分是 0.839,并不是很满意。继续观察泛化到测试集:
11、模型在测试集的得分
       模型在测试集的得分就低的多了,仅有0.54,说明有接近一半的样本被分到了错误的分类中。这很大一部份原因是我们抽取的样本太少,接下来尝试用 tf-idf 算法来处理一下数据。
12、tf-idf处理前后的特征对比
       由于训练集中的样本的有 3942 个特征,便于显示只打印前 5 个样本特征。从结果可以看出,未经 TfidfTransformer 处理的时候,CountVectorizer 只是计算某个词在样本中某个特征出现的次数,而 tf-idf 计算的是词频乘以逆向文档频率,所以是个浮点数。
       观察预处理后的数据集训练的模型有什么变化。
13、经过tf-idf处理后模型的得分
       可以看到,模型并没有得到什么显著的提升,接下来继续改进。

  • 删除文本中的停用词

       “ 停用词 ” 也有称为 “ 应删除词” 或 “ 停止 词 ”。
       在自然语言处理领域,有一个概念称为 “ 停用词 ” (Stopwords),指的是在那些文本处理过程中被筛选出去的,出现频率很高但是又没有什么实际意义的词,如各种语气词、连词、介词等。目前还没有一个通用的定义 “ 停用词 ” 的规划或工具,但常见的方法是:统计文本数据中出现频率过高的词然后将它们作为 “ 停用词 ” 去掉,或者是使用现有的停词表。
       在不同语言中,停用词表的差异也非常大。比如英文中常见的停用词 “ above ” “ into ” “ also ” 等,而中文常见的停用词包括 “ 啊 ” “ 哎呀 ” “ 即便 ” “ 具体地说 ” 等。(可搜索 “ 哈工大停用词库 ”、“ 百度停用词库 ” 等进行深入了解)
       这里主要是使用 scikit-learn 中内置的英语的停用词表,其中包括常见的停用词 318 个。
14、停用词个数及前后各20个
       可以看到,scikit-learn 中 作为停用词的单词包括 “ someone ” “ latterly ”等,一共 318 个。而网上流传比较广泛的中文停用词表基本都超过了1000 个。
       下面对 IMDB 影评数据集中进行停用词的删除,看看模型的分数变化:
15、去掉停用词后的交叉验证分数和测试集分数
       此处经 TfidfVectorizer 处理之后测试集的特征由原来的 3942 变为 3687 个,导致在获取模型得分时报错 “ ValueError: X has 3687 features per sample; expecting 3942 ”,目前问题还没解决。
       程序中直接使用了 TfidfVectorizer 来对文本数据进行特征抽取,这和使用 CountVectorizer 提取特征后,再用 TfidfTransformer 进行转化的效果基本是一样的。随后通过指定 TfidfVectorizer 的 stop_words 参数,让模型将文本中的英语停用词去掉,可得到图中的结果。(得分有了明显的提高,说明去掉停用词确实可以让机器学习模型更好的拟合文本数据,并且能够有效提高模型的泛华能力。)【蓝色字体为书中所写,此处看不出来。】
       中文停用词表可以去网上下载,并在 scikit-learn 中自己定义一个停用词的字典,来达到去掉中文文本停用词的目的。

自然语言处理补充

       Python工具包 NLTK——自然语言领域最常用的工具之一。使用 NLTK 同样可以实现分词、为文本加注标签等功能,此外还可以进行词干提取(Stemming)以及词干还原(Lemmatization)等进阶功能。
       话题建模(Topic Modeling)和文档聚类(Document Clustering)这两种技术所使用的模型可以简单的理解为是一种文本数据的降维方法。但是它和 PCA 或者 NMF 算法不同,而是另外一种被称为 “ 潜狄利克雷分布” 的模型(Latent Dirichlet Allocation,LDA)。LDA所进行的所谓话题建模,这里 “ 话题 ” 二字的意思,并不是平时说的话题,而是指机器对数据进行分析后,将近似的文本进行聚类的结果。
       另外i随着神经网络的发展,自然语言处理领域也诞生了很多新的技术和应用,不得不提的一个工具就是 word2vec 库,另外还有人使用 Tensorflow 建立循环神经网络(RNN)在该领域实现了重大突破。
       
       
       
       
       
       小编机器学习学的一般,只是日常做做比记加深一下印象,望读者不吝赐教,谢谢!

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值