美文网首页Machine Learning & Data Analysis
python 日常笔记 hmmlearn 隐性马尔科夫模型案例分

python 日常笔记 hmmlearn 隐性马尔科夫模型案例分

作者: 科学俱乐会 | 来源:发表于2020-01-06 09:11 被阅读0次

    问题:

    什么是马尔科夫模型?用来干什么?
    大家可以参考这篇简书

    <隐性马尔科夫模型简介,只聊原理, (保证没有数学)>
    https://www.jianshu.com/p/3b4fbcea2744

    python 实现

    关于HMM有两个主要问题:
    已知上述三个参数,和当前观测序列,求解隐藏状态的变化
    所有参数未知,只有数据,如何获得三个参数
    需要使用hmmlearn 包

    导入需要的库

    import random
    import datetime   # 可有可无,用来记录模型学习时间,
    import numpy as np
    from hmmlearn import hmm
    

    已知参数和当前的观测序列,求解隐含状态的序列

    隐藏状态:

    hidden_states = ["A", "B" ]
    n_hidden_states = len(hidden_states)
    

    观察情况

    observations = ["1", "2", "3", "4", "5", "6"]
    n_observations = len(observations)
    

    初始状态矩阵

    start_probability = np.array([0.8, 0.2,])
    

    状态转移矩阵

    transition_probability = np.array([[0.2, 0.8], 
                                       [0.8, 0.2]]
                                     )
    

    发射矩阵

    emission_probability = np.array([ [1/6,  1/6,  1/6,  1/6,  1/6,  1/6,], 
                                      [0.25, 0.25, 0.25, 0.25, 0,    0] ]
                                   )
    

    构建模型

    model = hmm.MultinomialHMM(n_components=n_hidden_states)
    

    将上述设定的参数传入其中

    model.startprob_=start_probability
    model.transmat_=transition_probability
    model.emissionprob_=emission_probability
    

    输入我们观察到的序列

    observations_sequence = np.array([[0, 1, 2,1, 3, 3, 4, 0, 5, 3]]).T
    print("观察到的取出的色子点数:", ", ".join(map(lambda x: observations[int(x)], observations_sequence)))
    logprob, box = model.decode(observations_sequence, algorithm="viterbi")
    print("decode 方法计算:    ", ", ".join(map(lambda x: hidden_states[x], box)))
    box = model.predict(observations_sequence)
    print("predict方法计算:    ", ", ".join(map(lambda x: hidden_states[int(x)], box)), '\n')
    
    
    observations_sequence = np.array([[2, 1, 1,0, 2, 3, 0, 1, 1, 2, 2,1,0,0,3,3]]).T
    print("取出的色子点数:", ", ".join(map(lambda x: observations[int(x)], observations_sequence)))
    box = model.predict(observations_sequence)
    print("从哪个盒子取的:", ", ".join(map(lambda x: hidden_states[int(x)], box)),'\n')
    
    
    observations_sequence = np.array([[5, 4, 3, 2, 2, 3, 0, 4, 5, 4, 1,1,0,0,3,3]]).T
    print("取出的色子点数:", ", ".join(map(lambda x: observations[int(x)], observations_sequence)))
    box = model.predict(observations_sequence)
    print("从哪个盒子取的:", ", ".join(map(lambda x: hidden_states[int(x)], box)))
    

    输出的结果是
    观察到的取出的色子点数: 1, 2, 3, 2, 4, 4, 5, 1, 6, 4
    decode 方法计算: A, B, A, B, A, B, A, B, A, B
    predict方法计算: A, B, A, B, A, B, A, B, A, B

    取出的色子点数: 3, 2, 2, 1, 3, 4, 1, 2, 2, 3, 3, 2, 1, 1, 4, 4
    从哪个盒子取的: A, B, A, B, A, B, A, B, A, B, A, B, A, B, A, B

    取出的色子点数: 6, 5, 4, 3, 3, 4, 1, 5, 6, 5, 2, 2, 1, 1, 4, 4
    从哪个盒子取的: A, A, B, A, B, A, B, A, A, A, B, A, B, A, B, A

    所有参数未知,只有数据,如何获得三个参数

    方案: 我们先假定一个初始概率分布,转移矩阵,以及发射矩阵,按照这些参数生成很多很多数据.
    然后将数据放到HMM模型里,利用数据学习,检查模型学到的参数和我们假定的参数是不是一致。
    按照假象的规则去生成一些列数据

    #  初始状态 判断标准,小于此值为A 大于此值为B
    a_b_init_critia = 0.2
    
    # state_change
    state_change = {"A": 0.3,   # 此时如果是A, 那么取random, 如果小于 此值就是A 否则为B
                    "B": 0.6    # 此时如果是B, 那么取random, 如果小于 此值就是A 否则为B
                   }
    # 点数情况
    observations = ["1", "2", "3", "4", "5", "6"]
    # 点数对应的 index
    point={"A": [0,1,2,3,4,5],  "B": [0,1,2,3]}
    
    data_size = 10000
    whole_data = []
    lengths = []
    for i in range(data_size):
        dice = "A" if random.random() < a_b_init_critia else "B"
        data = []
        sequence_length = random.randint(2, 25)
        for _ in range(sequence_length):
    #         print(dice, end="  ")
            data.append([random.sample(point[dice], 1)[0]])
            dice = "A" if random.random() < state_change[dice] else "B"
    #     print(f"一共投了  {sequence_length} 次 \n点数的index  {data} \n")
        whole_data.append(data)
        lengths.append(sequence_length)
    whole_data = np.concatenate(whole_data)
    

    将数据填入模型中,进行学习

    print(f"开始学习 {datetime.datetime.now()} 共 {len(lengths)}条数据")
    hmm_model = hmm.MultinomialHMM(n_components=len(point),
                                   n_iter=100000,  # Maximum number of iterations to perform.
                                   tol=0.000001,   # Convergence threshold. EM will stop if the gain in log-likelihood is below this value.
                                   verbose = False, # When True per-iteration convergence reports are printed to sys.stderr. 
                                  )
    hmm_model.fit(whole_data, lengths)
    
    # 学习之后,查看参数
    print(f"结束学习 {datetime.datetime.now()}")
    print('因为是无监督学习,所以模型不会把 A B 排定先后顺序,但是 三个参数是相互关联的,所以顺序其实无关系')
    print('初始概率')
    print(hmm_model.startprob_,'\n')
    print('状态转移矩阵')
    print(hmm_model.transmat_,'\n')
    print('从隐藏状态到 显示状态的发散矩阵')
    print(hmm_model.emissionprob_,'\n')
    

    输出的结果是
    开始学习 2020-01-05 10:03:02.832792 共 10000条数据
    结束学习 2020-01-05 13:05:53.612298
    因为是无监督学习,所以模型不会把 A B 排定先后顺序,但是 三个参数是相互关联的,所以顺序其实无关系
    初始概率
    [0.20509604 0.79490396]

    状态转移矩阵
    [[0.31460223 0.68539777]
    [0.6213235 0.3786765 ]]

    从隐藏状态到 显示状态的发散矩阵
    [[1.67834277e-01 1.74886284e-01 1.69078215e-01 1.68723388e-01
    1.61611529e-01 1.57866306e-01]
    [2.51185996e-01 2.46793569e-01 2.46239587e-01 2.53539909e-01
    1.54840968e-06 2.23939182e-03]]

    可见学习的还是很好的, 只是时间有点长(3个小时),
    但是结果非常符合预期, 主要原因是,我们的数据非常干净,没有噪音. 如果在数据中混杂这噪音,可能结果就不会这么好了

    ref

    https://hmmlearn.readthedocs.io/en/latest/api.html

    相关文章

      网友评论

        本文标题:python 日常笔记 hmmlearn 隐性马尔科夫模型案例分

        本文链接:https://www.haomeiwen.com/subject/zfyqactx.html