https://blog.csdn.net/Luzichang/article/details/91365752
假设有这样一个问题,远在另一个城市上大学的儿子每天通过邮件向你汇报他今天做的最多事情是什么,这些事情可能是这三项之一:打球、读书、访友。
那么在这种场景下,如何推测儿子所在城市的天气情况。
假设儿子活动有如下规律:在晴天更可能打球,在阴天更可能访友,在雨天更可能的读书,在散发概率矩阵中显示为概率值大小。
在这个问题中,儿子的活动类型构成了模型的可见层,天气情况成了隐藏层。
1.状态的样本空间 states = ('晴', '阴','雨');
2.起始的状态概率 start_probability = {'晴':0.5, '阴':0.3,'雨':0.2}
3.状态转移概率 transition_probability = {
'晴': {'晴':0.7, '阴':0.2,'雨':0.1},
'阴': {'晴':0.3, '阴':0.5,'雨':0.2},
'雨': {'晴':0.3, '阴':0.4,'雨':0.3},
}
4.状态->观测的发散概率 emission_probability = {
'晴': { '读书': 0.3,'打球': 0.4, '访友': 0.3},
'阴': { '读书': 0.3,'打球': 0.2, '访友': 0.5},
'雨': { '读书': 0.8,'打球': 0.1, '访友': 0.1},
}
5.观测的样本空间(观测序列) observations = ( '读书', '打球','访友','读书')
代码:
# https://blog.csdn.net/Luzichang/article/details/91365752 import math # 状态的样本空间 states = ('晴', '阴','雨') # 观测的样本空间 observations = ( '读书', '打球','访友','读书') #observations = ( '读书', '读书','读书','读书') #observations = ( '打球', '打球','打球','打球') #observations = ( '访友', '访友','访友','访友') #observations = ( '读书', '访友','访友','读书') # 起始个状态概率 start_probability = {'晴':0.5, '阴':0.3,'雨':0.2} # 状态转移概率 transition_probability = { '晴': {'晴':0.7, '阴':0.2,'雨':0.1}, '阴': {'晴':0.3, '阴':0.5,'雨':0.2}, '雨': {'晴':0.3, '阴':0.4,'雨':0.3}, } # 状态->观测的发散概率 emission_probability = { '晴': { '读书': 0.3,'打球': 0.4, '访友': 0.3}, '阴': { '读书': 0.3,'打球': 0.2, '访友': 0.5}, '雨': { '读书': 0.8,'打球': 0.1, '访友': 0.1}, } # 计算以E为底的幂 def E(x): #return math.pow(math.e,x) return x def display_result(observations,result_m):#较为友好清晰的显示结果 # 从结果中找出最佳路径 #print(result_m) infered_states = [] final = len(result_m) - 1 (p, pre_state), final_state = max(zip(result_m[final].values(), result_m[final].keys())) infered_states.insert(0, final_state) infered_states.insert(0, pre_state) for t in range(final - 1, 0, -1): _, pre_state = result_m[t][pre_state] infered_states.insert(0, pre_state) print(format("Viterbi Result", "=^80s")) head = format("观测序列", " ^7s") head += format("推断状态", " ^16s") for s in states: head += format(s, " ^15s") print(head) print(format("", "-^80s")) for obs,result,infered_state in zip(observations,result_m,infered_states): item = format(obs," ^10s") item += format(infered_state," ^18s") for s in states: item += format(result[s][0]," >12.8f") if infered_state == s: item += "(*)" else: item +=" " print(item) print(format("", "=^80s")) def viterbi(obs, states, start_p, trans_p, emit_p): result_m = [{}] # 存放结果,每一个元素是一个字典,每一个字典的形式是 state:(p,pre_state) # 其中state,p分别是当前状态下的概率值,pre_state表示该值由上一次的那个状态计算得到 for s in states: # 对于每一个状态 result_m[0][s] = (E(start_p[s]*emit_p[s][obs[0]]),None) # 把第一个观测节点对应的各状态值计算出来 #print('11',result_m[0][s]) for t in range(1,len(obs)): result_m.append({}) # 准备t时刻的结果存放字典,形式同上 for s in states: # 对于每一个t时刻状态s,获取t-1时刻每个状态s0的p,结合由s0转化为s的转移概率和s状态至obs的发散概率 # 计算t时刻s状态的最大概率,并记录该概率的来源状态s0 # max()内部比较的是一个tuple:(p,s0),max比较tuple内的第一个元素值 result_m[t][s] = max([(E(result_m[t-1][s0][0]*trans_p[s0][s]*emit_p[s][obs[t]]),s0) for s0 in states]) #print(result_m[t][s]) return result_m # 所有结果(包括最佳路径)都在这里,但直观的最佳路径还需要依此结果单独生成,在显示的时候生成 if __name__ == "__main__": result_m = viterbi( observations, states, start_probability, transition_probability, emission_probability) display_result(observations,result_m)
输出结果:
=================================Viterbi Result================================= 观测序列 推断状态 晴 阴 雨 -------------------------------------------------------------------------------- 读书 晴 0.15000000(*) 0.09000000 0.16000000 打球 晴 0.04200000(*) 0.01280000 0.00480000 访友 晴 0.00882000(*) 0.00420000 0.00042000 读书 晴 0.00185220(*) 0.00063000 0.00070560 ================================================================================
测试其他观测序列
=================================Viterbi Result================================= 观测序列 推断状态 晴 阴 雨 -------------------------------------------------------------------------------- 读书 雨 0.15000000 0.09000000 0.16000000(*) 读书 雨 0.03150000 0.01920000 0.03840000(*) 读书 雨 0.00661500 0.00460800 0.00921600(*) 读书 雨 0.00138915 0.00110592 0.00221184(*) ================================================================================
=================================Viterbi Result================================= 观测序列 推断状态 晴 阴 雨 -------------------------------------------------------------------------------- 打球 晴 0.20000000(*) 0.06000000 0.02000000 打球 晴 0.05600000(*) 0.00800000 0.00200000 打球 晴 0.01568000(*) 0.00224000 0.00056000 打球 晴 0.00439040(*) 0.00062720 0.00015680 ================================================================================
=================================Viterbi Result================================= 观测序列 推断状态 晴 阴 雨 -------------------------------------------------------------------------------- 访友 阴 0.15000000 0.15000000(*) 0.02000000 访友 阴 0.03150000 0.03750000(*) 0.00300000 访友 阴 0.00661500 0.00937500(*) 0.00075000 访友 阴 0.00138915 0.00234375(*) 0.00018750 ================================================================================
=================================Viterbi Result================================= 观测序列 推断状态 晴 阴 雨 -------------------------------------------------------------------------------- 访友 阴 0.15000000 0.15000000(*) 0.02000000 访友 阴 0.03150000 0.03750000(*) 0.00300000 读书 阴 0.00661500 0.00562500(*) 0.00600000 访友 阴 0.00138915 0.00140625(*) 0.00018000 访友 阴 0.00029172 0.00035156(*) 0.00002812 访友 阴 0.00006126 0.00008789(*) 0.00000703 读书 雨 0.00001286 0.00001318 0.00001406(*) ================================================================================