参考
github-通用维特比算法的Java实现
一文搞懂HMM(隐马尔可夫模型)
没啥新意,就是不熟悉算法,在网上找了个参考的例子,用Python实现了下算法,用于学习并理解此算法。
维特比算法
测试假设的问题
经典例子:一个东京的朋友每天根据天气{下雨,天晴}决定当天的活动{公园散步,购物,清理房间}中的一种,我每天只能在twitter上看到她发的推“啊,我前天公园散步、昨天购物、今天清理房间了!”,那么我可以根据她发的推特推断东京这三天的天气。
问题分解
假设已经有一个相当长时间的观察记录数据
日期 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | … |
---|---|---|---|---|---|---|---|---|---|
天气 | 下雨 | 天晴 | 天晴 | 下雨 | 下雨 | 天晴 | 天晴 | 下雨 | … |
行为 | 购物 | 公园散步 | 公园散步 | 购物 | 清理房间 | 公园散步 | 公园散步 | 清理房间 | … |
这里有两条线,一条天气线一条隐藏线
对统计如下数据(统计数据都是假设):
行为类型:[‘walk’,’shop’,’clean’]
天气类型:[‘Rainy’,’Sunny’]
前一天晴,后一天天气概率:[晴:0.4,雨:0.6]
前一天雨,后一天天气概率:[晴:0.7,雨:0.3]
天晴,三种行为概率:[0.6,0.3,0.1]
下雨,三种行为概率:[0.1,0.4,0.5]
假如今天活动是购物,那么预测天气的计算步骤如下:
今天是晴的概率:
1. ([前一天计算结果][晴])*([前一天晴,后一天天气概率][晴])*([天晴,三种行为概率][购物])
2. ([前一天计算结果][雨])*([前一天雨,后一天天气概率][晴])*([天晴,三种行为概率][购物])
最终结果取1,2两步计算里的最大值
今天是雨的概率:
1. ([前一天计算结果][晴])*([前一天晴,后一天天气概率][雨])*([天雨,三种行为概率][购物])
2. ([前一天计算结果][雨])*([前一天雨,后一天天气概率][雨])*([天雨,三种行为概率][购物])
最终结果取1,2两步计算里的最大值
明天以此类推,一天天计算下去
代码
#coding=utf-8
import numpy as np
#维特比算法
class Viterbi(object):
#求解HMM模型
#int[] obs 每一天的行为
#int[] work_t 行为的总类列表
#int[] states 天气的总类列表
#double[] start_p 初始概率(隐状态)
#double[][] trans_p 转移概率(隐状态)
#double[][] emit_p 发射概率 (隐状态表现为显状态的概率)
#int[] return 最可能的序列
def compute(self, obs, work_t, states, start_p, trans_p, emit_p):
N = len(obs)
obs_p = [work_t.index(obs[x]) for x in xrange(N)]
T = len(states)
states_p = [x for x in xrange(T)]
#V:不同行为对应不同天气的概率
V = np.zeros((N,T))
path = np.zeros((T,N), dtype=np.int32)
#初始化,第一个数据
for y in xrange(T):
#计算第一个行为在当前初始概率下,对应不同天气的概率
V[0][y] = start_p[y]*emit_p[y][obs_p[0]]
path[y][0] = states_p[y]
for t in xrange(1,N):
newpath = np.zeros((T,N),dtype=np.int32)
for y in xrange(T):
prob = -1
state = 0
for y0 in xrange(T):
nprob = V[t-1][y0]*trans_p[y0][y]*emit_p[y][obs_p[t]]
if nprob > prob:
prob = nprob
state = y0
#记录最大概率
V[t][y]=prob
#记录路径
for x in xrange(t):
newpath[y][x] = path[state][x]
newpath[y][t]=states_p[y]
path = newpath
prob = -1
state = 0
for y in xrange(T):
if V[N-1][y] > prob:
prob = V[N - 1][y]
state = y
return [states[x] for x in path[state]]
if __name__ == '__main__':
model = Viterbi()
result = model.compute(['walk','shop','clean','clean'],['walk','shop','clean'], ['Rainy','Sunny'], [0.5,0.5], [[0.7,0.3],[0.4,0.6]], [[0.1,0.4,0.5],[0.6,0.3,0.1]])
for r in result:
print r
pass