HMM 隐马尔可夫模型 代码实现

#encoding:utf-8
import sys
import pickle
from copy import deepcopy

is_train = False

DEFAULT_PROB = 0.000000000001
MIN_PROB = -1 * float('inf')

train_path = "train.in"
test_path = "test.in"
output_path = "test.out"

#统计 各个次数 作为 各个概率
def train():
    print "start training ..."

    # 以下5个元素是HMM模型的参数
    V = set() # 观测集合
    Q = set() # 状态集合
    A = {} # 状态转移概率矩阵,P(状态|状态),是一个二层dict 具体是 pre_state->(state->prob)
    B = {} # 观测概率矩阵,P(观测|状态),是一个二层dict 具体是 state->(observ->prob)
    PI = {} # 初始状态概率向量

    # 统计模型参数
    with open(train_path, "rb") as infile:
        pre_s = -1 # t-1时刻的状态
        for line in infile:
            segs = line.rstrip().split('\t')
            if len(segs) != 2: # 遇到空行时
                pre_s = -1
            else:
                o = segs[0] # t时刻的观测o
                s = segs[1] # t时刻的状态s
                # 统计状态s到观测o的次数
                B[s][o] = B.setdefault(s, {}).setdefault(o, 0) + 1
                V.add(o)
                Q.add(s)
                if pre_s == -1: # 统计每个句子开头第一个状态的次数
                    PI[s] = PI.setdefault(s, 0) + 1
                else: # 统计状态pre_s到状态s的次数
                    A[pre_s][s] = A.setdefault(pre_s, {}).setdefault(s, 0) + 1
                pre_s = s #切换到下一个状态
    # 概率归一化
    for i in A.keys():
        prob_sum = 0
        for j in A[i].keys():
            prob_sum += A[i][j]
        for j in A[i].keys():
            A[i][j] = 1.0 * A[i][j] / prob_sum

    for i in B.keys():
        prob_sum = 0
        for j in B[i].keys():
            prob_sum += B[i][j]
        for j in B[i].keys():
            B[i][j] = 1.0 * B[i][j] / prob_sum

    prob_sum = sum(PI.values())
    for i in PI.keys():
        PI[i] = 1.0 * PI[i] / prob_sum
    print "finished training ..."

    return A, B, PI, V, Q

def saveModel(A, B, PI, V, Q):
    with open("A.param", "wb") as outfile:
        pickle.dump(A, outfile)
    with open("B.param", "wb") as outfile:
        pickle.dump(B, outfile)
    with open("PI.param", "wb") as outfile:
        pickle.dump(PI, outfile)
    with open("V.param", "wb") as outfile:
        pickle.dump(V, outfile)
    with open("Q.param", "wb") as outfile:
        pickle.dump(Q, outfile)

#维特比
def predict(X, A, B, PI, V, Q):
    W = [{} for t in range(len(X))] #相当于书上的δ
    path = {}
    for s in Q:
        W[0][s] = 1.0 * PI.get(s, DEFAULT_PROB) * B.get(s, {}).get(X[0], DEFAULT_PROB) #0时刻状态为s的概率
        path[s] = [s]
    for t in range(1, len(X)):
        new_path = {}
        for s in Q: #两轮循环暴力求解
            max_prob = MIN_PROB
            max_s = ''
            for pre_s in Q:
                prob = W[t-1][pre_s] * \
                       A.get(pre_s, {}).get(s, DEFAULT_PROB) * \
                       B.get(s, {}).get(X[t], DEFAULT_PROB)
                (max_prob, max_s) = max((max_prob, max_s), (prob, pre_s)) #全由第一个prob决定
            W[t][s] = max_prob #t时刻状态为s的最大概率
            tmp = deepcopy(path[max_s])
            tmp.append(s)
            new_path[s] = tmp
        path = new_path
    (max_prob, max_s) = max((W[len(X)-1][s], s) for s in Q)# 最后一个时刻各个状态的概率的最大的
    return path[max_s]

def getModel():
    with open("A.param", "rb") as infile:
        A = pickle.load(infile)
    with open("B.param", "rb") as infile:
        B = pickle.load(infile)
    with open("PI.param", "rb") as infile:
        PI = pickle.load(infile)
    with open("V.param", "rb") as infile:
        V = pickle.load(infile)
    with open("Q.param", "rb") as infile:
        Q = pickle.load(infile)     
    return A, B, PI, V, Q

def test(A, B, PI, V, Q):
    print "start testing"
    with open(test_path, "rb") as infile, \
         open(output_path, "wb") as outfile:
        X_test = []
        y_test = []
        for line in infile:
            segs = line.strip().split('\t')
            if len(segs) != 2: # 遇到空行时
                if len(X_test) == 0:#一整句 比如NBAD
                    continue
                preds = predict(X_test, A, B, PI, V, Q)
                for vals in zip(X_test, y_test, preds):
                    outfile.write("\t".join(vals) + "\n")   
                outfile.write("\n")
                X_test = []
                y_test = []
            else:
                o = segs[0] # t时刻的观测o
                s = segs[1] # t时刻的状态s       
                X_test.append(o)
                y_test.append(s)

    print "finished testing"

def main():
    if is_train:
        A, B, PI, V, Q = train()
        saveModel(A, B, PI, V, Q)
    else:
        A, B, PI, V, Q = getModel()

    test(A, B, PI, V, Q)

if __name__ == '__main__':
    main()

数据在https://github.com/guotong1988/MachineLearningFromZero
参考《统计学习方法》

  • 4
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
嗯,隐马尔可夫模型(Hidden Markov Model)是一种常用的序列建模方法,可以用于股票价格的预测。下面我将提供一个基于Python的完整源码和数据的例子,来解释如何使用隐马尔可夫模型进行股票价格预测。 首先,我们需要准备一些数据。假设我们手头有股票A的每日收盘价数据,这些数据可以保存在一个以日期为索引的Pandas DataFrame中。 以下是数据的示例,其中Date表示日期,Close表示当天的收盘价: ```py import pandas as pd data = {'Date': ['2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04', '2021-01-05'], 'Close': [100, 110, 115, 105, 95]} df = pd.DataFrame(data) df['Date'] = pd.to_datetime(df['Date']) df.set_index('Date', inplace=True) ``` 接下来,我们需要使用Python的hmmlearn库来构建隐马尔可夫模型并进行预测。如果尚未安装该库,可以使用以下命令进行安装: ```py pip install hmmlearn ``` 以下是使用隐马尔可夫模型进行股票价格预测的代码示例: ```py from hmmlearn import hmm # 创建隐马尔可夫模型对象 model = hmm.GaussianHMM(n_components=2, covariance_type="diag") # 拟合模型 model.fit(df[['Close']]) # 预测概率和状态序列 prob, states = model.decode(df[['Close']]) # 输出预测结果 df['State'] = states print(df) ``` 上述代码中,我们首先创建一个GaussianHMM对象,该对象的`n_components`参数指定了两个隐藏状态(我们假设股票价格会呈现上涨和下跌两种状态),`covariance_type`参数指定了协方差矩阵的类型。 然后,我们使用拟合方法(fit)来训练模型,输入的是收盘价数据。 接着,我们使用decode方法来计算每个观测值对应的隐藏状态,并将其保存在DataFrame中的State列中。 最后,打印输出整个DataFrame,即可查看预测结果。 使用隐马尔可夫模型进行股票价格预测是一个相对简化的方法,实际情况可能更加复杂。然而,这个例子可以帮助你了解如何使用隐马尔可夫模型进行股票价格预测,并且提供一个基于Python的完整源码和数据的参考。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

热爱Coding

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值