Viterbi算法

44 篇文章 0 订阅
24 篇文章 1 订阅

简介和示例理解

Viterbi算法是典型的动态规划算法,通过中间节点的优选来大为简化整体复杂度。关键点在于隐藏状态的判断。根据观察值,转移概率来推测真实状态(隐藏状态)。注意到中间的节点所有状态都是保留的,只在最后一个观察值来最终判断哪一条路径(那个序列)是最优的就是最终的答案。
比如生病、健康状态,医生每天观察到的是正常、发烧、头晕这样症状,病人每天的健康、生病状态转移有一点概率(假设平稳不变),则由发烧-健康康复的过程中每个状态点(对应观察时刻点)就是隐藏状态。我们需要知道的是医生判断出的病人每个健康状态。比如,一开始Day1医生观察到对象正常(如果健康观察到正常、发烧、头晕为0.5,0.4,0.1; 生病观察到正常、发烧、头晕分别为0.1,0.3,0.6),得知他初始{健康是60%,生病40%} (假设是通过整体推算出来正常人概率),则诊断值为{健康:0.3,生病:0.04}; =》健康;
Day2,根据转移概率{}观察到病人发烧,如果硬判不考虑昨天,健康发烧0.4;生病发烧0.3,健康概率更大;=》健康;
Day3,观察病人dizzy头晕,那么健康头晕0.1,生病0.6,那么判断生病;=>生病;

如果软判决呢?
那么综合考量转移概率{健康->健康:0.7,->生病0.3; 生病->健康0.4,->生病0.6};
Day1开始:内在病人变化,{健康-健康 0.21,健康-生病:0.09, 生病-健康0.016, 生病-生病0.024},观察到发烧推断,{健康-健康-发烧 0.084,H-S-发烧:0.027,S-H-发烧 0.064,S-S-发烧0.0072},虽然HH概率最高,但是软判还要考虑后面,并且发现H-S
Day2开始:变化{H-H-H 0.056, H-H-S 0.024, H-S-H 0.01, H-S-S 0.0164, S-H-H 0.042, S-H-S 0.018, S-S-H 0.0028, S-S-S 0.0042},推断头晕:
{H-H-H 0.0056, H-H-S 0.012, H-S-H 0.001, H-S-S 0.09, S-H-H 0.0042, S-H-S 0.01, S-S-H 0.00028, S-S-S 0.0024}如果是终点选择最高概率0.036即可,可以发现最终路径不是第二步最高的H-H发烧-S,而是H正常-S发烧-S头晕。 如果不是最终节点,可以削减中间态,隐藏起来,砍掉不必要枝节,继续迭代下去。

主要算法流程

viterbi主要算法流程
1 πi是初始状态,初始状态乘以第一观察B_i,y1就是起点状态;
2 后面每次观察都是前一状态T1[k,j-1]乘以转移概率Aki(事物本身发展规律)*观察因果率(如果健康,观察到头晕概率); 每次留下最高概率的路径。

code

'''
维特比译码的例子-发烧实验
'''

obs = ("normal", "cold", "dizzy", "cold")  #医生3次观察, 相当于收到三次y(y0,y1,y2);
states = ("Healthy", "Fever")
start_p = {"Healthy": 0.6, "Fever": 0.4} #初始观察,0.6健康,0.4生病; 发射状态(隐藏状态); 开始healthy 0.6, 0.4概率值;
trans_p = {
"Healthy": {"Healthy": 0.7, "Fever": 0.3},
"Fever": {"Healthy": 0.4, "Fever": 0.6},
}                                        #转移概率,根据星座点等等变化,迁移;
emit_p = {
"Healthy": {"normal": 0.5, "cold": 0.4, "dizzy": 0.1},
"Fever": {"normal": 0.1, "cold": 0.3, "dizzy": 0.6},
}  # 原本状态 emit_p

# 观察到的是 正常、冷、晕; 隐藏状态是 健康或感冒;
def dptable(V):
    # Print a table of steps from dictionary
    yield " ".join(("%12d" % i) for i in range(len(V)))
    for state in V[0]:
        yield "%.7s: " % state + " ".join("%.7s" % ("%f" % v[state]["prob"]) for v in V)

#def viterbi(obs, states, start_p, trans_p, emit_p):
V = [{}]
for st in states:
    V[0][st] = {"prob": start_p[st] * emit_p[st][obs[0]], "prev": None} #实际是真实状态* 观察结果,可以推测的概率--共同概率,既正确,又推理正确概率;
# Run Viterbi when t > 0
for t in range(1, 2): #len(obs)
    V.append({})
    for st in states:
        max_tr_prob = V[t - 1][states[0]]["prob"] * trans_p[states[0]][st]
        prev_st_selected = states[0]
        for prev_st in states[1:]:
            tr_prob = V[t - 1][prev_st]["prob"] * trans_p[prev_st][st]
            if tr_prob > max_tr_prob:
                max_tr_prob = tr_prob
                prev_st_selected = prev_st

        max_prob = max_tr_prob * emit_p[st][obs[t]]
        V[t][st] = {"prob": max_prob, "prev": prev_st_selected}

for line in dptable(V):
    print(line)

opt = []
max_prob = 0.0
best_st = None
# Get most probable state and its backtrack
for st, data in V[-1].items():
    if data["prob"] > max_prob:
        max_prob = data["prob"]
        best_st = st
opt.append(best_st)
previous = best_st

# Follow the backtrack till the first observation
for t in range(len(V) - 2, -1, -1):
    opt.insert(0, V[t + 1][previous]["prev"])
    previous = V[t + 1][previous]["prev"]

print("The steps of states are " + " ".join(opt) + " with highest probability of %s" % max_prob)
print(V)




# viterbi(obs,
# states,
# start_p,
# trans_p,
# emit_p)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值