文本分类是最经典的机器学习问题之一,像 anti-spam,情感分析,语义相似等,都是以文本分类为核心建立起来的。当我们能处理好文本分类问题的时候,往往都能很好解决这些问题。

文本数据

常见的数据类型,文本、语音、图片、视频,其中文本是最常见的,即使是信息技术飞速发展的今天,各种短视频和图片应用火得一塌糊涂,文本还是占据相当大的份额。

相对于图片的像素,音频的数字信号,文本对计算机显得有些特殊了。虽然计算机中用各种编码来储存文本信息,且各种编码中通常也包含一定的语言特征,但是这些特征跟像素和数字信号比起来就弱得多了。因此,文本数据需要更多的预处理。

预处理

预处理对结果的影响还是相当大的,可以说,做好预处理工作,就已经成功了一半了。

数据清洗

文本数据中需要处理的问题主要有以下几点:

  • 混杂其中的 tags,比如 HTML tags
  • URL,Email,电话或其他信息
  • 英文大小写、单词的形态、词缀
  • 中文分词
  • 拼写纠错
  • stop words、标点符号、表情等

其中,第一项基本都会去除,做起来也很简单,第二项根据具体情况来考虑是否去除。这两项都可以通过正则来处理,我写了一个简单的 Python 包来做这件事,可以看下 Plane

对英文的形态和词缀,可以用 NLTK 来处理。大小写就更简单了。

是否需要中文分词还有待商榷。一些人认为做分词很重要,可以排除词义混淆的情况,这也是长久以来大家研究分词的意义所在;另一些人认为做分词的话模型就会依赖分词的效果,提前设置了上限,而且现在的深度学习也能很好地从单个字中学到相关特征,没必要再去用分词。总的来说,可以都试试,反正还能做 Ensemble。

拼写纠错其实不好做,英文的话还能参考 Norvig 这个简单的拼写检查器,中文的就非常麻烦了,如果用户没有被输入法纠正的话,那就需要从形近字、同音字、模糊拼音等角度考虑,目前好像没有开源的项目来专门处理这个。

Stop words 的问题也有很多争议,有的觉得这些词会妨碍模型对句子的理解,有的认为足够大的语料可以规避掉这些问题,而且还可能从中获取一些意想不到的特征。标点符号和表情通常会被替换成空格,不过有些任务可能需要特别考虑表情的问题。

另外还有垃圾文本的问题,在足够大的语料面前,这通常不会造成太大影响,排除一些低频词就可以应对大多数情况。

word embedding

前面提到,文本在计算机中通常以编码的形式存在,像 GBK,Unicode 等,并不能直接丢到模型中,需要先转换成对应的编号。

之前大家通常都用 one-hot encoding、count encoding 或者 TF-IDF,但是语言的词汇量巨大,拿中文来说,常用字可能几千个,但是常用词可能几十万都不止,即使用稀疏矩阵表示能解决内存占用问题,也会产生维度灾难,带来一系列问题。

后来,大家都开始用 word embedding 了,本质上是一种降维方法,可以从语料中习得词语的分布式表示,通常会使用几十维到300维的向量,就能大大提高后续任务的效果。

word embedding 基本上有 word2vec 和 GloVe 两种实现。word2vec 有 continuous bag-of-words(CBOW) 和 continuous skip-gram 两种架构,都是只能考虑一个窗口内的中心词和其他词的联系,有一定的局限性;而 GloVe 是考虑词的共现,不过在实际效果上两者相差无几。

分类模型

分类任务

文本分类任务根据类别可以分为二分类和多分类,其中多分类也包括单一类别的多分类和多类别的多分类。

二分类最经典的就是 antispam 了,不管是邮件还是各种论坛,凡是允许用户提交信息的地方几乎都需要用到 antispam。这类任务通常不会简单使用单一模型来做,更多的是根据实际场景进行调整,有针对性地处理各种 spam。

多分类任务更常见,像是一篇新闻,通常会有一个主要的类别,比如经济、体育或者军事等,然而对于大多数文章,通常会涉及多个类别,这个时候就需要多类别多分类模型。

多分类问题中,各个类别的训练样本要尽可能保持一致,否则就会增加一个先验的 bias,即使是用 weights 来调整 loss function 也不如直接保持类别均衡。另外,多个类别之间很可能存在相互包含或某种联系,也会影响最终的分类效果,如果要用 PCA 降维得到独立的新类别的话,新类别可能无法解释,所以这方面怎么做就看个人需要了。

机器学习

传统的机器学习方法中,通常是用 Naive Bayes、Support Vector Machine、Random Forest 等算法来进行分类。其中,SVM 是标准的二分类模型,要处理多分类,则需要 one-vs-one 或 one-vs-rest 方法,不管是哪种,效果都不够好;NB 常被用在 antispam 方面,对于多分类,理论上是可以直接用,不过朴素(天真)的假设,在应对多分类任务的时候会暴露出更严重的问题;RF 在解释性方面还是不错的,只不过 RF 应对太多类别就会力不从心,需要足够多的训练样本。

深度学习

某种程度上来讲,用深度学习来做文本分类可能会显得大材小用了,通常只需要两三层就可以达到很不错的效果了。

最开始用的就是普通的全连接层,这方面的代表是 fastText,速度非常快,不过 fastText 是针对单类别的多分类任务,最后有一个 softmax 层,最后的结果就是只有一个类别是突出的,虽然理论上讲直接用在多分类方面也没大问题,不过效果还是会差一点。

之后 RNN 就被频繁用在各种 NLP 任务上,自然也可以用在文本分类方面,不过词的顺序对分类任务的影响几乎可以忽略不计。

再后来,CNN 也被用在 NLP 任务上,速度更快,效果也足够好,使用不同 size 的 filter 的话,即使不做分词也能得到不错的效果。

最后,Attention 结构也火起来,在 NLP 和 CV 方面都取得了不错的效果,用在文本分类上略显“重”,不过确实能取得更好的效果。

结语

最后给自己写的 multi-label text classification 包 Caver 打个广告,用到了主流的几类模型,易于使用,也可以自己写其他模型嵌入进去,支持简单的 voting ensemble。