HMM(隐马尔可夫模型)是用来描述隐含未知参数的统计模型,是一个关于时序的概率模型,它描述了一个由隐藏的马尔可夫链生成状态序列,再由状态序列生成观测序列的过程。其中,状态之间的转换以及观测序列和状态序列之间都存在一定的概率关系。
任何一个HMM都可以通过下列五元组来描述:
:param obs:观测序列
:param states:隐状态
:param start_p:初始概率(隐状态)
:param trans_p:转移概率(隐状态)
:param emit_p: 发射概率 (隐状态表现为显状态的概率)
而Viterbi算法是解决隐马第三问题(求观察序列的最可能标注序列)。
算法通过已知的可以观察到的序列,和一些已知的状态转换之间的概率情况,通过综合状态之间的转移概率和前一个状态的情况计算出概率最大的状态转换路径,从而推断出隐含状态的序列的情况。
维基百科动态图表示Viterbi算法过程
一个简单问题
问题描述
隐含的身体状态 = { 健康 , 发烧 }
可观察的感觉状态 = { 正常 , 冷 , 头晕 }
月儿预判的阿驴身体状态的概率分布 = { 健康:0.6 , 发烧: 0.4 }
月儿认为的阿驴身体健康状态的转换概率分布 = {健康->健康: 0.7 ,健康->发烧: 0.3 ,发烧->健康:0.4 ,发烧->发烧: 0.6}
月儿认为的在相应健康状况条件下,阿驴的感觉的概率分布 = {健康,正常:0.5 ,冷 :0.4 ,头晕: 0.1 ;发烧,正常:0.1 ,冷 :0.3 ,头晕: 0.6 }
阿驴连续三天的身体感觉依次是: 正常、冷、头晕 。
利用五元组来描述问题
1 states = ('Health', 'Fever')
2 observations = ('normal', 'cold', 'dizzy')
3 start_probability = {'Health': 0.6, 'Fever': 0.4}
4 transition_probability = {
5'Health' : {'Health': 0.7, 'Fever': 0.3},
6'Fever' : {'Health': 0.4, 'Fever': 0.6},
7 }
8 emission_probability = {
9'Health' : {'normal': 0.5, 'cold': 0.4, 'dizzy': 0.1},
10'Fever' : {'normal': 0.1, 'cold': 0.3, 'dizzy': 0.6},
11 }
代码实现Viterbi 算法
1import numpy
2def Viterbi () :
3#已知条件 4 states = ('Health', 'Fever')
5 observations = ('normal', 'cold', 'dizzy')
6 start_probability = {'Health': 0.6, 'Fever': 0.4}
7 transition_probability = {
8'Health' : {'Health': 0.7, 'Fever': 0.3},
9'Fever' : {'Health': 0.4, 'Fever': 0.6},
10 }
11 emission_probability = {
12'Health' : {'normal': 0.5, 'cold': 0.4, 'dizzy': 0.1},
13'Fever' : {'normal': 0.1, 'cold': 0.3, 'dizzy': 0.6},
14 }
15 day = 3
16 s = len(states)
17 V = []
1819 Wether = []
20 Temp = []
21#求解初始状态可能22for j in list(range(s)):
23 Temp.append(start_probability.get(states[j]) * emission_probability.get(states[j])[observations[0]])
24 V.append(Temp)
25#根据初始状态求解26 Wether.append(states[V[0].index(max(V[0]))]);
2728#求解第2 - day 状态转换概率29 prob = []
30for d in [i + 1 for i in list(range( day - 1))]:
31 prob = []
32 pp = -1
33for j in list(range(s)):
34 Temp = []
35for k in list(range(s)):
36 np = V[d-1][j] * transition_probability.get(states[j])[states[k]] * emission_probability.get(states[k])[observations[d]]
37 Temp.append(np)
38#记录路径39if np > pp:
40 m1 = j
41 m2 = k
42 pp = np
43 prob.append(Temp)
4445print('Compute_Probability:')
46print(prob)
47 Wether.append(states[m2])
48 V.append(prob[m1])
49print('Large_One:')
50print(prob[m1])
5152print(V)
53print(Wether)
5455if__name__ == '__main__':
56 Viterbi()
结果截图