viterbi-algorithm 维特比算法的例子解析
維特比算法的目的:
尋找最可能的隱藏狀態序列(Finding most probable sequence of hidden states)
關于原理的講解可以參考下面兩篇文章,講的比較清楚
小白給小白詳解維特比算法1.
小白給小白詳解維特比算法2.
本文通過分析維特比算法的例子,來學習該算法
2.定義初始化狀態
# 路徑概率表 V[時間][隱狀態] = 概率V = [{}]# 一個中間變量,代表當前狀態是哪個隱狀態path = {}# 初始化初始狀態 t=0for y in states:V[0][y] = start_p[y] * emit_p[y][obs[0]]path[y] = [y]V[時間][天氣] = 概率
觀測序列(observations)得到的結果 觀測對象第一天是散步
計算第一天的天氣:
V[第一天][天晴] = 初始概率[天晴] * 發射概率[散步] = 0.4 * 0.6 = 0.24
V[第一天][下雨] = 初始概率[下雨] * 發射概率[散步] = 0.6 * 0.1 = 0.06
計算結果可見,第一天天晴的概率比較大。
此時初始的路徑 path = {}
第二天: 由觀測序列可得 observations[1] = ‘購物’
① 首先看計算第二天下雨的概率
- V[第二天][下雨] = V[第一天][下雨] * 轉移概率[下雨][下雨] * 發射概率[下雨][購物] = 0.06 * 0.7 * 0.4 = 0.0168
- V[第二天][下雨] = V[第一天][天晴] * 轉移概率[天晴][下雨] * 發射概率[下雨][購物] = 0.24 * 0.4 * 0.4 = 0.0384
同樣在這里取最大概率
V[第二天][下雨] = 0.0384
得到的新路徑 newpath[下雨] = [晴天,下雨]
②然后計算第二天天晴的概率
- V[第二天][天晴] = V[第一天][下雨] * 轉移概率[下雨][天晴] * 發射概率[天晴][購物] = 0.06 * 0.3 * 0.3 = 0.0054
- V[第二天][天晴] = V[第一天][天晴] * 轉移概率[天晴][天晴] * 發射概率[天晴][購物] = 0.24 * 0.6 * 0.3 = 0.0432
V[第二天][天晴] = 0.0432
得到的新路徑 newpath[晴天] = [晴天,晴天]
第二天計算完成之后得到前兩天的路徑
paht={雨天:[晴天,下雨],晴天:[晴天,晴天]}
以同樣的方式得到第三天的結果
observations[1] = 打掃
- V[第三天][下雨] = V[第二天][下雨] * 轉移概率[下雨][下雨] * 發射概率[下雨][打掃] = 0.0384 * 0.7 * 0.5 = 0.01344
- V[第三天][下雨] = V[第二天][天晴] * 轉移概率[天晴][下雨] * 發射概率[下雨][打掃] = 0.0432 * 0.4 * 0.5 = 0.00864
V[第三天][下雨] = 0.01344
newpath[下雨] = [晴天,下雨,下雨] - V[第三天][天晴] = V[第二天][下雨] * 轉移概率[下雨][天晴] * 發射概率[天晴][打掃] = 0.0384* 0.3 * 0.1 = 0.001152
- V[第三天][天晴] = V[第二天][天晴] * 轉移概率[天晴][天晴] * 發射概率[天晴][打掃] = 0.0432 * 0.6 * 0.1 = 0.002592
V[第三天][天晴] = 0.002592
newpath[晴天] = [晴天,晴天,晴天]
把得到的newpath賦值給path
最后通過找出V[第三天]中天氣最大的那個概率得到天氣的情況
因此第三天的天氣為V[第三天][下雨] = 0.01344
由此可反推得到路徑path[下雨] = [晴天,下雨,下雨]
圖形表示如下,第二天之后的天氣概率計算后取最大值,根據第三天天氣的最大概率再反推天氣的路徑
上面就是維特比算法實現的詳解,下面是完整代碼。
# -*- coding:utf-8 -*- # @Time :2019/5/27 15:30 # @author :ding # @filename :vertibi.py""" 維特比算法的實現 HMM 五個重要元素 S 隱藏序列的集合 K 輸出狀態或觀測狀態的集合 π對應隱藏狀態的的初始概率 A 隱藏狀態的轉移概率 是一個N*M的概率矩陣 B 影廠狀態到觀測狀態的混淆矩陣,是一個N*M的發射概率的矩陣 """# 隱藏序列 S states = ("Rainy", "Sunny")# 觀測序列 K observations = ('walk', 'shop', 'clean')# 初始概率 π start_probability = {'Rainy': 0.6, "Sunny": 0.4}# 轉移概率 A transition_probability = {'Rainy': {"Rainy": 0.7, "Sunny": 0.3},"Sunny": {"Rainy": 0.4, "Sunny": 0.6} }# 發射概率 B emission_probability = {"Rainy": {"walk": 0.1, "shop": 0.4, "clean": 0.5},"Sunny": {"walk": 0.6, "shop": 0.3, "clean": 0.1}, }def print_dptable(V):print(" ")for i in range(len(V)): print("%7d" % i, end="")print()for y in V[0].keys():print("%.5s: " % y, end=" ")for t in range(len(V)):print("%.7s" % V[t][y], end=" ")print()def vierbi(obs, states, start_p, trans_p, emit_p):""":param obs: 觀察序列 K:param states: 隱藏狀態 S:param start_p: 初始概率 π:param trans_p: 轉移概率 A:param emit_p: 發射概率 B:return:"""# 路徑概率表 V[時間][隱狀態] = 概率V = [{}]# 一個中間變量,代表當前狀態是哪個隱狀態path = {}# 初始化初始狀態 t=0for y in states:V[0][y] = start_p[y] * emit_p[y][obs[0]]path[y] = [y]# 對t>0 跑一遍維特比算法for t in range(1, len(obs)):V.append({})newpath = {}for y in states:# 概率 隱狀態 = 前狀態是y0的概率 * y0轉移到y的概率 * y表現為當前狀態的概率(prob, state) = max([(V[t - 1][y0] * trans_p[y0][y] * emit_p[y][obs[t]], y0) for y0 in states])# 記錄最大概率V[t][y] = prob# 記錄路徑newpath[y] = path[state] + [y]# 不需要保存舊路徑path = newpathprint_dptable(V)(prob, state) = max([(V[len(obs) - 1][y], y) for y in states])return prob, path[state]def test():return vierbi(observations,states,start_probability,transition_probability,emission_probability)print(test())打印結果如下
維特比算法在NLP方面有很多的應用
- 詞性標注:給定一個詞的序列,找出最可能的詞性序列
- 分詞:給定一個字的序列,找出最可能的標簽序列,可利用BMES這些標簽來分詞B(開頭)M(中間詞)E(結尾)S(單個詞)
- 明明實體識別:給定一個詞的序列,找出最可能的標簽序列
本文講的可能不是很清楚,有不對的地方,還請不吝指教。
總結
以上是生活随笔為你收集整理的viterbi-algorithm 维特比算法的例子解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【BZOJ】3698:XWW的难题-上下
- 下一篇: 分享15款漂亮的WordPress企业主