使用Keras框架进行单变量时间序列预测——以上证指数为例

写在前面

之前一直纠结于DL框架的选用,直到看到了《Practical Time Series Analysis》这本书,了解到Keras的简洁与高效,使我更加坚定了使用Keras的决心,不过由于其高度模块化,对一些功能的定制不支持,所以熟练使用后还是要Torch|Tensorflow进行训练(个人理解)。

本文代码部分基于Packt出版社的《Practical Time Series Analysis》一书第五章——深度学习以进行时间序列预测,做了一些更改,数据使用上证指数(本文使用网易财经的免费下载接口->下载地址),需要本书Ebook的可以私信我。

代码及其解释

# 用于训练&测试数据的分割(设置时间点)
from datetime import datetime

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



# 使用sklearn中的MinMaxScaler函数处理数据(归一化)
from sklearn.preprocessing import MinMaxScaler

# 使用sklearn中的MAE函数,计算平均绝对误差
from sklearn.metrics import mean_absolute_error as MAE

# 使用tk库绘制图形,便于图形的调整
import matplotlib as mpl
mpl.use('TkAgg')


# 加载数据&格式化数据
def import_csv(stock_code, rows):
    df = pd.read_csv(stock_code + '.csv', encoding='gbk')
    df.rename(columns={'日期': 'date', '收盘价': 'close'}, inplace=True)
    df.sort_values(by='date', inplace=True)
    
    df = df[['date', 'close']][-rows:]
    df['date'] = pd.to_datetime(df['date'])
    df.reset_index(drop=True, inplace=True)
    return df


stock_code = '000001'

# 选取全部数据的后7000个值作为模型的数据
df = import_csv(stock_code, 7000)

# 箱形图绘制,用于可视化收盘价的中心趋势和离散程度
# import seaborn as sns
# plt.figure()
# fig1 = sns.boxplot(df['close'])
# fig1.set_title('Box plot of %s'%stock_code)
# plt.show()

# 数据正规化处理
scaler = MinMaxScaler(feature_range=(0, 1))
df['scaled_close'] = scaler.fit_transform(np.array(df['close']).reshape(-1, 1))

# 数据集划分处理
split_date = datetime(year=2019, month=9, day=27)
df_train = df.loc[df['date'] < split_date]
df_val = df.loc[df['date'] >= split_date]
df_val.reset_index(drop=True, inplace=True)

# print(df_train.shape, df_val.shape)
# exit()


def makeXy(df, time_steps):
    # 用于生成训练模型的数组数据
    # 使用过去time_steps长度的数据来预测下一天的数据
    X = []
    y = []
    for i in range(time_steps, df.shape[0]):
        X.append(list(df.loc[i - time_steps:i - 1]))
        y.append(df.loc[i])
    X, y = np.array(X), np.array(y)
    return X, y


time_steps = 5
# 生成训练数据
X_train, y_train = makeXy(df_train['scaled_close'], time_steps)
X_val, y_val = makeXy(df_val['scaled_close'], time_steps)

X_train = X_train.reshape((X_train.shape[0], X_train.shape[1], 1))
X_val = X_val.reshape((X_val.shape[0], X_val.shape[1], 1))


# print(X_train.shape, y_train.shape)
# print(X_val.shape, y_val.shape)
# exit()

def train_model():
    from keras.layers import Dense, Input, Dropout
    from keras.layers.recurrent import LSTM
    from keras.models import Model
    from keras.optimizers import Adam
    from keras.callbacks import ModelCheckpoint
    # 定义LSTM神经网络层结构(利用函数式AP构建)
    input_layer = Input(shape=(time_steps, 1), dtype='float32')
    lstm_layer1 = LSTM(64, input_shape=(time_steps, 1), return_sequences=True)(input_layer)
    lstm_layer2 = LSTM(32, input_shape=(time_steps, 64), return_sequences=False)(lstm_layer1)

    dropout_layer = Dropout(.5)(lstm_layer2)
    output_layer = Dense(1, activation='linear')(dropout_layer)

    optimizer = Adam(lr=0.05, beta_1=0.9, beta_2=0.99, epsilon=0.1, decay=0.0, amsgrad=False)

    ts_model = Model(inputs=input_layer, outputs=output_layer)
    # 编译模型
    ts_model.compile(loss='mean_absolute_error', optimizer=optimizer)

    # ts_model.summary();exit() # 输出模型层结构

    # 存储损失函数最小值时的模型为hdf文件
    save_all = ModelCheckpoint('%s_LSTM_weights.{epoch:02d}-{val_loss:.4f}.h5' % stock_code,
                               monitor='val_loss', verbose=0, save_best_only=True,
                               save_weights_only=False, mode='min', period=1)
    # 开始训练模型(拟合)
    ts_model.fit(x=X_train, y=y_train, batch_size=16,
                 epochs=25, verbose=2, callbacks=[save_all],
                 validation_data=(X_val, y_val), shuffle=True)

# 首次运行程序得到误差最小的模型权重
# 第二次运行注释掉下面两行代码,自行添加最优模型的文件名
# 即可得到模型的预测结果,最后绘制成图
train_model()
exit()


# 读取最优模型
from keras.models import load_model

best_model = load_model('%s_LSTM_weights.21-0.0053.h5' % stock_code)
# 预测
preds = best_model.predict(X_val)
# 处理预测的数据(降维,便于2D绘图)
pred_close = np.squeeze(scaler.inverse_transform(preds))

# 输出MAE信息
mae = MAE(df_val['close'].loc[time_steps:], pred_close)
print('MAE : ', round(mae, 4))

# 设置绘制的图形的步长
plot_steps = 100

plt.figure()

plt.plot(range(plot_steps), df_val['close'].loc[time_steps:plot_steps + time_steps - 1], linewidth=1., color='r')
plt.plot(range(plot_steps), pred_close[:plot_steps], linewidth=1., color='b')

# 设置图例
plt.legend(['Actual', 'Predicted'], loc=2)
plt.title('Actual & Predicted %s close_price' % stock_code)

# 设置标签
plt.ylabel('close_price')
plt.xlabel('Index')

plt.show()
# 存图
plt.savefig('LSTM_%s_.png' % stock_code, format='png', dpi=300)

1

图1

模型的缺点&分析

  1. 由于输入的数据只有收盘价信息,导致这个模型的输出出现了很严重的滞后性。如果选用股价波动幅度不大的股票进行预测,其滞后性会小一些,但依然存在。

  2. 影响股价波动的因素有很多,如市场信息、政策调整、复权拆股等,从这些方面进行分析可能会改进模型。

  3. 股价波动是一种随机游走现象,这个观点已经被证明,所以使用框架进行预测只能得到一个大致的趋势信息,不具有普适性,鉴于此,可以通过金融学的相关知识来分析,可能会得到一些好的结果。(上面提到的那本书中前几章有提到)

  4. 可以使用Tensorflow&PyTorch框架进一步定制模型,使用更好的优化算法等使得模型Robust性加强。

    ⋯ ⋯ \cdots\cdots

后记

时间序列预测的滞后性问题比较明显,针对这个问题需要结合具体数据进行分析,找到关键的一两个点,就会有所突破。

Ubuntu训练模型确实快。还没调成GPU速度就已经比Windows下用GPU快很多了。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

zorchp

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

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

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

打赏作者

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

抵扣说明:

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

余额充值