# 基于备选片段的方法

## 文本片段

新词作为未登录词, 使用分词工具, 只能划分出已登录的词汇, 如果将剩余未匹配部分作为新词, 结果并不可靠. 所以我们绕开现成的分词工具, 在大规模语料中提取出**可以划分为词的文本片段**, 将这些文本片段作为词, 再与已有词库进行比较, 就可以找到新词了.

下一步, 要定义**怎样的文本片段才算词**?

## 何以为词

这里定义文本片段为词, 需要满足以下几个条件.

### 出现的次数是否足够多

即文本片段出现**频数**超过某个阈值. 只有使用比较广泛, 才能被作为词汇使用.

### 词的内部凝固程度高

一个经常出现的文本片段有可能不是一个词, 而是多个词构成的词组. 例如`电影`和`电影院`都是词, 但`电影院`出现的次数肯定是小于`电影`的. 我们倾向于把`电影院`作为一个词, 是因为直觉上看`电影`和`院`之间具有很高的**凝固度**.

如何定义词内部的凝固度? 从概率的角度出发, 如果`电影`和`院`是各自独立地在文本中随机出现, 它们恰好拼在一起出现的概率, 就应该为P(`电影`) *P(`院`), 但事实上, `电影院`这个文本片段出现的概率P(`电影院`)(出现概率 = 出现频数 / 总字数)是远大于前值的. 而`的电影`出现的概率应当是约等于P(`的`)* P(`电影`).

因此对于一个文本片段内部的凝固度, 使用**互信息**(MI)来定义:

$$
\begin{aligned}
\text{MI}(a,b) &= \frac{P(a,b)}{P(a)P(b)} \\
&= \frac{N \cdot #(a,b)}{#a \cdot #b}
\end{aligned}
$$

a, b分别表示两个字/子序列, (a, b)为两者连在一起组成的序列. $$#(\cdot)$$表示序列出现的频数. 在计算出现概率时, 不管`n-gram`中的`n`为多少, 序列的总数量与`unigram`相差数量为$$n-1$$, 可以忽略不计, 因此在计算时都使用单字的总数量$$N$$即可.

对于多于两个字的序列, 将其切分为两个子序列时就有不同的切法. 因此在计算时, 需要遍历所有切分方法, 对所有的方案计算对应的互信息, 然后取其中的**最小值**作为这个序列的互信息值.

在实际工程中, 对于计算过程中使用到的概率最好**取对数**之后再存储使用, 主要考虑到:

* 避免概率过低造成下溢出
* 将取值范围映射到更平滑的区间中

### 词的外部自由度高

除了内部的凝聚力, 还需要关注词的外部表现. 例如`被子`和`辈子`两个文本片段, 对于`被子`, 可以有`买被子`, `盖被子`, `这被子`, `进被子`, `好被子`等很多表达, 但`辈子`只有`一辈子`, `这辈子`, `上辈子`, `下辈子`等比较固定的用法. 所以`被子`成词和合理的, 但`辈子`单独成词就不合理了. 可见, **文本片段的自由运用程度也是判断它是否成词的重要标准**, 如果一个文本片段能够算作一个词的话, 它应该能够灵活地出现在各种不同的环境中, **具有非常丰富的左邻字集合和右邻字集合**.

这里使用**信息熵**来衡量文本片段的左邻字集合和右邻字集合的随机程度, 而信息熵直观地反映了一个事件的结果有多么的随机, 熵越大, 随机程度越大.

以**吃葡萄不吐葡萄皮不吃葡萄倒吐葡萄皮**为例, `葡萄`一词出现了四次, 其左邻字分别为`{吃, 吐, 吃, 吐}`, 右邻字分别为`{不, 皮, 倒, 皮}`, 则`葡萄`一词的左邻字的信息熵为$$-\frac{1}{2}\log(\frac{1}{2}) - \frac{1}{2}\log(\frac{1}{2}) \approx 0.693$$, 右邻字的信息熵为$$-\frac{1}{2}\log(\frac{1}{2}) - \frac{1}{4}\log(\frac{1}{4}) - \frac{1}{4}\log(\frac{1}{4}) \approx 1.04$$. `葡萄`一词的右邻字更为丰富, 对应的右邻字的信息熵也更大些.

一个文本片段是否能**单独成词**, 要求它的左右邻信息熵都要足够随机, 都要具有非常丰富的相邻字集合. 因此, 可以把**一个文本片段的自由运用程度定义为它的左邻字信息熵和右邻字信息熵中的较小值**.

## 代码实现

文本片段能够成词, 其凝固程度和自由程度, 两种判断标准缺一不可. 只看凝固程度的话, 会找出`巧克`, `俄罗`, `颜六色`等实际词的片段; 只看自由程度的话, 会把`吃了一顿`, `看了一遍`, `睡了一晚`, `去了一趟`中的`了一`判别为词, 因为它的左右邻字都太丰富了.

凝固程度和自由程度的阈值, 都要根据实际的语料调参确定. 不同语料的合适阈值差别很大.

代码实现可以参考: [新词发现的信息熵方法与实现](https://kexue.fm/archives/3491).

## 参考资料

* [互联网时代的社会语言学：基于SNS的文本数据挖掘](http://www.matrix67.com/blog/archives/5044)
* [新词发现的信息熵方法与实现](https://kexue.fm/archives/3491)
