HMM(隐马尔可夫)在中文分词中的应用

中文分词,就是给一个汉语句子作为输入,以“BEMS”组成的序列串作为输出,然后再进行切词,进而得到输入句子的划分。其中,B代表该字是词语中的起始字,M代表是词语中的中间字,E代表是词语中的结束字,S则代表是单字成词。
HMM简介
给定一个句子:

小明昨天去游泳馆学游泳了

得到BEMS组成的序列为

BEBESBMESBES

因为句尾只可能是E或者S,所以得到切词方式为

BE/BE/S/BME/S/BE/S
小明/昨天/去/游泳馆/学/游泳/了

五元组:

状态集合Q={B,E,M,S}

观测集合V={词典中的字}

观测序列O={小,明,昨,天,去,游,泳,馆,学,游,泳,了}

初始概率分布π:句子的第一个字属于{B,E,M,S}这四种状态的概率(假设句子第一个字属于B的概率为0.6,第一个字属于S的概率为0.4)π=(0.6, 0,0, 0.4)T

状态转移概率分布A:如果前一个字位置是B,那么后一个字位置为BEMS的概率各是多少(4x4矩阵)
在这里插入图片描述

观测概率矩阵B:在状态B的条件下,观察值为某个字的概率
在这里插入图片描述

HMM进行中文分词,属于解码问题,即已知模型(π,A,B)和观测序列O,求对给定观测序列最大的状态序列I(给定观测序列,求最有可能的状态序列)。
使用Viterbi算法
观测序列值是Viterbi的输入,而状态序列值是Viterbi的输出,输入和输出之间Viterbi算法还需要借助三个模型参数,分别是初始状态概率(π), 状态转移概率(A), 观测概率(B)。

def viterbi(pi, A, B, O):
    O = O.strip()
    O_len = len(O)
    pi_len = len(pi)
    if O_len == 0:
        return
    # 保存所有状态的最大值是由哪一个状态产生的也就是计算δ[t](i)时,是由哪一个δ[t-1](q)产生的,q就是哪个状态
    states = np.full(shape=(O_len, pi_len), fill_value=0.0)
    # 保存计算过所有的计算的δ
    deltas = np.full(shape=(O_len, pi_len), fill_value=0.0)
    # 初始化计算最优P(I,O1) = max{P(O1|I)*p(I)}
    for j in range(0, pi_len):
        deltas[0][j] = pi[j] + B[j][ord(O[0])]  # 变加法是因为取了对数
    # dp计算P(I|O1,O2,O3,...Ot,I1,I2...It-1)
    for t in range(1, O_len):
        for i in range(0, pi_len):  # 计算每一个δ[t](i=q1...q[pi_len]) = max{δt[j]*A[ji]*B[qi|Ot]},j是遍历所有状态
            deltas[t][i] = deltas[t - 1][0] + A[0][i]
            # 寻找最大的δ[t](i)
            for j in range(1, pi_len):
                current = deltas[t - 1][j] + A[j][i]
                if current > deltas[t][i]:
                    deltas[t][i] = current
                    # 保存当前δ[t](i)取得最大值是是从上一个哪个状态来的
                    states[t][i] = j
            deltas[t][i] += B[i][ord(O[t])]
    # 回溯找到最优概率路径
    max1 = deltas[O_len - 1][0]
    best_state = np.zeros(O_len)
    # 先找出最后一个观测的最可能状态是什么
    for i in range(1, pi_len):
        if deltas[O_len - 1][i] > max1:
            max1 = deltas[O_len - 1][i]
            best_state[O_len - 1] = i
    # 由最后一个观测得到的最好状态往前回溯找出状态序列
    for i in range(O_len - 2, -1, -1):
        best_state[i] = states[i + 1][int(best_state[i + 1])]
    return best_state

猜你喜欢

转载自blog.csdn.net/liusisi_/article/details/108352173