用python实现新词发现程序基于凝固度和自由度

12次阅读

共计 1448 个字符,预计需要花费 4 分钟才能阅读完成。

互联网时代,信息产生的数量和传递的速度非常快,语言文字也不断变化更新,新词层出不穷。一个好的新词发现程序对做 NLP(自然预言处理)来说是非常重要的。

N-Gram 加词频

最原始的新词算法莫过于 n -gram 加词频了。简单来说就是,从大量语料中抽取连续的字的组合片段,这些字组合片段最多包含 n 个字,同时统计每个字组合的频率,按照词频并设置一个阈值来判断一个字组合片段是否为词汇。

该方法简单处理速度快,它的缺点也很明显,就是会把一些不是词汇但出现频率很高的字组合也当成词了。

凝固度和自由度

这个算法在文章《互联网时代的社会语言学:基于 SNS 的文本数据挖掘》里有详细的阐述。

凝固度就是一个字组合片段里面字与字之间的紧密程度。比如“琉璃”、“榴莲”这样的词的凝固度就非常高,而“华为”、“组合”这样的词的凝固度就比较低。

自由度就是一个字组合片段能独立自由运用的程度。比如“巧克力”里面的“巧克”的凝固度就很高,和“巧克力”一样高,但是它自由运用的程度几乎为零,所以“巧克”不能单独成词。

Python 实现

根据以上阐述,算法实现的步骤如下:

  1. n-gram 统计字组合的频率

如果文本量很小,可以直接用 Python 的 dict 来统计 n -gram 及其频率。一段文本 n -gram 出来的字组合的大小大约是原始文本的(1+n)*n/ 2 倍,字组合的数量也非常惊人。比如,“中华人民共和国”的首字 n -gram 是(n=5):

中
中华
中华人
中华人民
中华人民共

n-gram 统计字组合频率的同时还要统计字组合的左右邻居,这个用来计算自由度。

如果文本量再大一些,Python 的 dict 经常会碰到最好使用 trie tree 这样的数据结构。双数组 Trie Tree 有很多非常好的开源实现,比如,cedar、darts 等等。Trie Tree 使用的好处是,它天然包含了字组合的右邻居信息,因为这个数据结构一般是前缀树。要统计左邻居信息时,只需要把字组合倒序放入另外一个 Trie Tree 即可。
使用 cedar Trie Tree 的时候,5-gram 统计 30M 的文本大约使用 6GB 左右的内存。

如果文本量更大,这就要借助硬盘了,可以使用 leveldb 这样的 key-value 数据库来实现。实验下来,trie tree 统计 30M 的文本用几十秒,而同样的用 leveldb 统计却要 6 个多小时!!!应该还有比 leveldb 更合适的数据库来做这件事情,有时间再说。
当然,为了发现新词,几十 MB 的文本文本足够了。

  1. 计算字组合的凝固度;

有了上述的统计结果,计算每个字组合的凝固度就比较简单了。
首先,把字组合切分成不同的组合对,比如’abcd’可以拆成 (‘a’,‘bcd’), (‘ab’,‘cd’), (‘abc’,‘d’),
然后,计算每个组合对的凝固度:D(s1, s2) = P(s1s2) / (P(s1) * P(s2))
最后,取这些组合对凝固度中最小的那个为整个字组合的凝固度。

  1. 计算字组合的自由度;

分别计算它的左邻居信息熵和右邻居信息熵,取其中较小的为该组合的自由度。

  1. 阈值的选择

整个过程涉及到三个阈值的选择:

组合的词频:频率很低的组合成词的可能性很小
组合的凝固度:凝固度越大成词的可能性越大
组合的自由度:自由度越大成词的可能性越大
经验值:30M 文本,词频 >200, 凝固度 >10**(n-1), 自由度 >1.5

小窍门:词频 >30, 凝固度 >20**(n-1)也能发现很多低频的词汇。

文章来源于:猿人学网站的 python 教程。

版权申明: 若没有特殊说明,文章皆是猿人学原创,没有猿人学授权,请勿以任何形式转载。

正文完
 0