LSTM對股票的收益進行預測(Keras實現)

目錄

一、概述:

二、股票數據準備

三、股票數據預處理

1、數據特徵歸一化(標準化)

2、將數據集轉化爲有監督學習問題

四、股票數據劃分爲訓練集和測試集

五、模型構建及其預測

1、搭建LSTM模型並繪製損失圖

2、預測並反轉數據(反歸一化)

3、繪製模型預測結果圖

六、模型評估


一、概述:

傳統的線性模型難以解決多變量或多輸入問題,而神經網絡如LSTM則擅長於處理多個變量的問題,該特性使其有助於解決時間序列預測問題。

本文將初步探究 LSTM 在股票市場的應用。通過使用LSTM對股票收益的預測,可以瞭解到:(1)如何將原始數據集轉換爲可用於時間序列預測的數據。(2)如何準備數據並使LSTM適合多變量時間序列預測問題。(3)如何進行預測並將結果重新調整回原始數據。

本文以600000.SH股票數據爲基準進行分析,以2016年3月1日至2017年12月31日爲回測期,進行收益率的預測模擬。

本實驗所需要導入的庫如下:

import pandas as pd
# 核心代碼,設置顯示的最大列、寬等參數,消掉打印不完全中間的省略號
pd.set_option('display.max_columns', 1000)
pd.set_option('display.width', 1000)
pd.set_option('display.max_colwidth', 1000)

import matplotlib.pyplot as plt
from pandas import read_excel
import numpy as np
from pandas import DataFrame
from pandas import concat
from sklearn.preprocessing import MinMaxScaler
from keras.models import Sequential
from keras.layers import LSTM,Dense,Dropout
from numpy import concatenate
from sklearn.metrics import mean_squared_error,mean_absolute_error,r2_score
from math import sqrt

二、股票數據準備

前兩篇博客對股票數據進行了詳細分析,根據股票指標間的相關關係,刪除成交量市值pb這三個指標,實現了股票數據的降維。具體股票數據如下:

#定義字符串轉換爲浮點型(此處是轉換換手率)
def str_to_float(s):
    s=s[:-1]
    s_float=float(s)
    return s_float

## 讀取excel文件,並將‘日期’列解析爲日期時間格式,並設爲索引
stock_data=read_excel('stock_data/600000.SH.xlsx',parse_dates=['日期'],index_col='日期')
stock_data.drop(['交易日期','成交量','市值','pb'],axis=1, inplace=True) #刪除多列數據
stock_data['換手率']=stock_data['換手率'].apply(str_to_float)
#對股票數據的列名重新命名
stock_data.columns=['open','high','low','close','turnover','pe']
stock_data.index.name='date' #日期爲索引列
#將數據按日期這一列排序(保證後續計算收益率的正確性)
stock_data=stock_data.sort_values(by='date')
# 增加一列'earn_rate', 存儲每日的收益率
stock_data['earn_rate'] = stock_data['close'].pct_change()
#缺失值填充
stock_data['earn_rate'].fillna(method='bfill',inplace=True)
# 打印數據的前5行
print(stock_data.head())

 部分數據如下:

三、股票數據預處理

採用LSTM模型時,需要對數據進行適配處理,其中包括歸一化變量(包括輸入和輸出值)和將數據集轉化爲有監督學習問題,使其能夠實現通過前一個時刻(t-1)的股票數據和收益率預測當前時刻(t)的股票收益率。

1、數據特徵歸一化(標準化)

LSTM對輸入數據的規模很敏感,特別是當使用sigmoid(默認)或tanh激活函數時。需要將數據重新調整到0到1的範圍(也稱爲標準化)。本實驗使用scikit-learn庫中的MinMaxScaler預處理類實現數據集的規範化。

#獲取DataFrame中的數據,形式爲數組array形式
values=stock_data.values
#確保所有數據爲float類型
values=values.astype('float32')

# 特徵的歸一化處理
scaler = MinMaxScaler(feature_range=(0, 1))
scaled = scaler.fit_transform(values)
print(scaled)

歸一化結果如下:

2、將數據集轉化爲有監督學習問題

在本文中,定義一個名爲series_to_supervised()函數該函數採用單變量或多變量時間序列並將其構建爲監督學習數據集。

#定義series_to_supervised()函數
#將時間序列轉換爲監督學習問題
def series_to_supervised(data, n_in=1, n_out=1, dropnan=True):
	"""
	Frame a time series as a supervised learning dataset.
	Arguments:
		data: Sequence of observations as a list or NumPy array.
		n_in: Number of lag observations as input (X).
		n_out: Number of observations as output (y).
		dropnan: Boolean whether or not to drop rows with NaN values.
	Returns:
		Pandas DataFrame of series framed for supervised learning.
	"""
	n_vars = 1 if type(data) is list else data.shape[1]
	df = DataFrame(data)
	cols, names = list(), list()
	# input sequence (t-n, ... t-1)
	for i in range(n_in, 0, -1):
		cols.append(df.shift(i))
		names += [('var%d(t-%d)' % (j+1, i)) for j in range(n_vars)]
	# forecast sequence (t, t+1, ... t+n)
	for i in range(0, n_out):
		cols.append(df.shift(-i))
		if i == 0:
			names += [('var%d(t)' % (j+1)) for j in range(n_vars)]
		else:
			names += [('var%d(t+%d)' % (j+1, i)) for j in range(n_vars)]
	# put it all together
	agg = concat(cols, axis=1)
	agg.columns = names
	# drop rows with NaN values
	if dropnan:
		agg.dropna(inplace=True)
	return agg

該函數有四個參數:

  • data:輸入數據需要是列表或二維的NumPy數組的觀察序列。
  • n_in:輸入的滯後觀察數(X)。值可以在[1..len(data)]之間,可選的。默認爲1。
  • n_out:輸出的觀察數(y)。值可以在[0..len(data)-1]之間,可選的。默認爲1。
  • dropnan:Bool值,是否刪除具有NaN值的行,可選的。默認爲True。

該函數返回一個值:

  • 返回:用於監督學習的Pandas DataFrame。

新數據集構造爲DataFrame,每列適當地由變量編號和時間步驟命名。使其可以根據給定的單變量或多變量時間序列設計各種不同的時間步長序列類型預測問題。

本文股票數據轉換爲監督學習問題如下:

#將時間序列轉換爲監督學習問題
reframed = series_to_supervised(scaled, 1, 1)
# 刪除不想預測的特徵列,這裏只預測收益率
reframed.drop(reframed.columns[[7,8,9,10,11,12]], axis=1, inplace=True)
# 打印數據的前5行
print(reframed.head())

結果如下:

四、股票數據劃分爲訓練集和測試集

將處理後的數據集劃分爲訓練集和測試集。我們將2016年3月1日至2017年12月31日的股票數據作爲測試集,其餘作爲訓練集。將訓練集和測試集的最終輸入(X)轉換爲爲LSTM的輸入格式,即[samples,timesteps,features]

Keras LSTM層的工作方式是通過接收3維(N,W,F)的數字陣列,其中N是訓練序列的數目,W是序列長度,F是每個序列的特徵數目。

# 劃分訓練集和測試集
values = reframed.values
train = np.concatenate([values[:774, :],values[1219:,:]])
test = values[774:1219, :]
# 劃分訓練集和測試集的輸入和輸出
train_X, train_y = train[:, :-1], train[:, -1]
test_X, test_y = test[:, :-1], test[:, -1]
#轉化爲三維數據
# reshape input to be 3D [samples, timesteps, features]
train_X = train_X.reshape((train_X.shape[0], 1, train_X.shape[1]))
test_X = test_X.reshape((test_X.shape[0], 1, test_X.shape[1]))
print(train_X.shape, train_y.shape)
print(test_X.shape, test_y.shape)

訓練集和測試集的輸入格式如下:

五、模型構建及其預測

1、搭建LSTM模型並繪製損失圖

本實驗使用keras深度學習框架對模型進行快速搭建。建立Sequential模型,向其中添加LSTM層,設定Dropout爲0.5,加入Dense層將其維度聚合爲1,激活函數使用relu(也用了sigmoid作爲激活函數,但實驗效果不如relu),損失函數定爲均方差Mean Absolute Error(MAE)。優化算法採用Adam,模型採用50個epochs並且每個batch的大小爲100。 

其中:隱藏層有64個神經元,輸出層1個神經元(迴歸問題),輸入變量是一個時間步(t-1)的特徵。在fit()函數中設置validation_data參數,記錄訓練集和測試集的損失。

# 搭建LSTM模型
model = Sequential()
model.add(LSTM(64, input_shape=(train_X.shape[1], train_X.shape[2])))
model.add(Dropout(0.5))
model.add(Dense(1,activation='relu'))
model.compile(loss='mae', optimizer='adam')
# fit network
history = model.fit(train_X, train_y, epochs=50, batch_size=100, validation_data=(test_X, test_y), verbose=2,shuffle=False)

# 繪製損失圖
plt.plot(history.history['loss'], label='train')
plt.plot(history.history['val_loss'], label='test')
plt.title('LSTM_600000.SH', fontsize='12')
plt.ylabel('loss', fontsize='10')
plt.xlabel('epoch', fontsize='10')
plt.legend()
plt.show()

 完成訓練和測試後繪製損失圖如下:

2、預測並反轉數據(反歸一化)

需要將預測結果和測試集數據組合然後進行比例反轉(invert the scaling),同時需要將測試集上的預期值也進行比例轉換。 

這裏爲什麼進行比例反轉(反歸一化)呢?(因爲我們將原始數據進行了預處理(連同輸出值y),此時的誤差損失計算是在處理之後的數據上進行的,爲了計算在原始比例上的誤差需要將數據進行轉化。反轉時的矩陣大小一定要和原來的大小(shape)完全相同,否則就會報錯。)

#模型預測收益率
y_predict = model.predict(test_X)
test_X = test_X.reshape((test_X.shape[0], test_X.shape[2]))

# invert scaling for forecast
#將預測結果按比例反歸一化
inv_y_test = concatenate((test_X[:, :6],y_predict), axis=1)
inv_y_test = scaler.inverse_transform(inv_y_test)
inv_y_predict=inv_y_test[:,-1]

# invert scaling for actual
#將真實結果按比例反歸一化
test_y = test_y.reshape((len(test_y), 1))
inv_y_train = concatenate((test_X[:, :6],test_y), axis=1)
inv_y_train = scaler.inverse_transform(inv_y_train)
inv_y = inv_y_train[:, -1]
print('反歸一化後的預測結果:',inv_y_predict)
print('反歸一化後的真實結果:',inv_y)

反歸一化後的部分結果如下:

3、繪製模型預測結果圖

plt.plot(inv_y,color='red',label='Original')
plt.plot(inv_y_predict,color='green',label='Predict')
plt.xlabel('the number of test data')
plt.ylabel('earn_rate')
plt.title('2016.3—2017.12')
plt.legend()
plt.show()

六、模型評估

迴歸模型常用評價指標有:均方誤差(Mean Squared Error,MAE)、均方根誤差(Root Mean Squard Error,RMSE)、平均絕對誤差(MAE)、R squared

本實驗的LSTM模型主要採用RMSE作爲評價標準。主要比較訓練集誤差損失train_loss和驗證集誤差損失val_loss和預測集誤差損失pre_loss。很顯然loss的值越低說明模型擬合的效果越好。

爲了測試模型,使用了所有的評估指標,如下:


#迴歸評價指標
# calculate MSE 均方誤差
mse=mean_squared_error(inv_y,inv_y_predict)
# calculate RMSE 均方根誤差
rmse = sqrt(mean_squared_error(inv_y, inv_y_predict))
#calculate MAE 平均絕對誤差
mae=mean_absolute_error(inv_y,inv_y_predict)
#calculate R square
r_square=r2_score(inv_y,inv_y_predict)
print('均方誤差: %.6f' % mse)
print('均方根誤差: %.6f' % rmse)
print('平均絕對誤差: %.6f' % mae)
print('R_square: %.6f' % r_square)

結果爲:

 

 

 

本實驗旨在將LSTM應用於股票數據預測,通過使用LSTM對股票收益的預測,學習時間序列數據的處理和轉化。使用LSTM來對股票數據的預測具有一定的可行性,但本實驗效果不佳。同時可以使用此方法預測股票的價格,每日最高價等,思路相似。如果要形成一個在股票市場比較實用的 LSTM 模型,還需要在 features 選擇、模型構建、模型參數選擇以及調優等方面進行學習研究。

本博客所述以及代碼僅供學習交流。

 

 

 

 

 

 

參考:

1、如何將時間序列轉換爲Python的監督學習問題

2、Keras中LSTM的多變量時間序列預測

3、空氣污染預測

4、用於時間序列預測的LSTM神經網絡

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章