第6.1节 词袋模型
各位朋友大家好,欢迎来到月来客栈,我是掌柜空字符。
本期推送内容目录如下,如果你觉得本期内容对你所有帮助欢迎点个赞、关个注、下回更新不迷路。
6.1 词袋模型 6.1.1 理解词袋模型 6.1.2 文本分词 6.1.3 构造词表 6.1.4 文本向量化 6.1.5 考虑词频的文本向量化 6.1.6 小结
在前面几章的示例介绍中,我们所用到的数据集都是已经处理好的数据,换句话说这些数据集的每个特征维度都已经转换成了可用于计算的数值形式,但是在实际的建模任务中,我们获得的数据集可能并不是这样的形式。例如接下来要完成的一个任务,对中文垃圾邮件进行分类。
6.1 词袋模型
例如,对于下面这样一个邮件(样本),应该采用什么样的方式对其进行量化呢?同时,我们知道在建模过程中需要保证每个样本的特征维度数都一样,但是这里每一封邮件的长度却并不同,这又该怎么处理呢?接下来,笔者就介绍机器学习中的第一种文本向量化方法——词袋模型(Bag Of Words,BOW)。
“股权分置已经牵动全国股民的心,是机会?还是陷阱?如果是机会,则应该如何把握?如果是陷阱,则应该如何规避?请单击此网址索取和讯专家团针对股权分置的操作指导:http://www.spam.com/gwyqxjqxx/ ”。
6.1.1 理解词袋模型
什么是词袋模型呢?其实词袋模型这个叫法非常形象,突出了模型的核心思想。所谓词袋模型就是,首先将训练样本中所有不重复的词放到这个袋子中构成一个词表(字典),然后以这个词表为标准来遍历每个样本,如果词表中对应位置的词出现在样本中,则词表对应位置就用1来表示,没有出现就用0来表示,最后,对于每个样本来讲都将其向量化成了一个和词表长度一样的只含有0和1的向量。
如图6-1所示,此示意图为一个直观的词袋模型转换示意图。左边为原始数据集(包含两个样本),中间为词表,右边为向量化的结果。
其中[1 1 0 1]
的含义就是,在样本“机器学习是人工智能的子集”中有3个词出现在词表当中,分别是“机器学习”、“人工智能”和“子集”。
具体步骤可以总结为以下3步。
1. 文本分词
首先需要将原始数据的每个样本进行分词处理(英文语料可以跳过这步)。
2. 构造词表
然后在所有的分词结果中去掉重复的部分,保证每个词语只出现一次,并且同时要以任意一种顺序来固定词表中每个词的位置。
3. 文本向量化
遍历每个数据样本,若词表中的词出现在该样本中,则对应位置为1,否则为0。
在图6-1中,对样本“机器学习是人工智能的子集”来讲,其中有3个词出现在词表中,所以词表中每个词的对应位置为1,而“深度学习”这个词并没有出现在样本中,所以对应位置为0。
可以看出,向量化后每个样本特征维度的长度都和词表长度相同(图6-1中为4)。虽然这样做的好处是词表包含了样本中所有出现过的词,但是却很容易导致维度灾难。因为通常一个一般大小的中文数据集,可能会出现数万个词语(而这意味着转化后向量的维度也有这么大),所以在实际处理中,在分词结束后通常还会进行词频统计这一步,即统计每个词在数据集中出现的次数,然后只选择其中出现频率最高的前K个词作为最终的词表。最后,通常也会将一些无意义的虚词,即停用词(Stop Words)去掉,例如的、啊、了等。
6.1.2 文本分词
通过6.1.1节的介绍可以知道,向量化的第一步是需要对文本进行分词。下面笔者将介绍一款常用的开源分词工具jieba。当然,使用jieba库的前提是先要安装,读者可以先进入对应的虚拟环境中,然后通过命令pip install jieba
进行安装。
这里先用下面这段文本进行分词处理并做词频统计。
央视网消息:当地时间11日,美国国会参议院以88票对11票的结果通过了一项动议,允许国会“在总统以国家安全为由决定征收关税时”发挥一定的限制作用。这项动议主要针对加征钢、铝关税的232调查,目前尚不具有约束力。动议的主要发起者——共和党参议员鲍勃·科克说,11日的投票只是一小步,他会继续推动进行有约束力的投票。
可以看到,这段文本中还包含了很多标点符号和数字,显然暂时不需要这些内容,所以在分词的时候可以通过正则表达式进行过滤。同时,jieba库分别提供了两种分词模式来应对不同场景下的中文分词,下面分别进行介绍。完整代码见Book/Chapter06/01_cut_words.py
文件。
1. 普通分词模式
普通分词模式指的是按照常规的分词方法,将一个句子分割成多个词语的组成形式,代码如下:
1 import jieba,re
2 def cutWords(s, cut_all=False):
3 cut_words = []
4 s = re.sub("[A-Za-z0-9\:\·\—\,\。\“ \”]", "", s)
5 seg_list = jieba.cut(s, cut_all=cut_all)
6 cut_words.append("/".join(seg_list))
在上述代码中,第4行代码的作用是将所有字母、数字、冒号、逗号、句号等过滤掉,第5行用来完成分词处理的过程,当cut_all = False
时,表示普通分词模式;第6行是将所有分词后的结果以/
进行分割展示。根据上述代码分词结束后便能看到以下所示的结果:
['央视网/消息/当地/时间/日/美国国会参议院/以票/对票/的/结果/通过/了/一项/动议/允许/国会/在/总统/以/国家/安全/为/由/决定/征收/关税/时/发挥/一定/的/限制/作用/这项/动议/主要/针对/加征/钢铝/关税/的/调查/目前/尚/不/具有/约束力/动议/的/主要/发起者/共和党/参议员/鲍勃/科克/说/日/的/投票/只是/一/小步/他会/继续/推动/进行/有/约束力/的/投票']
但是,对于有的句子来讲可以有不同的分词方法,例如“美国国会参议院”这段描述,既可以分成“美国 国会 参议院”,也可以分成“美国国会 参议院”,甚至可以直接分成“美国国会参议院”,不同的人可能有不同的切分方式,因此,jieba还提供了另外一种全分词模式。
2. 全分词模式
当把上面代码中的cut_all
设置为True
后,便可以开启全分词模式,分词后的结果如下:
['央视/央视网/视网/消息/当地/时间/日/美国/美国国会/美国国会参议院/国会/参议/参议院/议院/以/票/对/票/的/结果/通过/了/一项/动议/允许/许国/国会/在/总统/以/国家/家安/安全/为/由/决定/征收/关税/时/发挥/一定/的/限制/制作/作用/这项/动议/主要/针对/加征/钢/铝/关税/的/调查/目前/尚不/不具/具有/约束/约束力/动议/的/主要/发起/发起者/共和/共和党/党参/参议/参议员/议员/鲍/勃/科克/说/日/的/投票/只是/一小/小步/他/会/继续/推动/进行/有/约束/约束力/的/投票']
可以看出,对于有的句子,分词后的结果确实看起来结结巴巴,但这就是全分词模式的作用。在分词结束后,就可以对分词结果进行词频统计并构造词表。