隱馬爾可夫HMM中viterbi算法


引言

viterbi算法簡化最有可能的天氣序列的運算過程,forward算法簡化該該觀察值的概率。

問題描述

你在中國,你朋友F在美國,F的作息有walk, shop, clean,但這選擇跟天氣有關,我們又知道Rainy的概率比Sunny的概率大
這是初始概率

這是天氣轉移矩陣

這是在相應天氣下發生相應事的概率分布
然后,F這三天是walk,walk,shop,問最有可能的天氣序列

問題分析

同樣的,我們先用窮舉法來算,即

Sunny Sunny Sunny 
Sunny Sunny Rainy
Sunny Rainy Sunny
Sunny Rainy Rainy
Rainy Sunny Sunny
Rainy Sunny Rainy
Rainy Rainy Sunny
Rainy Rainy Rainy

分 別求出在各個情況下,{walk,walk,shop}的概率,然后比較概率,最大的就是我們想要的結果,我們發現這跟我們forward的應用場景相 似,只不過,forward算法是求和,而viterbi算法是求最大,forward算法是所有路徑之和,而viterbi算法只是求一條路徑。這也就 意味着這兩算法可以寫在一起。

那我們重點講講算法吧,這次我是看wiki上的代碼,再寫,再比較,發現wiki上的代碼有一處甚是費解,因此,加以修改,並一目了然了,我把我的思考羅列如下

1)我的思路是把第一天的情況特殊考慮,可wiki上的代碼直接整合在一起了,其意義甚是費解,所以,我把第一天特殊考慮了

2)再者,我發現wiki上的代碼,明明要求只需要確定三天的天氣卻出現四天的天氣,估計是第一天沒用的

3)我修改后代碼跟wiki上代碼,forward算法最終結果是一樣的,但過程中求得值是不一樣的

4)用viterbi求得概率是不同的,但wiki上的代碼,把第一天去掉之后,剩下的天氣序列跟我的是一樣

不管怎樣,wiki上的代碼整體框架還是非常好的(或許還是我改錯了),思路如下:

1)我上一篇自己寫forward算法,差不多用二維數組來記錄整個過程,其實沒必要,只需一維足以,用完一行,替代一行,所以才會有字典T和字典U

2)返回三樣,分別是該觀察序列的最大概率(即之前用forward求出來的),最可能出現的天氣序列,該天氣序列的概率,同時每次都更新這三個值

3)三重for循環,第一重是第幾天,第二重是第幾天晴天還是雨天,第三重是前一天是晴天還是雨天下求得概率,再具體求和,求最大值

我稍加修改的Python代碼及結果

View Code
 1 def forward_viterbi(obs, states, start_p, trans_p, emit_p):
 2     T = {}
 3     #for the first one
 4     for state in states:
 5         T[state] = (start_p[state] * emit_p[state][obs[0]], [state], start_p[state])
 6     for output in obs:
 7         U = {}
 8         #pass the first one
 9         if output == obs[0]:
10             continue
11         for next_state in states:
12             total = 0
13             argmax = None
14             valmax = 0
15             for source_state in states:
16                 #get the previous one
17                 (prob, v_path, v_prob) = T[source_state]
18                 #caculate the commone one
19                 p = trans_p[source_state][next_state] * emit_p[next_state][output]
20                 prob *= p
21                 v_prob *= p
22                 #sum up
23                 total += prob
24                 #find the max
25                 if v_prob > valmax:
26                     argmax = v_path + [next_state]
27                     valmax = v_prob
28             U[next_state] = (total, argmax, valmax)
29         T = U
30     #sum up & find the max one
31     total = 0
32     argmax = None
33     valmax = 0
34     for state in states:
35         (prob, v_path, v_prob) = T[state]
36         total += prob
37         if v_prob > valmax:
38             valmax = v_prob
39             argmax = v_path
40     return (total, argmax, valmax)
41 states = ('Rainy', 'Sunny')
42 observations = ('walk', 'shop', 'clean')
43 start_probability = {'Rainy': 0.6, 'Sunny': 0.4}
44 transition_probability = {
45    'Rainy' : {'Rainy': 0.7, 'Sunny': 0.3},
46    'Sunny' : {'Rainy': 0.4, 'Sunny': 0.6},
47    }
48 emission_probability = {
49    'Rainy' : {'walk': 0.1, 'shop': 0.4, 'clean': 0.5},
50    'Sunny' : {'walk': 0.6, 'shop': 0.3, 'clean': 0.1},
51    }
52 #A simple example of the using algorithm
53 def example():
54     return forward_viterbi(observations,
55                            states,
56                            start_probability,
57                            transition_probability,
58                            emission_probability)
59 print example()
60 
61 #(0.033611999999999996, ['Rainy', 'Rainy', 'Rainy'], 0.05879999999999999)

 

wiki代碼及結果

View Code
 1 def forward_viterbi(obs, states, start_p, trans_p, emit_p):
 2     T = {}
 3     for state in states:
 4         ##          prob.           V. path  V. prob.
 5         T[state] = (start_p[state], [state], start_p[state])
 6     for output in obs:
 7         print T
 8         U = {}
 9         for next_state in states:
10             total = 0
11             argmax = None
12             valmax = 0
13             for source_state in states:
14                 (prob, v_path, v_prob) = T[source_state]
15                 p = emit_p[source_state][output] * trans_p[source_state][next_state]
16                 #caculate
17                 prob *= p
18                 v_prob *= p
19                 #the different way to gain
20                 total += prob
21                 if v_prob > valmax:
22                     argmax = v_path + [next_state]
23                     valmax = v_prob
24             U[next_state] = (total, argmax, valmax)
25         T = U
26     print T
27     ## apply sum/max to the final states:
28     total = 0
29     argmax = None
30     valmax = 0
31     for state in states:
32         (prob, v_path, v_prob) = T[state]
33         total += prob
34         if v_prob > valmax:
35             argmax = v_path
36             valmax = v_prob
37     return (total, argmax, valmax)
38    
39 states = ('Rainy', 'Sunny')
40 observations = ('walk', 'shop', 'clean')
41 start_probability = {'Rainy': 0.6, 'Sunny': 0.4}
42 transition_probability = {
43    'Rainy' : {'Rainy': 0.7, 'Sunny': 0.3},
44    'Sunny' : {'Rainy': 0.4, 'Sunny': 0.6},
45    }
46 emission_probability = {
47    'Rainy' : {'walk': 0.1, 'shop': 0.4, 'clean': 0.5},
48    'Sunny' : {'walk': 0.6, 'shop': 0.3, 'clean': 0.1},
49    }
50 #A simple example of the using algorithm
51 def example():
52     return forward_viterbi(observations,
53                            states,
54                            start_probability,
55                            transition_probability,
56                            emission_probability)
57 print example()
58 
59 #(0.033611999999999996, ['Sunny', 'Rainy', 'Rainy', 'Rainy'], 0.009407999999999998)

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM