## 目录
- [7. 词性标注](#7-词性标注)
- [7.1 词性标注概述](#71-词性标注概述)
- [7.2 词性标注语料库与标注集](#72-词性标注语料库与标注集)
- [7.3 基于隐马尔可夫模型的词性标注](#73-基于隐马尔可夫模型的词性标注)
- [7.4 基于感知机的词性标注](#74-基于感知机的词性标注)
- [7.5 基于条件随机场的词性标注](#75-基于条件随机场的词性标注)
- [7.6 词性标注评测](#76-词性标注评测)
- [7.7 自定义词性](#77-自定义词性)

## 7. 词性标注

### 7.1 词性标注概述

1. **什么是词性**

   在语言学上，**词性**(Par-Of-Speech, Pos )指的是单词的语法分类，也称为词类。同一个类别的词语具有相似的语法性质，所有词性的集合称为词性标注集。不同的语料库采用了不同的词性标注集，一般都含有形容词、动词、名词等常见词性。下图就是HanLP输出的一个含有词性的结构化句子。

   ```
   我/r 的/u 希望/n 是/v 希望/v 张晚霞/nr 的/u 背影/n 被/p 晚霞/n 映/v 红/a
   ```

   每个单词的后边跟的就是词性标签:

   | 词性标签 | 词性   |
   | -------- | ------ |
   | r        | 代词   |
   | u        | 动词   |
   | n        | 名词   |
   | v        | 动词   |
   | nr       | 人名   |
   | p        | 介词   |
   | a        | 形容词 |

   

2. **词性的用处**

   词性的作用是提供词语的抽象表示，词的数量是无穷的，但词性的数量是有限的。词性支撑着许多高级应用，当下游应用遇到 OOV 时，可以通过 OOV 的词性猜测用法，比如上面的句子“林晚霞”就识别为人名进行处理，而不会拆开。

   词性也可以直接用于抽取一些信息，比如抽取所有描述特定商品的形容词等。

   

3. **词性标注**

   **词性标注**指的是为句子中每个单词预测一个词性标签的任务。它有以下两个难点:

   - 汉语中一个单词多个词性的现象很常见，但在具体语境下一定是唯一词性。

   - OOV 是任何自然语言处理任务的难题。

     

4. **词性标注模型**

   统计方法为这两个难点提供了解决方案，那就是我们熟悉的**序列标注模型**。只需将中文分词中的汉字替换为词语，{B,M,E,S} 替换为“名词、动词、形容词等”，序列标注模型马上就可以用来做词性标注。

   词性标注既可以看作中文分词的后续任务，也可以与中文分词集成为同一个任务。其中就可以把分词语料库加上词性标签就可以了，这样同时进行多个任务的模型称为**联合模型**。由于综合考虑了多种监督信号，联合模型在几乎所有问题上都要优于独立模型。

   然而工业界就没有那么理想，同时具有分词和词性标注的语料库非常少，需要大量的人力进行标注。



### 7.2 词性标注语料库与标注集

同中文分词一样，语言学界在标注规范上存在分歧，导致目前还没有一个被广泛接受的汉语词性划分标准。无论是词性划分的颗粒度，还是词性标签都不统一。一方面，各研究机构各持己见、派系林立，标注了大量互不兼容的语料库。另一方面，部分语料库受到严格版权控制，成为内部材料，得不到充分共享利用。

本节选取其中一些授权宽松， 容易获得的语料库作为案例。

以下示例我们选取 PKU 标注的《人民日报》语料库的标注集。



### 7.3 基于隐马尔可夫模型的词性标注

之前我们就介绍过隐马尔可夫模型，详细见: [4.隐马尔可夫模型与序列标注](https://github.com/NLP-LOVE/Introduction-NLP/blob/master/chapter/4.%E9%9A%90%E9%A9%AC%E5%B0%94%E5%8F%AF%E5%A4%AB%E6%A8%A1%E5%9E%8B%E4%B8%8E%E5%BA%8F%E5%88%97%E6%A0%87%E6%B3%A8.md)

隐马尔可夫模型词性标注代码见(**程序会自动下载 PKU 语料库**): hmm_pos.py

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

运行代码后结果如下:

```
一阶隐马尔可夫模型:
r, u, n, v, v, v
他/r 的/u 希望/n 是/v 希望/v 上学/v
他/代词 的/助词 希望/名词 是/动词 希望/动词 上学/动词
李狗蛋/动词 的/动词 希望/动词 是/动词 希望/动词 上学/动词

二阶隐马尔可夫模型:
r, u, n, v, v, v
他/r 的/u 希望/n 是/v 希望/v 上学/v
他/代词 的/助词 希望/名词 是/动词 希望/动词 上学/动词
李狗蛋/动词 的/动词 希望/动词 是/动词 希望/动词 上学/动词
```

可见隐马尔可夫模型成功的辨别出“希望”的两种词性 n 和 v。但 OOV问题就出现了，无法把“李狗蛋”识别成人名，隐马尔可夫模型一步走错满盘皆输，其根本原因在于隐马尔可夫模型只能利用单词这一个状态特征，无法通过姓氏“李”来推测“李狗蛋”是人名。



### 7.4 基于感知机的词性标注

之前我们就介绍过感知机模型，详细见: [5.感知机分类与序列标注](https://github.com/NLP-LOVE/Introduction-NLP/blob/master/chapter/5.%E6%84%9F%E7%9F%A5%E6%9C%BA%E5%88%86%E7%B1%BB%E4%B8%8E%E5%BA%8F%E5%88%97%E6%A0%87%E6%B3%A8.md)

按照中文分词时的经验，感知机能够利用丰富的上下文特征，是优于隐马尔可夫模型的选择，对于词性标注也是如此。

感知机模型词性标注代码见(**程序会自动下载 PKU 语料库**): perceptron_pos.py

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

运行会有些慢，结果如下:

```
李狗蛋/nr 的/u 希望/n 是/v 希望/v 上学/v
李狗蛋/人名 的/助词 希望/名词 是/动词 希望/动词 上学/动词
```

这次的运行结果完全正确，感知机成功的识别出 OOV “李狗蛋”的词性。



### 7.5 基于条件随机场的词性标注

之前我们就介绍过条件随机场模型，详细见: [6.条件随机场与序列标注](https://github.com/NLP-LOVE/Introduction-NLP/blob/master/chapter/6.%E6%9D%A1%E4%BB%B6%E9%9A%8F%E6%9C%BA%E5%9C%BA%E4%B8%8E%E5%BA%8F%E5%88%97%E6%A0%87%E6%B3%A8.md)

条件随机场模型词性标注代码见(**程序会自动下载 PKU 语料库**): crf_pos.py

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

运行时间会比较长，结果如下:

```
李狗蛋/nr 的/u 希望/n 是/v 希望/v 上学/v
李狗蛋/人名 的/助词 希望/名词 是/动词 希望/动词 上学/动词
```

依然可以成功识别 OOV “李狗蛋”的词性。



### 7.6 词性标注评测

将 PKU 语料库按 9:1 分隔为训练集和测试集，分别用以上三种模型来训练，准确率如下:

| 算法               | 准确率 |
| ------------------ | ------ |
| 一阶隐马尔可夫模型 | 44.99% |
| 二阶隐马尔可夫模型 | 40.53% |
| 结构化感知机       | 83.07% |
| 条件随机场         | 82.12% |

从上图可知，结构化感知机和条件随机场都要优于隐马尔可夫模型，判别式模型能够利用更多的特征来进行训练，从而提高更多的精度。



### 7.7 自定义词性

在工程上，许多用户希望将特定的一些词语打上自定义的标签，称为**自定义词性**。比如，电商领域的用户希望将一些手机品牌打上相应标签，以便后续分析。HanLP 提供了自定义词性功能。具体有两种实现。

1. **朴素实现**

   可以使用HanLP挂载的方式实现:

   ```python
   from pyhanlp import *
   
   CustomDictionary.insert("苹果", "手机品牌 1")
   CustomDictionary.insert("iPhone X", "手机型号 1")
   analyzer = PerceptronLexicalAnalyzer()
   analyzer.enableCustomDictionaryForcing(True)
   print(analyzer.analyze("你们苹果iPhone X保修吗？"))
   print(analyzer.analyze("多吃苹果有益健康"))
   ```

   当然，此处以代码的方式插入自定义词语，在实际项目中也可以用词典文件的方式，运行效果如下:

   ```
   你们/r 苹果/手机品牌 iPhone X/手机型号 保修/v 吗/y ?/w
   多/ad 吃/v 苹果/手机品牌 有益健康/i
   ```

   从结果来看，词典只是机械的匹配，将“吃苹果”也当成了手机品牌，犯了所有规则系统的通病，看来词典同样解决不了词性标注，词性标注还是应当交给统计方法。

   

2. **标注语料**

   词性的确定需要根据上下文语境，这恰好是统计模型所擅长的。为了实现自定义词性，最佳实践是标注一份语料库，然后训练一个统计模型。

   至于语料库规模，与所有机器学习问题一样，数据越多，模型越准。






