文本分类概述

文本分类问题: 给定文档p(可能含有标题t),将文档分类为n个类别中的一个或多个

文本分类应用: 常见的有垃圾邮件识别,情感分析

文本分类方向: 主要有二分类,多分类,多标签分类

文本分类方法: 传统机器学习方法(贝叶斯,svm等),深度学习方法(fastText,TextCNN等)

本文的思路: 本文主要介绍文本分类的处理过程,主要哪些方法。致力让读者明白在处理文本分类问题时应该从什么方向入手,重点关注什么问题,对于不同的场景应该采用什么方法。

文本分类的处理大致分为文本预处理、文本特征提取、分类模型构建等。和英文文本处理分类相比,中文文本的预处理是关键技术。

一、中文分词:

针对中文文本分类时,很关键的一个技术就是中文分词。特征粒度为词粒度远远好于字粒度,其大部分分类算法不考虑词序信息,基于字粒度的损失了过多的n-gram信息。下面简单总结一下中文分词技术:基于字符串匹配的分词方法、基于理解的分词方法和基于统计的分词方法 [1]。

1,基于字符串匹配的分词方法:

过程:这是一种基于词典的中文分词,核心是首先建立统一的词典表,当需要对一个句子进行分词时,首先将句子拆分成多个部分,将每一个部分与字典一一对应,如果该词语在词典中,分词成功,否则继续拆分匹配直到成功。 核心: 字典,切分规则和匹配顺序是核心。 分析:优点是速度快,时间复杂度可以保持在O(n),实现简单,效果尚可;但对歧义和未登录词处理效果不佳。

2,基于理解的分词方法:

基于理解的分词方法是通过让计算机模拟人对句子的理解,达到识别词的效果。其基本思想就是在分词的同时进行句法、语义分析,利用句法信息和语义信息来处理歧义现象。它通常包括三个部分:分词子系统、句法语义子系统、总控部分。

在总控部分的协调下,分词子系统可以获得有关词、句子等的句法和语义信息来对分词歧义进行判断,即它模拟了人对句子的理解过程。这种分词方法需要使用大量的语言知识和信息。由于汉语语言知识的笼统、复杂性,难以将各种语言信息组织成机器可直接读取的形式,因此目前基于理解的分词系统还处在试验阶段。

3,基于统计的分词方法:

过程:统计学认为分词是一个概率最大化问题,即拆分句子,基于语料库,统计相邻的字组成的词语出现的概率,相邻的词出现的次数多,就出现的概率大,按照概率值进行分词,所以一个完整的语料库很重要。

主要的统计模型有:

N元文法模型(N-gram),隐马尔可夫模型(Hidden Markov Model ,HMM),最大熵模型(ME),条件随机场模型(Conditional Random Fields,CRF)等。

二、文本预处理:

1,分词: 中文任务分词必不可少,一般使用jieba分词,工业界的翘楚。

2,去停用词:建立停用词字典,目前停用词字典有2000个左右,停用词主要包括一些副词、形容词及其一些连接词。通过维护一个停用词表,实际上是一个特征提取的过程,本质上是特征选择的一部分。

3,词性标注: 在分词后判断词性(动词、名词、形容词、副词…),在使用jieba分词的时候设置参数就能获取。

三、文本特征工程:

文本分类的核心都是如何从文本中抽取出能够体现文本特点的关键特征,抓取特征到类别之间的映射。

所以特征工程很重要,可以由四部分组成:

1,基于词袋模型的特征表示:以词为单位(Unigram)构建的词袋可能就达到几万维,如果考虑二元词组(Bigram)、三元词组(Trigram)的话词袋大小可能会有几十万之多,因此基于词袋模型的特征表示通常是极其稀疏的。

(1)词袋特征的方法有三种:

Naive版本:不考虑词出现的频率,只要出现过就在相应的位置标1,否则为0;

考虑词频(即term frequency):,认为一段文本中出现越多的词越重要,因此权重也越大;

考虑词的重要性:以TF-IDF表征一个词的重要程度。TF-IDF反映了一种折中的思想:即在一篇文档中,TF认为一个词出现的次数越大可能越重要,但也可能并不是(比如停用词:“的”“是”之类的);IDF认为一个词出现在的文档数越少越重要,但也可能不是(比如一些无意义的生僻词)。

(2)优缺点:

优点: 词袋模型比较简单直观,它通常能学习出一些关键词和类别之间的映射关系

缺点: 丢失了文本中词出现的先后顺序信息;仅将词语符号化,没有考虑词之间的语义联系(比如,“麦克风”和“话筒”是不同的词,但是语义是相同的);

2,基于embedding的特征表示: 通过词向量计算文本的特征。(主要针对短文本)

取平均: 取短文本的各个词向量之和(或者取平均)作为文本的向量表示;

网络特征: 用一个pre-train好的NN model得到文本作为输入的最后一层向量表示;

3,基于NN Model抽取的特征: NN的好处在于能end2end实现模型的训练和测试,利用模型的非线性和众多参数来学习特征,而不需要手工提取特征。CNN善于捕捉文本中关键的局部信息,而RNN则善于捕捉文本的上下文信息(考虑语序信息),并且有一定的记忆能力。

4,基于任务本身抽取的特征:主要是针对具体任务而设计的,通过我们对数据的观察和感知,也许能够发现一些可能有用的特征。有时候,这些手工特征对最后的分类效果提升很大。举个例子,比如对于正负面评论分类任务,对于负面评论,包含负面词的数量就是一维很强的特征。

5,特征融合:对于特征维数较高、数据模式复杂的情况,建议用非线性模型(如比较流行的GDBT, XGBoost);对于特征维数较低、数据模式简单的情况,建议用简单的线性模型即可(如LR)。

6,主题特征:

LDA(文档的话题): 可以假设文档集有T个话题,一篇文档可能属于一个或多个话题,通过LDA模型可以计算出文档属于某个话题的概率,这样可以计算出一个DxT的矩阵。LDA特征在文档打标签等任务上表现很好。

LSI(文档的潜在语义): 通过分解文档-词频矩阵来计算文档的潜在语义,和LDA有一点相似,都是文档的潜在特征。

四、文本分类,传统机器学习方法:

这部分不是重点,传统机器学习算法中能用来分类的模型都可以用,常见的有:

NB模型,随机森林模型(RF),SVM分类模型,KNN分类模型,神经网络分类模型。

这里重点提一下贝叶斯模型,因为工业用这个模型用来识别垃圾邮件。

常见方法

文本分类问题与其它分类问题没有本质上的区别,其方法可以归结为根据待分类数据的某些特征来进行匹配,当然完全的匹配是不太可能的,因此必须(根据某种评价标准)选择最优的匹配结果,从而完成分类。

词匹配法

词匹配法是最早被提出的分类算法。

这种方法仅根据文档中是否出现了与类名相同的词(顶多再加入同义词的处理)来判断文档是否属于某个类别。

很显然,这种过于简单机械的方法无法带来良好的分类效果。

知识工程

后来兴起过一段时间的知识工程的方法则借助于专业人员的帮助,为每个类别定义大量的推理规则,如果一篇文档能满足这些推理规则,则可以判定属于该类别。这 里与特定规则的匹配程度成为了文本的特征。

由于在系统中加入了人为判断的因素,准确度比词匹配法大为提高。

但这种方法的缺点仍然明显,例如分类的质量严重依赖于这些规则的好坏,也就是依赖于制定规则的“人”的好坏;

再比如制定规则的人都是专家级别,人力成本大幅上升常常令人难以承受;

而知识工程最致命的弱点是完全不具备可推广性,一个针对金融领域构建的分类系统,如果要扩充到医疗或社会保险等相关领域,则除了完全推倒重来以外没有其他办法,常常造成巨大的知识和资金浪费。

统计学习

后来人们意识到,究竟依据什么特征来判断文本应当隶属的类别这个问题,就连人类自己都不太回答得清楚,有太多所谓“只可意会,不能言传”的东西在里面。

人类的判断大多依据经验以及直觉,因此自然而然的会有人想到和让机器像人类一样自己来通过对大量同类文档的观察来自己总结经验,作为今后分类的依据。

这便是统计学习方法的基本思想。

统计学习方法需要一批由人工进行了准确分类的文档作为学习的材料(称为训练集,注意由人分类一批文档比从这些文档中总结出准确的规则成本要低得多),计算机从这些文档中挖掘出一些能够有效分类的规则,这个过程被形象的称为训练,而总结出的规则集合常常被称为分类器。

训练完成之后,需要对计算机从来没有见过的文档进行分类时,便使用这些分类器来进行。

这些训练集包括sogou文本分类分类测试数据、中文文本分类分类语料库,包含Arts、Literature等类别的语料文本、可用于聚类的英文文本数据集、网易分类文本分类文本数据、tc-corpus-train(语料库训练集,适用于文本分类分类中的训练)、2002年中文网页分类训练集CCT2002-v1.1等。

现如今,统计学习方法已经成为了文本分类领域绝对的主流。

主要的原因在于其中的很多技术拥有坚实的理论基础(相比之下,知识工程方法中专家的主观因素居多),存在明确的评价标准,以及实际表现良好。

统计分类算法

将样本数据成功转化为向量表示之后,计算机才算开始真正意义上的“学习”过程。

常用的分类算法为:

决策树,Rocchio,朴素贝叶斯,神经网络,支持向量机,线性最小平方拟合,kNN,遗传算法,最大熵,Generalized Instance Set等。

在这里只挑几个最具代表性的算法侃一侃。

Rocchio 算法

Rocchio算法应该算是人们思考文本分类问题时最先能想到,也最符合直觉的解决方法。

基本的思路是把一个类别里的样本文档各项取个平均值(例如把所有 “体育”类文档中词汇“篮球”出现的次数取个平均值,再把“裁判”取个平均值,依次做下去),可以得到一个新的向量,形象的称之为“质心”,质心就成了这个类别最具代表性的向量表示。

再有新文档需要判断的时候,比较新文档和质心有多么相像(八股点说,判断他们之间的距离)就可以确定新文档属不属于这个类。

稍微改进一点的Rocchio算法不仅考虑属于这个类别的文档(称为正样本),也考虑不属于这个类别的文档数据(称为负样本),计算出来的质心尽量靠近正样本同时尽量远离负样本。

Rocchio算法做了两个很致命的假设,使得它的性能出奇的差。

一是它认为一个类别的文档仅仅聚集在一个质心的周围,实际情况往往不是如此(这样的数据称为线性不可分的);二是它假设训练数据是绝对正确的,因为它没有任何定量衡量样本是否含有噪声的机制,因而也就对错误数据毫无抵抗力。

不过Rocchio产生的分类器很直观,很容易被人类理解,算法也简单,还是有一定的利用价值的,常常被用来做科研中比较不同算法优劣的基线系统(Base Line)。

朴素贝叶斯算法

贝叶斯算法关注的是文档属于某类别概率。

文档属于某个类别的概率等于文档中每个词属于该类别的概率的综合表达式。

而每个词属于该类别的概率又在一定程度上 可以用这个词在该类别训练文档中出现的次数(词频信息)来粗略估计,因而使得整个计算过程成为可行的。

使用朴素贝叶斯算法时,在训练阶段的主要任务就是估计这些值。

朴素贝叶斯算法的公式并不是只有一个。

首先对于每一个样本中的元素要计算先验概率。其次要计算一个样本对于每个分类的概率,概率最大的分类将被采纳。

所以

其中 P(d| Ci)=P(w1|Ci) P(w2|Ci) …P(wi|Ci) P(w1|Ci) …P(wm|Ci) (式1)

P(w|C)=元素w在分类为C的样本中出现次数/数据整理后的样本中元素的总数 (式2)

这其中就蕴含着朴素贝叶斯算法最大的两个缺陷。

首先,P(d|Ci) 之所以能展开成(式1)的连乘积形式,就是假设一篇文章中的各个词之间是彼此独立的,其中一个词的出现丝毫不受另一个词的影响(回忆一下概率论中变量彼此独立的概念就可以知道),但这显然不对,即使不是语言学专家的我们也知道,词语之间有明显的所谓“共现”关系,在不同主题的文章中,可能共现的次数 或频率有变化,但彼此间绝对谈不上独立。

ps: 然而朴素贝叶斯往往表现良好,因为这种假设在数据量较大时反而影响没有那么大。

其二,使用某个词在某个类别训练文档中出现的次数来估计P(wi|Ci)时,只在训练样本数量非常多的情况下才比较准确(考虑扔硬币的问题,得通过大量观察才能基本得出正反面出现的概率都是二分之一的结论,观察次数太少时很可能得到错误的答案),而需要大量样本的要求不仅给前期人工分类的工作带来更高要求 (从而成本上升),在后期由计算机处理的时候也对存储和计算资源提出了更高的要求。

但是稍有常识的技术人员都会了解,数据挖掘中占用大量时间的部分是数据整理。

在数据整理阶段,可以根据词汇的情况生成字典,删除冗余没有意义的词汇,对于单字和重要的词组分开计算等等。

这样可以避免朴素贝叶斯算法的一些问题。其实真正的问题还是存在于算法对于信息熵的计算方式。

朴素贝叶斯算法在很多情况下,通过专业人员的优化,可以取得极为良好的识别效果。

最为人熟悉的两家跨国软件公司在仍采用朴素贝叶斯算法作为有些软件自然语言处理的工具算法。

kNN 算法

最近邻算法(kNN):

在给定新文档后,计算新文档特征向量和训练文档集中各个文档的向量的相似度,得到K篇与该新文档距离最近最相似的文档,根据这K篇文档所属的类别判定新文档所属的类别(注意这也意味着kNN算法根本没有真正意义上的“训练”阶段)。

这种判断方法很好的克服了Rocchio算法中无法处理线性不可分问题的缺陷,也很适用于分类标准随时会产生变化的需求(只要删除旧训练文档,添加新训练文档,就改变了分类的准则)。

kNN唯一的也可以说最致命的缺点就是判断一篇新文档的类别时,需要把它与现存的所有训练文档全都比较一遍,这个计算代价并不是每个系统都能够承受的(比 如我将要构建的一个文本分类系统,上万个类,每个类即便只有20个训练样本,为了判断一个新文档的类别,也要做20万次的向量比较!)。

一些基于kNN的改良方法比如Generalized Instance Set就在试图解决这个问题。

kNN也有另一个缺点,当样本不平衡时,如一个类的样本容量很大,而其他类样本容量很小时,有可能导致当输入一个新样本时,该样本的K个邻居中大容量类的样本占多数。

SVM

SVM(Support Vector Machine)是Cortes和Vapnik于1995年首先提出的,它在解决小样本、非线性及高维模式识别中表现出许多特有的优势,并能够推广应用到函数拟合等其他机器学习问题中。

支持向量机方法是建立在统计学习理论的VC维理论和结构风险最小原理基础上的,根据有限的样本信息在模型的复杂性(即对特定训练样本的学习精度,Accuracy)和学习能力(即无错误地识别任意样本的能力)之间寻求最佳折衷,以期获得最好的推广能力(或称泛化能力)。

SVM 方法有很坚实的理论基础,SVM 训练的本质是解决一个二次规划问题(Quadruple Programming,指目标函数为二次函数,约束条件为线性约束的最优化问题),得到的是全局最优解,这使它有着其他统计学习技术难以比拟的优越性。

SVM分类器的文本分类效果很好,是最好的分类器之一。

同时使用核函数将原始的样本空间向高维空间进行变换,能够解决原始样本线性不可分的问题。

其缺点是核函数的选择缺乏指导,难以针对具体问题选择最佳的核函数;

另外SVM 训练速度极大地受到训练集规模的影响,计算开销比较大,针对SVM 的训练速度问题,研究者提出了很多改进方法,包括Chunking 方法、Osuna算法、SMO 算法和交互SVM 等。

SVM分类器的优点在于通用性较好,且分类精度高、分类速度快、分类速度与训练样本个数无关,在查准和查全率方面都略优于kNN及朴素贝叶斯方法。

五、深度学习文本分类模型:

1,fastText 模型:

fastText 是 word2vec 作者 Mikolov 转战 Facebook 后16年7月刚发表的一篇论文:

Bag of Tricks for Efficient Text Classification

模型结构:

模型结构

原理: 句子中所有的词向量进行平均(某种意义上可以理解为只有一个avg pooling特殊CNN),然后直接连接一个 softmax 层进行分类。

2,TextCNN:

利用CNN来提取句子中类似 n-gram 的关键信息。

模型结构:

模型结构

模型结构

改进: fastText 中的网络结果是完全没有考虑词序信息的,而TextCNN提取句子中类似 n-gram 的关键信息。

3,TextRNN:

模型: Bi-directional RNN(实际使用的是双向LSTM)从某种意义上可以理解为可以捕获变长且双向的的 “n-gram” 信息。

3,TextRNN:

改进: CNN有个最大问题是固定 filter_size 的视野,一方面无法建模更长的序列信息,另一方面 filter_size 的超参调节也很繁琐。

4,TextRNN + Attention:

模型结构:

模型结构

改进:注意力(Attention)机制是自然语言处理领域一个常用的建模长时间记忆机制,能够很直观的给出每个词对结果的贡献,基本成了Seq2Seq模型的标配了。实际上文本分类从某种意义上也可以理解为一种特殊的Seq2Seq,所以考虑把Attention机制引入进来。

5,TextRCNN(TextRNN + CNN):

模型结构:

模型结构

过程:

利用前向和后向RNN得到每个词的前向和后向上下文的表示:

前向和后向RNN

词的表示变成词向量和前向后向上下文向量连接起来的形式:

词的表示

再接跟TextCNN相同卷积层,pooling层即可,唯一不同的是卷积层 filter_size = 1就可以了,不再需要更大 filter_size 获得更大视野。

6,深度学习经验:

模型显然并不是最重要的: 好的模型设计对拿到好结果的至关重要,也更是学术关注热点。

但实际使用中,模型的工作量占的时间其实相对比较少。虽然再第二部分介绍了5种CNN/RNN及其变体的模型,实际中文本分类任务单纯用CNN已经足以取得很不错的结果了,我们的实验测试RCNN对准确率提升大约1%,并不是十分的显著。

最佳实践是先用TextCNN模型把整体任务效果调试到最好,再尝试改进模型。

理解你的数据: 虽然应用深度学习有一个很大的优势是不再需要繁琐低效的人工特征工程,然而如果你只是把他当做一个黑盒,难免会经常怀疑人生。

一定要理解你的数据,记住无论传统方法还是深度学习方法,数据 sense 始终非常重要。

要重视 badcase 分析,明白你的数据是否适合,为什么对为什么错。

一定要用 dropout: 有两种情况可以不用:数据量特别小,或者你用了更好的正则方法,比如bn。实际中我们尝试了不同参数的dropout,最好的还是0.5,所以如果你的计算资源很有限,默认0.5是一个很好的选择。

未必一定要 softmax loss: 这取决与你的数据,如果你的任务是多个类别间非互斥,可以试试着训练多个二分类器,也就是把问题定义为multi lable 而非 multi class,我们调整后准确率还是增加了>1%。

类目不均衡问题: 基本是一个在很多场景都验证过的结论:如果你的loss被一部分类别dominate,对总体而言大多是负向的。建议可以尝试类似 booststrap 方法调整 loss 中样本权重方式解决。

避免训练震荡: 默认一定要增加随机采样因素尽可能使得数据分布iid,默认shuffle机制能使得训练结果更稳定。如果训练模型仍然很震荡,可以考虑调整学习率或 mini_batch_size。

参考资料

贝叶斯分类

百度百科-文本分类

知乎-1-文本分类之综述

知乎-如何进行文本分类?

文本分类概述(nlp)

NLP之文本分类

自然语言处理——文本分类概述

文本情感分类

深度学习入门NLP-文本分类