Python实现LSTM股票预测阶段心得笔记

前言

尝试阶段,本科课设,简易实现,应付期末,还在探索,欢迎交流

实现框架

  • TensorFlow

实验数据

来自老师给的CSV文件,共3000多行,每行包含字段如下:

avg_pricecloseamp_ratefactorhigh_limitlow_limitopenquote_rateturnoverturnover_ratevolume

本次预测是就是基于上述字段,预测之后某一天的股票平均价格。

前置知识

LSTM

https://zybuluo.com/hanbingtao/note/541458

TensorFlow

https://tf.wiki/
http://www.tensorfly.cn/

TensorFlow中的张量、变量、占位

神经网络训练过程中的一些术语

  • Epoch:当一个完整的数据集通过了神经网络一次并且返回了一次,这个过程称为一个 epoch,epoch的数量表示对训练集迭代执行了多少次。
  • Batch:在不能将数据一次性通过神经网络的时候,就需要将数据集分成几个 batch。BATCH SIZE表示一个 batch 中的样本总数。通常是在一个epoch中,有多个Batch通过神经网络模型,在一个Batch中,同时输入了多个样本进入神经网络模型。同时loss函数也是针对一批样本而言,也就是说神经网络通常是考虑令一批数据整体的误差最低。
  • Time Step:对于LSTM预测股票来说,时间步的大小决定了考虑多少天之前的数据进行训练和预测,例如Time Step设置为10,则表示用过去10天进行预测,此时每一批内的每一组样本应该包含10天的信息

关于tf.nn.dynamic_rnn与不同批的状态是否应该传递下去的问题

output_rnn,final_states=tf.nn.dynamic_rnn(cell, input_rnn,initial_state=init_state, dtype=tf.float32) 
#output_rnn是记录lstm每个输出节点的结果,final_states是最后一个cell的结果
#dynamic_rnn是一套循环操作,输入初始和值和状态,返回最终的值和状态
#输入初始的值的shape=(batch_size,time_step,rnn_unit),初始状态是h(batch_size,rnn_unit),c(batch_size,rnn_unit),每批的每组都有对应的状态
#输出值:shape=(batch_size,time_step,rnn_unit),因为每一组、每一个时间步、每一个细胞中都会有一个输出值
#输出状态:h(batch_size,rnn_unit),c(batch_size,rnn_unit) 每一组中的每一个细胞最后会得出一个状态值(h和c),
#output_rnn与final_states的关系:output_rnn是每个时间步的输出组成的矩阵,对于output_rnn中一个时间步内的数据h来说,经过一次y=wh+b变化得到这个时间步输出的结果y
#output_rnn中每个时间步的输出就是这个时间步的状态h,这个h还将用于下一个时间步的输出与状态的计算,也就是说每一个时间步的状态(c,h)都由上一个时间步的输出h和本次时间步的输入x计算得到
#output_rnn最后一个时间步的输出等于final_states中的h
#对于一批数据而言(一批有好多组),不同组数据的状态值是独立的,但是大家用的都是一套权重参数
#负向反馈的目标,是让loss尽可能低,这个loss是对一批数据(一批有很多组)的综合评价,修改后的权重参数并非让每一组的结果变的更好,而是让一批数据整体的结果变得更好
#如果不同批次内,同一组号的数据连接在一起结果是延时间的连续的,则final_states也应该feed进去,不考虑负向反馈的话,假如一共有n批数据,这样做等价于使用第一批数据并把时间步扩充了n倍的效果
#考虑负向反馈的话,这样做等价于,时间步扩充了n倍,但每次过固定数目的时间步就对之前一定数目的结果整体评估一下,然后更新权重参数
#相比于直接将时间步扩充了n倍,这样做准确度可能不如直接扩充,但是某一瞬间消耗的内存应该是小于直接扩充的,毕竟每次负向反馈的处理的权重参数少了很多

完整代码

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf

#训练和预测
only_prediction=0

#数据常量
colnums=21
output_size=10
rows=3000
#神经网络常量
rnn_unit=20      #hidden layer units
input_size=colnums-output_size
batch_size=5
time_step=10
epoch=2000
lr=0.0006  #学习率
#其他常数
# model_path='./model'
model_path='./model2'
data_path='./dataset.csv'


# 定义输入输出的w和b
wi = tf.Variable(tf.random_normal([input_size, rnn_unit]))
bi = tf.Variable(tf.random_normal(shape=[rnn_unit, ], mean=0.0, stddev=1.0))
wo = tf.Variable(tf.random_normal([rnn_unit, output_size]))
bo = tf.Variable(tf.random_normal(shape=[output_size, ], mean=0.0, stddev=1.0))

#导入数据
def import_data():
    f=open(data_path)
    df=pd.read_csv(f)     #读入股票数据
    data=df.iloc[:rows,:colnums].values
    return data


#获取训练集
def get_train_data(data,train_begin=0,train_end=500):
    batch_index=[]
    data_train=data[train_begin:train_end]
    train_x,train_y=[],[]   #训练集
    for i in range(int(len(data_train)/time_step)):
        if i % batch_size==0:
           batch_index.append(i)
        data = data_train[i*time_step:(i+1)*time_step,:]  # 对每批中每组数据进行标准化
        x=data[:,:colnums-output_size]
        mean_x=np.mean(x, axis=0)
        std_x=np.std(x, axis=0) + 0.1
        x = (x - mean_x) / std_x
        y=data[:,colnums-output_size:colnums]
        mean_y=np.mean(y, axis=0)
        std_y=np.std(y, axis=0) + 0.1
        y = (y - mean_y) / std_y
        train_x.append(x.tolist())
        train_y.append(y.tolist())
    return batch_index,train_x,train_y

#获取测试集
def get_test_data(data,test_begin=0,test_end=20):
    data_test=data[test_begin:test_end]

    test_x,test_y,mean,std=[],[],[],[]
    for i in range(int(len(data_test)/time_step)):
        x=data_test[i*time_step:(i+1)*time_step,:colnums-output_size]
        mean_x = np.mean(x, axis=0)
        std_x = np.std(x, axis=0) + 0.1
        x = (x - mean_x) / std_x
        mean_y, std_y = [], []
        for j in (range(output_size)):
            mean_y.append(mean_x[0])
            std_y.append(std_x[0])
        mean.append(mean_y)
        std.append(std_y)
        test_x.append(x.tolist())
    test_y=data_test[:,0]
    return test_x,test_y,mean,std

#定义模型
def RNN(cell,X,init_state):

    #定义隐藏层的运算
    input=tf.reshape(X,[-1,input_size])
    input_rnn=tf.matmul(input,wi)+bi

    input_rnn=tf.reshape(input_rnn,[-1,time_step,rnn_unit])
    output_rnn,final_states=tf.nn.dynamic_rnn(cell, input_rnn,initial_state=init_state, dtype=tf.float32)  #output_rnn是记录lstm每个输出节点的结果,final_states是最后一个cell的结果
    output=tf.reshape(output_rnn,[-1,rnn_unit]) #作为输出层的输入

    pred=tf.matmul(output,wo)+bo
    return pred,final_states

#开始训练
def train_data(train_begin=500,train_end=2500):
    #读数据集,设置神经网络模型,准备X和Y,初始状态
    batch_index, train_x, train_y = get_train_data(import_data(), train_begin, train_end)
    cell = tf.nn.rnn_cell.BasicLSTMCell(rnn_unit)
    X = tf.placeholder(tf.float32, shape=[None, time_step, input_size])
    Y = tf.placeholder(tf.float32, shape=[None, time_step, output_size])
    init_state = cell.zero_state(batch_size, dtype=tf.float32)

    #构建计算图结点
    pred, final_states=RNN(cell,X,init_state)
    loss = tf.reduce_mean(tf.square(tf.reshape(pred,[-1,]) - tf.reshape(Y,[-1,])))
    train_op = tf.train.AdamOptimizer(lr).minimize(loss)

    #声明保存模型需要用的对象
    saver = tf.train.Saver(tf.global_variables(), max_to_keep=15)

    #开始训练
    sess = tf.Session()
    sess.run(tf.global_variables_initializer())
    for i in range(epoch):
        for step in range(len(batch_index) - 1):

            feed_dict = {X: train_x[batch_index[step]:batch_index[step + 1]],
                         Y: train_y[batch_index[step]:batch_index[step + 1]]}

            _, loss_, states = sess.run([train_op, loss, final_states],
                                                feed_dict=feed_dict)
        print( i, loss_)
        if i % 20 == 0:
            print("保存模型:", saver.save(sess, model_path+'/stock.model', global_step=i))
    print("保存模型:", saver.save(sess, model_path, global_step=i))
    sess.close()


#预测
def prediction(test_begin=0,test_end=500):
    #读数据集,配置X和初始状态
    test_x, test_y,mean,std = get_test_data(import_data(), test_begin, test_end)
    X=tf.placeholder(tf.float32, shape=[None,time_step,input_size])
    cell = tf.nn.rnn_cell.BasicLSTMCell(rnn_unit)

    init_state = cell.zero_state(1, dtype=tf.float32)

    #构建计算图结点
    pred, final_states=RNN(cell,X,init_state)

    #配置读取模型需要用的对象
    saver=tf.train.Saver(tf.global_variables())

    #开始预测
    sess=tf.Session()
    module_file = tf.train.latest_checkpoint(model_path)
    saver.restore(sess, module_file)
    test_predict=[]

    for step in range(len(test_x)):
        prob=sess.run(pred,feed_dict={X:[test_x[step]]})
        test_predict.append(prob[len(prob)-1])
    sess.close
    # acc = np.average(np.abs(test_predict - test_y) / test_y)  # 偏差
    # print(acc)
    #以折线图表示结果
    real=[]
    pred=(np.array(test_predict)*std)+mean
    plt.figure()
    plt.plot(list(range(len(test_y))), test_y,  color='r')
    for step in range(0,len(test_predict)-1):
        real.append(test_y[(step+1) * time_step:(step+1) * time_step + output_size])
        plt.plot(list(range((step+1) * time_step, (step+1) * time_step + output_size)), pred[step], color='b', marker="v")
    acc = np.average(np.abs( pred[:len(real)]-np.array(real)) / np.array(real))  # 偏差
    print("acc", acc)
    plt.show()



if only_prediction==0:
    with tf.variable_scope('train'):
        train_data(500,2000)
    with tf.variable_scope('train', reuse=True):
        prediction(2500, 3000)
else:
    with tf.variable_scope('train'):
        prediction(2500, 3000)

经历与心得

起因

​ 大三下学期软件工程的课设就是要求尝试使用RNN进行股票预测,我之前从未接触过Python和神经网络的相关知识,这次课设算是给了我一个学习的动力。

经过

我的学习路线是bp神经网络,RNN神经网络,Python,TensorFlow。bp神经网络是开启我神经网络大门的钥匙,我学习的过程中,我曾对神经网络持有一种怀疑的态度,原因是,我对神经网络的认知是采用了一种特殊的数据结构,运用逐步接近最优的算法,通过大量输入与输出样本,模拟输入与输出中的某种规律,这种数据结构就是神经元,所采用的算法就是构造误差函数,使用梯度下降令误差函数达到最小。

梯度下降是其实并不难理解,假设y=f(x)是一元连续函数,梯度下降就是不断令x=x+ny’,假如y是某定义域内的凹函数,我们知道,y’=0的点是,该函数的极小值点,极小值点的左侧y’<0,而右侧y’>0,所以如果x梯度下降的起点在极小值点的左边,那么可见x在逐步增加的,如果起点在在极小值点右边,则x会逐步减少,且这种变化的幅度会随函数导数大小而改变,导数大变化幅度也大,导数小,变化幅度也小,可以想象,对于凹函数给定任意起点,不断使用梯度下降,最终x会收敛在极小值点。

我们可以求出误差函数对某一参数的偏导数,然后不断用梯度下降修正这个参数,当这个误差函数收敛到一个值时,则说明误差函数的极小值点(并非严谨定义上的极小值)时,参数应该接近的当前值,此时输出结果与预期结果相差的最小。神经网络用它独有的数据结构定义了大量参数,对这些参数求偏导并梯度下降,使误差函数收敛到一个值。

RNN和LSTM也是用的这个道理,只不过RNN和LSTM把一组运算的输出也作为输入的一部分进行运算,通常这两组数据具有时间先后关系,RNN是将之前的数据全部作为参考,而LSTM又引入了一组参数,可以令之前部分参数作为参考,即模型具备了遗忘能力。

学完Python后,我开始学习Python,Python我感觉从某个角度来说,和JavaScript很像,虽然是第一次接触Python,但是对于软件工程的学生来说,只做到能读懂代码还是很轻松的,我很快就完成了Python学习阶段,只学会了基础的语法和特性,Python的代码真的很简洁,写起来比Java得劲多了,但是Python还有很多进阶技巧我没来得及学,这个日后一定要补上。

TensorFlow框架把模型都封装好了,不改模型的话,只需要用它的api把运算图构建出来就好了,这个过程还好,理解神经网络后很快就上手了,但是一些机器学习领域的术语很让我困扰,不过还是在不断实践和查阅资料的过程中搞明白了。

结果

课设完成了,准确率还行,只预测后一天的价格情况还好,越往后越跑偏,但是考虑到本身股票一天之内就没多大变化,所以这个准确率虽然高,但多少给人一点自欺欺人的感觉,说实话我不认为股票有什么规律可以用神经网络来模拟,股票作为一个多人博弈的过程,它很多影响因素在于外界,我认为单从历史数据预测未来不是很把握,所以对于这个准确率我还是蛮惊讶的,期末又和老师以及其他同学交流过,我这套代码只能说是实现了,在数据预处理和超参数调整方面还有进步空间,马上要考研了,近期可能不会有很多时间来改进了,待以后慢慢摸索学习吧

相对误差的平均值 0.03125852369012719

在这里插入图片描述

评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值