finalseg 的作用
对于非登录词问题,jieba 使用 HMM 和 Viterbi 算法来解决。如果不采用解决方法,所有非登录词就会以字为单位进行分割,这显然是不合理的。在代码中具体的做法是:用一个变量buf
来记录非登录词,然后用finalseg.cut()
进行切割。
隐马尔可夫模型(HMM)
隐马尔可夫模型是一种用来序列建模的方法。为了了解它,我们需要熟知几个概念:
- 马尔可夫假设:随机过程中各个状态 \(S_t\) 的概率分布,只与它的前一个状态 \(S_{t-1}\) 有关
- 马尔可夫链:符合马尔可夫假设的随机过程为马尔可夫过程,也称马尔可夫链
- 隐马尔可夫链:马尔可夫链的扩展。在隐马尔可夫链中,状态 \(S_t\) 是不可见的,但每一个时刻 \(t\) 为输出 \(O_t\),\(O_t\) 和 \(S_t\) 相关且仅和 \(S_t\) 相关
隐马尔可夫模型有三个基本问题:
- 给定模型,如何计算某个特定的输出序列的概率?Forward-Backward 算法
- 给定模型和某个特定的输出序列,如何找到最可能产生这个输出的状态序列?Viterbi 算法
- 给定足够的观测数据,如何估计隐马尔可夫模型的参数?Baum-Welch 算法
对于 jieba 分词系统,HMM 中的序列状态空间为 \(\{B, M, E, S\}\),分别表示字在开头、字在中间、字在结尾以及独立成词。对于 HMM 模型的几种要用到的概率值:开始状态概率、状态转移概率以及发射概率分别存在文件prob_start.py
、prob_trans.py
以及prob_emit.py
中。为了防止概率值出现 0,jieba 做了对数变换,0 概率表示成了 -3.14e+100(接近负无穷)。
现在问题转换为我们已经知道了输出序列(即非登录词),要知道最可能的状态序列,因此我们需要使用 Viterbi 算法。
Viterbi 算法
Viterbi 算法本质上是一种动态规划算法。其在每一步的所有选择都保存了前续所有步骤到当前步骤当前选择的最小总代价(或者最大价值)以及当前代价的情况下前继步骤的选择。在依次计算完所有步骤后,Viterbi 算法可通过回溯的方法找到最优选择路径。
根据 Viterbi 算法,可以得到概率最大的状态序列,然后通过规则就可以得到非登录词的切割结果。