分词的做法有很多种,最简单粗暴的方法就是依照《中华汉语词典》,从左到右依次判断词是否在词典中,不过这种方法有可能会产生分词歧义,比如说:
结婚/的/和/尚未/结婚/的
结婚/的/和尚/未/结婚/的
现在已经有许多解决这个问题的方法,jieba分词是目前比较流行的一个分词工具.使用非常简单:
import jieba
seg_list = jieba.cut("结婚的和尚未结婚的")
print("/ ".join(seg_list))
结婚/的/和/尚未/结婚/的
下面来介绍一下jieba分词的工作原理.
结巴分词内部有一个dict.txt文件里面存储着这样一些信息:
单词 | 词频 | 词性 |
---|---|---|
的 | 3188252 | uj |
了 | 883634 | ul |
是 | 796991 | v |
在 | 727915 | p |
和 | 555815 | c |
有 | 423765 | v |
他 | 401339 | r |
... | ... | ... |
这个字典是作者通过大量文本数据(60101967个词)统计出的结果,其中的词频指的是该单词在这些文本中出现的次数.
jieba分词会依照这个字典,将出现在词典中的词生成一个无向图DAG:
根据字典我们就可以计算出无向图中每个单词出现的概率:
那么如何确定用哪个分支呢?这里需要用到概率的知识,越可能发生的概率越大,例如:
所以"结婚"应该被切分为一个词.依照这个原理计算整个句子所有路径上的联合概率,然后找到最大的联合概率为:
这就是最终的分词结果.
互联网中经常会出现很多网红词,比如最近的"佛系青年",“食草男”.这些词并不在词典中,被称为未登录词,前面写过一篇文章信息熵在新词发现中的运用利用简单的概率知识就可以识别这种新词,不过jieba分词并没有采用这种方法,而是用更为强大的隐马尔科夫模型进行新词发现.
对于未登录词,词典中没有,所以使用上述方法会被分为单字词,还是上面的例子:
结婚/的/和/尚未/结婚/的
对于jieba分词来说,这里的连续单字词"的和"就很有可能是一个新词,会被送入隐马尔科夫模型来做进一步的识别.
实际上当我们把dict.txt中的词语全部删除,jieba依然能够进行分词,其实这个时候使用的就是HMM来进行分词了。
马尔科夫模型用来分词时,使用BMES,作为每个字的状态,B代表词头,M代表词中,E代表词尾词,S代表单个字的词.根据预先训练好的起始状态,转移概率和观测概率,就可以估计出每个单词状态:
新词发现和分词同样的道理,估计每个字的隐状态就可以判断是否为一个词.