实现1:有观测序列,发射概率,状态转移矩阵返回最佳路径
# --*--coding:utf-8--*--
import numpy as np
# 隐状态
hidden_state=['sunny','rainy']
# 观测序列
observation=['walk','shop','clean']
#根据观测序列,发射概率,状态转移矩阵返回最佳路径
def viterbi(obs,states,start_p,trans_p,emit_p):
'''
:param obs: 观测序列
:param states: 状态序列
:param start_p: 初始化状态序列的概率
:param trabs_p: 转移概率
:param emit_p: 发射概率
:return: 最佳路径
'''
# max_p为3*2的矩阵,每一列存储第一列不同隐状态的最大概率
max_p=np.zeros((len(obs),len(states)))
#path(2*3的矩阵),每一行存储max_p对应列的路径
path=np.zeros((len(states),len(obs)))
#初始化
for i in range(len(states)):
max_p[0][i]=start_p[i]*emit_p[i][obs[0]]
path[i][0]=i
for k in range(1,len(obs)):
newpath=np.zeros((len(states),len(obs)))
for v in range(len(states)):
prob=-1
for u in range(len(states)):
nprob=max_p[k-1][u]*trans_p[u][v]*emit_p[v][obs[k]]
if nprob>prob:
prob=nprob
state=u
#记录路径
max_p[k][v]=prob
for m in range(k):
newpath[v][m]=path[state][m]
newpath[v][k]=v
path=newpath
max_prob=-1
path_state=0
#返回最大概率的路径
for v in range(len(states)):
if max_p[len(obs)-1][v]>max_prob:
max_prob=max_p[len(obs)-1][v]
path_state=v
return path[path_state]
state_s=[0,1]
obser=[0,1,2]
# 初始状态,测试集中,0.6概率观测序列以sunny开始
start_probability=[0.6,0.4]
# 转移概率,0.7:sunny的下一天还是sunny的概率
transition_probability=np.array([[0.7,0.3],[0.4,0.6]])
# 发射概率,0.4:sunny条件下0.4的概率去shop
emit_probability=np.array([[0.1,0.4,0.5],[0.6,0.3,0.1]])
result=viterbi(obser,state_s,start_probability,transition_probability,emit_probability)
for idx in range(len(result)):
print(hidden_state[int(result[idx])])
实现2:
# --*--coding:utf-8 --*--
import numpy as np
def viterbi2(transiton_prob,emit_prob,pi,obs_seq):
'''
:param transiton_prob: 转移概率矩阵[len(隐状态),len(隐状态)]
:param emit_prob:发射概率矩阵[len(观测序列),len(隐状态)]
:param pi:初始概率
:param obs_seq:观测序列
:return:
'''
# 转换为矩阵进行运算
tansition_prob=np.array(transiton_prob)
emit_prob=np.array(emit_prob)
pi=np.array(pi)
obs_seq=[0,2,3]
#最后返回一个row*col的矩阵
Row=tansition_prob.shape[0]
Col=len(obs_seq)
F=np.zeros((Row,Col))
#初始状态
#emit_prob[:,obs_seq[0]]表示从初始状态转移到观测到的第一个状态的转移概率
F[:,0]=pi*np.transpose(emit_prob[:,obs_seq[0]])
# 遍历观测序列中的每一个值
for t in range(1,Col):
list_max=[]
for n in range(Row):
list_x=list(np.array(F[:,t-1])*np.transpose(tansition_prob[:,n])) #相当于pi(0,u,v)*p(v|u)
#获取最大概率
list_p=[]
for i in list_x:
list_p.append(i*10000)
list_max.append(max(list_p)/10000)
#相当与pi(0,u,v)*p(v|u) 再乘p(x|v)
F[:,t]=np.array(list_max)*np.transpose(emit_prob[:,obs_seq[t]])
return F
if __name__ == '__main__':
# 隐藏状态
invisible = ['Sunny', 'Cloud', 'Rainy']
# 初始状态
pi = [0.63, 0.17, 0.20]
# 转移矩阵
trainsion_probility = [[0.5, 0.375, 0.125], [0.25, 0.125, 0.625], [0.25, 0.375, 0.375]]
# 发射矩阵
emission_probility = [[0.6, 0.2, 0.15, 0.05], [0.25, 0.25, 0.25, 0.25], [0.05, 0.10, 0.35, 0.5]]
# 最后显示状态:每列代表Dry,Damp,Soggy的概率
obs_seq = [0, 2, 3]
# 最后返回一个Row*Col的矩阵结果
F = viterbi2(trainsion_probility, emission_probility, pi, obs_seq)
print(F)
实现3:
# --*-- coding:utf-8 --*--
import numpy as np
states = ('Healthy', 'Fever') #所有可能的隐含状态
observations = ('normal', 'cold', 'dizzy') #实际观测到的现象序列
start_probability = {'Healthy': 0.8, 'Fever': 0.2} #每个隐含状态的初始概率
transition_probability = {'Healthy' : {'Healthy': 0.8, 'Fever': 0.2},'Fever' :{'Healthy': 0.4, 'Fever': 0.6},}
#每个隐含状态产生某种观测现象的概率
emission_probability = {'Healthy' : {'normal': 0.5, 'cold': 0.4, 'dizzy': 0.1},'Fever': {'normal': 0.1, 'cold': 0.3, 'dizzy': 0.6},}
#某种隐含状态产生某种观测现象的概率
def Viterbit(obs, states, s_pro, t_pro, e_pro):
path = { s:[] for s in states}#先生成一个初始的状态序列。
print(path)# init path: path[s] represents the path ends with s
curr_pro = {} #当前状态可能。
for s in states:#每种状态枚举,当前为health
print("obs[0]",obs[0]) #第一天是normal
print("e_pro[%s][%s]"%(s,e_pro[s][obs[0]])) #打印normal, healthy状况下发射为normal的概率
print("s_pro[s]=",s_pro[s]) #健康对应的初始状态的概率
print("s_pro[s]*e_pro[s][obs[0]]",s_pro[s]*e_pro[s][obs[0]]) #初始为healthy后,从health发射到normal的概率
curr_pro[s] = s_pro[s]*e_pro[s][obs[0]] #Health状态为0.6*0.5=0.3,fever状态为0.1*0.4=0.04;第一天为health可能性最大。
for i in range(1,len(obs)): #从第2天开始计算
last_pro = curr_pro
print("---------------------------")
print("last_pro",last_pro)
#每次都把当前态存起来。
curr_pro = {}#先设置最初态。
for curr_state in states:#逐一比对隐含状态。
print("curr_state=%s"%curr_state)
for last_state in states:
print("****************************last_state=%s"%last_state)
print("last_pro[%s]=%s"%(last_state,last_pro[last_state])) #最后状态
print("t_pro[%s][%s]=%s"%(last_state,curr_state,t_pro[last_state][curr_state]))#last_states转移到当前状态。
print("e_pro[%s][%s]=%s" % (curr_state, obs[i], e_pro[curr_state][obs[i]])) # 当前状态到观测值的发射概率。
#health-health,health-fever的概率。前一天health,今天health和fever的概率,选出最大的那个,得出今天的健康状况
max_pro, last_sta = max(((last_pro[last_state] * t_pro[last_state][curr_state] * e_pro[curr_state][obs[i]],last_state) for last_state in states))
print(max_pro)
curr_pro[curr_state] =max_pro
print(last_pro[last_state])
curr_pro[curr_state]=curr_pro[curr_state].append(max(last_pro[last_state]))
# find the final largest probability
max_pro = -1
max_path = None
for s in states:
path[s].append(s)
if curr_pro[s] > max_pro:
max_path = path[s]
max_pro = curr_pro[s]
return max_path
if __name__ == '__main__':
obs = ['normal', 'cold', 'dizzy'] # 观测序列。
print(Viterbit(obs, states, start_probability, transition_probability, emission_probability))
实现4:
# --*-- coding:utf-8 --*--
states = ('Rainy', 'Sunny')
observations = ('walk', 'shop', 'clean')
start_probability = {'Rainy': 0.6, 'Sunny': 0.4}
transition_probability = {
'Rainy': {'Rainy': 0.7, 'Sunny': 0.3},
'Sunny': {'Rainy': 0.4, 'Sunny': 0.6},
}
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(" ",end='')
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" % ("%f" % V[t][y]),end='')
print()
def viterbi(obs, states, start_p, trans_p, emit_p):
"""
:param obs:观测序列
:param states:隐状态
:param start_p:初始概率(隐状态)
:param trans_p:转移概率(隐状态)
:param emit_p: 发射概率 (隐状态表现为显状态的概率)
:return:
"""
# 路径概率表 V[时间][隐状态] = 概率
V = [{}]
# 一个中间变量,代表当前状态是哪个隐状态
path = {}
# 初始化初始状态 (t == 0)
for 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
# 记录路径
print(path[state])
print([y])
newpath[y] = path[state] + [y]
print(newpath[y])
# 不需要保留旧路径
path = newpath
print_dptable(V)
(prob, state) = max([(V[len(obs) - 1][y], y) for y in states])
return (prob, path[state])
def example():
return viterbi(observations,
states,
start_probability,
transition_probability,
emission_probability)
print(example())