## 目录
- [11. 文本分类](#11-文本分类)
- [11.1 文本分类的概念](#111-文本分类的概念)
- [11.2 文本分类语料库](#112-文本分类语料库)
- [11.3 文本分类的特征提取](#113-文本分类的特征提取)
- [11.4 朴素贝叶斯分类器](#114-朴素贝叶斯分类器)
- [11.5 支持向量机](#115-支持向量机)
- [11.6 标准化评测](#116-标准化评测)
- [11.7 情感分析](#117-情感分析)

## 11. 文本分类

上一章我们学习了 文本聚类，体验了无须标注语料库的便利性。然而无监督学习总归无法按照我们的意志预测出文档的类别，限制了文本聚类的应用场景。有许多场景需要将文档分门别类地归人具体的类别中，比如垃圾邮件过滤和社交媒体的自动标签推荐。在这一章中， 我们将介绍如何实现这些需求。



### 11.1 文本分类的概念

**文本分类**( text classification),又称**文档分类**( document classification),指的是将一个文档归类到一个或多个类别中的自然语言处理任务。文本分类的应用场景非常广泛，涵盖垃圾邮件过滤、垃圾评论过滤、自动标签、情感分析等任何需要自动归档文本的场合。

文本的类别有时又称作**标签**，所有类别组成了标注集，文本分类输出结果一定属于标注集。

文本分类是一个典型的监督学习任务，其流程离不开人工指导: 人工标注文档的类别，利用语料训练模型，利用模型预测文档的类别。



### 11.2 文本分类语料库

文本分类语料库的标注过程相对简单，只需收集一些文档， 人工指定每篇文档的类别即可。另外，许多新闻网站的栏目是由编辑人工整理的，如果栏目设置符合要求，也可以用爬虫爬取下来作语料库使用。其中，搜狗实验室就提供了这样一份语料库 ，详情见代码(**自动下载语料库**): load_text_classification_corpus.py

[https://github.com/NLP-LOVE/Introduction-NLP/tree/master/code/ch11/load_text_classification_corpus.py](https://github.com/NLP-LOVE/Introduction-NLP/tree/master/code/ch11/load_text_classification_corpus.py)

运行结果如下:

```
标注集：[教育, 汽车, 健康, 军事, 体育, 自然语言处理]
第一篇文档的类别：教育
```

当语料库就绪时，文本分类的流程一般分为特征提取和分类器处理两大步。



### 11.3 文本分类的特征提取

在机器学习中，我们需要对具体对象提取出有助于分类的特征，才能交给某个分类器进行分类。这些特征数值化后为一个定长的向量(数据点)，用来作为分类器的输入。在训练时，分类器根据数据集中的数据点学习出决策边界。在预测时，分类器根据输人的效据点落在决策边界的位置来决定类别。

我们依然使用词袋向量作为特征向量，词袋向量是词语颗粒度上的频次或 TF-IDF 向量，先进行分词处理

1. **分词**

   HanLP 允许为数据集的构造函数指定一个分词器 ITokenizer，用来实现包括分词在内的预处理逻辑。

   | 实现            | 应用场景                                        |
   | --------------- | ----------------------------------------------- |
   | HanLPTokenizer  | 中文文本，使用NotionalTokenizer分词并过滤停用词 |
   | BlankTokenizer  | 英文文本，使用空格分词                          |
   | BigramTokenizer | 中文文本，将相邻字符作为二元语法输出            |

   

2. **卡方特征选择**

   在文本分类时会有这样一个问题，比如汉语中的虚词“的”，这些词在所有类别的文档中均匀出现，为了消除这些单词的影响，一方面可以用停用词表，另一方面可以用**卡方非参数检验**来过滤掉与类别相关程度不高的词语。

   在统计学上，卡方检验常用于检验两个事件的独立性，如果两个随机事件 A 和 B 相互独立，则两者同时发生的概率P(AB)= P(A)P(B)。如果将词语的出现与类别的出现作为两个随机事件则类别独立性越高的词语越不适合作为特征。如果将某个事件的期望记作 E，实际出现(观测)的频次记作 N，则卡方检验衡量期望与观测的相似程度。卡方检验值越高，则期望和观测的计数越相化也更大程度地否定了独立性。

   一旦确定了哪些特征有用，接下来就可以将文档转化为向量了。

   

3. **词袋向量**

   我们提取的是 TF 特征，统计出每个特征及其频次。以特征的 id 作为下标，频次作为数值，假设一共有 n 个特征，一篇文档就转化为 n 维的词袋向量。沿用机器学习文献的习惯，将词袋向量记作 x，向量的第 i 维记作 X1。将类别记
   作 y，其中 K 为类别总数。则语料库(训练数据集) T 可以表示为词袋向量 x 和类别 y 所构成的二元组的集合:
   
   ![](https://github.com/NLP-LOVE/Introduction-NLP/raw/master/img/2020-2-13_14-47-11.gif)
   
   在不进行特征选择的前提下，如果以词语作为特征，则 n 大约在 10 万量级；如果以字符二元语法作为特征，则 n 大约在 50 万量级。数十万维的向量运算开销不容小觑，一般利用卡方特征选择，可以将特征数量减小到10% ~ 20%左右。

   当文档被转化为向量后，就可以利用机器学习进行训练了。



### 11.4 朴素贝叶斯分类器

在各种各样的分类器中，**朴素贝叶斯法**( naive Bayes)可算是最简单常用的一种生成式模型。朴素贝叶斯法基于贝叶斯定理将联合概率转化为条件概率，然后利用特征条件独立假设简化条件概率的计算。

1. **朴素贝叶斯法原理**

   朴素贝叶斯法的目标是通过训练集学习联合概率分布 P(X,Y)，由贝叶斯定理可以将联合概率转换为先验概率分布与条件概率分布之积:
   
   ![](https://github.com/NLP-LOVE/Introduction-NLP/raw/master/img/2020-2-13_15-49-16.gif)
   
   - **首先**计算先验概率分布 P(Y=Ck)，通过统计每个类别下的样本数:
   
     ![](https://github.com/NLP-LOVE/Introduction-NLP/raw/master/img/2020-2-13_15-51-18.gif)
   
   - **然后**计算 P(X=x|Y=Ck)，这个难以估计，因为 x 的量级非常大，可以从下式看出来:
   
     ![](https://github.com/NLP-LOVE/Introduction-NLP/raw/master/img/2020-2-13_15-52-26.gif)
   
     该条件概率分布的参数数量是指数级的，难以估计。
   
     为此朴素贝叶斯法“朴素”的假设了所有特征是条件独立的:
   
     ![](https://github.com/NLP-LOVE/Introduction-NLP/raw/master/img/2020-2-13_15-54-25.gif)
   
     于是，又可以利用极大似然来进行估计:
   
     ![](https://github.com/NLP-LOVE/Introduction-NLP/raw/master/img/2020-2-13_15-55-22.gif)
   
   - **预测**时，朴素贝叶斯法依然利用贝叶斯公式找出后验概率 P(Y=Ck|X=x) 最大的类别 Ck 作为输出 y:
   
     ![](https://github.com/NLP-LOVE/Introduction-NLP/raw/master/img/2020-2-13_15-56-25.gif)
   
     将贝叶斯公式带入上式得:
   
     ![](https://github.com/NLP-LOVE/Introduction-NLP/raw/master/img/2020-2-13_15-57-21.gif)
   
   - **最终**，由于分母与 Ck 无关，可以省略掉，然后将独立性假设带入，得到最终的分类预测函数:
   
     ![](https://github.com/NLP-LOVE/Introduction-NLP/raw/master/img/2020-2-13_15-58-29.gif)
2. **朴素贝叶斯分类器实现**

   实现代码详见: text_classification.py

   [https://github.com/NLP-LOVE/Introduction-NLP/tree/master/code/ch11/text_classification.py](https://github.com/NLP-LOVE/Introduction-NLP/tree/master/code/ch11/text_classification.py)

   运行结果如下:

   ```
   《C罗获2018环球足球奖最佳球员 德尚荣膺最佳教练》	属于分类	【体育】
   《英国造航母耗时8年仍未服役 被中国速度远远甩在身后》	属于分类	【军事】
   《 研究生考录模式亟待进一步专业化》	属于分类	【教育】
   《如果真想用食物解压,建议可以食用燕麦》	属于分类	【健康】
   《通用及其部分竞争对手目前正在考虑解决库存问题》	属于分类	【汽车】
   ```

   朴素贝叶斯法实现简单，但由于特征独立性假设过于强烈，有时会影响准确性，下面开始介绍更加健壮的支持向量机分类器。



### 11.5 支持向量机

**支持向量机**( Support Vector Machine, SVM)是一种二分类模型，其学习策略在于如何找出一个决策边界，使得边界到正负样本的最小距离都最远。这种策略使得支持向量机有别于感知机，能够找到一个更加稳健的决策边界。支持向量机最简单的形式为线性支持向量机，其决策边界为一个超平面，适用于线性可分数据集。

有关**支持向量机(SVM)的原理**详见我的博客，这里不加详细介绍:

[http://mantchs.com/2019/07/11/ML/SVM/](http://mantchs.com/2019/07/11/ML/SVM/)

**线性支持向量机文本分类器实现**

实现代码详见: svm_text_classification.py

[https://github.com/NLP-LOVE/Introduction-NLP/tree/master/code/ch11/svm_text_classification.py](https://github.com/NLP-LOVE/Introduction-NLP/tree/master/code/ch11/svm_text_classification.py)

可能第一次运行失败，java类没有加载，重启环境运行就可以了，运行结果如下:

```
《C罗获2018环球足球奖最佳球员 德尚荣膺最佳教练》	属于分类	【体育】
《潜艇具有很强的战略威慑能力与实战能力》	属于分类	【军事】
《 研究生考录模式亟待进一步专业化》	属于分类	【汽车】
《如果真想用食物解压,建议可以食用燕麦》	属于分类	【健康】
《通用及其部分竞争对手目前正在考虑解决库存问题》	属于分类	【汽车】
```



### 11.6 标准化评测

本次评测采用两种分类器和两种分词器搭配进行评估，所有试验采用的数据集皆为搜狗文本分类语料库，特征剪裁算法皆为卡方检验。

我们在搜狗文本分类语料库上对{朴素贝叶斯，支持向量机} * {中文分词(HanLPTokenizer)，二元语法(BigramTokenizer)}的 4 种搭配组合做评测。

评测代码详见: text_classification_evaluation.py

[https://github.com/NLP-LOVE/Introduction-NLP/tree/master/code/ch11/text_classification_evaluation.py](https://github.com/NLP-LOVE/Introduction-NLP/tree/master/code/ch11/text_classification_evaluation.py)

评测结果如下表:

| 算法+分词           | P     | R    | F1    | 文档/秒 |
| ------------------- | ----- | ---- | ----- | ------- |
| 朴素贝叶斯+中文分词 | 96.16 | 96   | 96.08 | 6172    |
| 朴素贝叶斯+二元语法 | 96.36 | 96.2 | 96.28 | 3378    |
| SVM + 中文分词      | 97.24 | 97.2 | 97.22 | 27777   |
| SVM + 二元语法      | 97.83 | 97.8 | 97.81 | 12195   |

- 中文文本分类的确不需要分词，不分词直接用元语法反而能够取得更高的准确率。只不过由于二元语法数量比单词多,导致参与运算的特征更多，相应的分类速度减半。
- 线性支持向量机的分类准确率更高，而且分类速度更快，推荐使用。



### 11.7 情感分析

文本**情感分析**指的是提取文本中的主观信息的一种 NLP 任务，其具体目标通常是找出文本对应的正负情感态度。情感分析可以在实体、句子、段落乃至文档上进行。本文介绍文档级别的情感分析，当然也适用于段落和句子。

对于情感分析而言，只需要准备标注了正负情感的大量文档，就能将其视作普通的文本分类任务来解决。

1. **ChnsentiCorp情感分析语料库**

   该语料库由谭松波博士整理发布，包含酒店、电脑与书籍三个行业的评论与相应情感极性。文档内容为数十字的简短评论。

   

2. **训练情感分析模型**

   实现代码详见: sentiment_analysis.py

   [https://github.com/NLP-LOVE/Introduction-NLP/tree/master/code/ch11/sentiment_analysis.py](https://github.com/NLP-LOVE/Introduction-NLP/tree/master/code/ch11/sentiment_analysis.py)

   运行结果如下:

   ```
   《前台客房服务态度非常好！早餐很丰富，房价很干净。再接再厉！》 情感极性是 【正面】
   《结果大失所望，灯光昏暗，空间极其狭小，床垫质量恶劣，房间还伴着一股霉味。》 情感极性是 【负面】
   《可利用文本分类实现情感分析，效果不是不行》 情感极性是 【负面】
   ```

   值得注意的是，最后一个测试案例“可利用文本分类实现情感分析，效果不是不行”虽然不属于酒店评论，但结果依然是正确地，这说明该统计模型有一定的泛化能力，能处理一些其他行业的文本。

   



