zoukankan      html  css  js  c++  java
  • 【NLP CODE】维特比算法 Viterbi

    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)
    View Code

    输出结果:

    =================================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(*)
    ================================================================================
  • 相关阅读:
    面试题58:翻转字符串
    面试题57_2:和为S的连续正数序列
    面试题57:和为S的数字
    面试题56:数组中数字出现的次数
    面试题55_2:平衡二叉树
    面试题54:二叉搜索树的第k大节点
    面试题55_1:二叉树的深度
    tortoisegit 本地创建的分支 push github
    TortoiseGit 拉取分支
    tortoiseGIT 本地分支创建合并
  • 原文地址:https://www.cnblogs.com/hbuwyg/p/13252386.html
Copyright © 2011-2022 走看看