為了預測股票,我用TensorFlow深度學習了股市資料

僱個城管打天下發表於2019-02-26

完整原始碼可在微信公眾號:「01二進位制」後臺回覆:「股市分析」獲取

閱讀此文前建議先閱讀《找物件的過程中,我竟然理解了什麼是機器學習!》

前言

相信大家這幾天或多或少的都開始關注到股市了,雖然我還不是很懂裡面的一些套路,但是從最近各個公眾號的推送裡面,我也看到最近的股市確實是形勢大好。對很多人來說,股票就和房價一樣,他的升與降牽動著眾多人的心。這幾天很多qq群、微信群都開始討論起股票了,各位坊間大神也紛紛開始預測各種股票走勢了。

股票價格是典型的時間序列資料(簡稱時序資料),會受到經濟環境、政府政策、人為操作多種複雜因素的影響,所以說股票價格預測是一件非常唬人的事情。但是基於歷史資料,以股票價格為例,介紹如何對時序資料進行預測,仍然值得一做。

不過今天我們不聊股市,因為我也不是很懂,今天我們來聊聊我們知道的東西。如今深度學習在金融市場的應用越來越廣泛,我們能否利用已有的歷史資料通過深度學習的方式來進行預測呢?

準備工作

答案自然是可以的,雖然我們無法非常準確的進行預測,但是作為一個深度學習入手的專案是完完全全可以的。

實驗環境

老樣子,以免出現因環境導致的問題,先將實驗環境列出:

  • MacOS 10.14.3
  • Python 3.6.8(Anaconda)
  • Jupyter Notebook
  • 使用的包有:
    • TensorFlow
    • Keras
    • matplotlib
    • pandas

資料

此次實驗,我們採用STATWORXS&P 500股價資料,該資料集爬取自Google Finance API,已經進行過缺失值處理。他們的官方網站是:www.statworx.com/。

資料集可在微信公眾號:「01二進位制」後臺回覆:「股市資料集」獲取

資料預覽

在這裡我們還是使用pandas,主要用於資料清洗和整理

import pandas as pd
data=pd.read_csv('data/data_stocks.csv')
data.info()
複製程式碼

執行data.info()可以檢視特徵的概要:

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 41266 entries, 0 to 41265
Columns: 502 entries, DATE to NYSE.ZTS
dtypes: float64(501), int64(1)
memory usage: 158.0 MB
複製程式碼

從上述結果可知:該資料集資料共502列,41266行,502列分別為:

  • DATE:該行資料的時間戳
  • SP500:可以理解為大盤指數
  • 其他:可以理解為500支個股的股價

檢視資料的前五行

data.head()
複製程式碼

為了預測股票,我用TensorFlow深度學習了股市資料

繪製大盤趨勢折線圖

plt.plot(data['SP500'])
複製程式碼

結果如下:

為了預測股票,我用TensorFlow深度學習了股市資料

Tips:此次實驗的除錯環境為Jupyter Notebook,我們最好在開頭匯入matplotlib包的時候在加一行%matplotlib inline,這樣就可以在Jupyter Notebook中內嵌繪圖,並且省略掉plt.show()這一步。

資料整理

在這裡,我們需要將資料集分為訓練和測試資料。分配比為8:2,即訓練資料包含總資料集的80%。當然在這之前我們需要先將DATE這個無關變數捨去。

data.drop('DATE', axis=1, inplace=True)
data_train = data.iloc[:int(data.shape[0] * 0.8), :]
data_test = data.iloc[int(data.shape[0] * 0.8):, :]
複製程式碼

我們來檢視一下訓練集和測試集的shape

為了預測股票,我用TensorFlow深度學習了股市資料

資料歸一化

將屬性縮放到一個指定的最大和最小值(通常是(-1,1))之間,這可以通過sklearn.preprocessing.MinMaxScaler類實現。

使用這種方法的目的包括:

  1. 對於方差非常小的屬性可以增強其穩定性。

  2. 維持稀疏矩陣中為0的條目。

scaler = MinMaxScaler(feature_range=(-1, 1))
scaler.fit(data_train)
data_train = scaler.transform(data_train)
data_test = scaler.transform(data_test)
複製程式碼

預測

在此次預測過程中,我採用TensorFlow這個深度學習框架,它是目前領先的深度學習和神經網路計算框架。這一部分推薦有基礎的人閱讀,在這推薦我還在整理的TensorFlow系列,有興趣的可以瞭解下。

這裡我們需要解決的問題是:使用當前時刻的500支個股股價,預測當前時刻的大盤指數。即一個迴歸問題,輸入共500維特徵,輸出一維,即[None, 500] => [None, 1]

設定X與Y

X_train = data_train[:, 1:]
y_train = data_train[:, 0]
X_test = data_test[:, 1:]
y_test = data_test[:, 0]
複製程式碼

這裡的x和y是已經分類好的資料集,只是用X和Y兩個變數表示,可以理解為函式裡面的X和Y。

設定超引數

input_dim = X_train.shape[1]
output_dim = 1
hidden_1 = 1024
hidden_2 = 512
hidden_3 = 256
hidden_4 = 128
batch_size = 256
epochs = 10
複製程式碼

這裡我們設定了幾個超引數,input_dim表示輸入資料的維度,即500。output_dim表示輸出資料的維度,即1。在該模型中設定了4層隱藏層,第一層包含1024個神經元,略大於輸入大小的兩倍。 後續的隱藏層總是前一層的一半大小,即分別為512,256和128個神經元。 每個後續層的神經元數量的減少壓縮了網路在先前層中識別的資訊。 當然,其他網路架構和神經元配置也是可能的,只是由於本文只是一個入門的專案所以並未深究。

在機器學習中,超引數是在開始學習過程之前設定值的引數,而不是通過訓練得到的引數資料。通常情況下,需要對超引數進行優化,給學習機選擇一組最優超引數,以提高學習的效能和效果。

設定佔位符(placeholder)

X = tf.placeholder(shape=[None, input_dim], dtype=tf.float32)
Y = tf.placeholder(shape=[None], dtype=tf.float32)
複製程式碼

為了適應我們的模型,我們需要兩個佔位符:X(神經網路的輸入)和Y(神經網路的輸出)。

設定神經網路

根據之前設定好的超引數進行神經網路的配置,其中w為權重,b為偏置值

# 第一層
W1 = tf.get_variable('W1', [input_dim, hidden_1], initializer=tf.contrib.layers.xavier_initializer(seed=1))
b1 = tf.get_variable('b1', [hidden_1], initializer=tf.zeros_initializer())
# 第二層
W2 = tf.get_variable('W2', [hidden_1, hidden_2], initializer=tf.contrib.layers.xavier_initializer(seed=1))
b2 = tf.get_variable('b2', [hidden_2], initializer=tf.zeros_initializer())
# 第三層
W3 = tf.get_variable('W3', [hidden_2, hidden_3], initializer=tf.contrib.layers.xavier_initializer(seed=1))
b3 = tf.get_variable('b3', [hidden_3], initializer=tf.zeros_initializer())
# 第四層
W4 = tf.get_variable('W4', [hidden_3, hidden_4], initializer=tf.contrib.layers.xavier_initializer(seed=1))
b4 = tf.get_variable('b4', [hidden_4], initializer=tf.zeros_initializer())
# 輸出層
W5 = tf.get_variable('W5', [hidden_4, output_dim], initializer=tf.contrib.layers.xavier_initializer(seed=1))
b5 = tf.get_variable('b5', [output_dim], initializer=tf.zeros_initializer())
複製程式碼

瞭解輸入層,隱藏層和輸出層之間所需的變數尺寸非常重要。作為多層感知器(MLP,這裡使用的網路型別)的一個經驗法則,前一層的第二維是當前層中權重矩陣的第一維。這可能聽起來很複雜,但實質上只是每個圖層都將其輸出作為輸入傳遞到下一圖層。偏差維度等於當前圖層的權重矩陣的第二維度,其對應於該層中的神經元的數量。

設定網路體系結構

在定義所需的權重和偏置變數後,需要指定網路拓撲結構和網路結構。因此,佔位符(資料)和變數(權重和偏置)需要組合成一個連續矩陣乘法系統。

h1 = tf.nn.relu(tf.add(tf.matmul(X, W1), b1))
h2 = tf.nn.relu(tf.add(tf.matmul(h1, W2), b2))
h3 = tf.nn.relu(tf.add(tf.matmul(h2, W3), b3))
h4 = tf.nn.relu(tf.add(tf.matmul(h3, W4), b4))
out = tf.transpose(tf.add(tf.matmul(h4, W5), b5))
複製程式碼

此外,網路的隱藏層需要被啟用函式啟用。啟用函式是網路體系結構的重要組成部分,因為它們將非線性引入到系統中。這裡採用最常見的ReLU啟用函式。

下圖說明了網路架構。 該模型由三個主要構建塊組成。 輸入層,隱藏層和輸出層。 該體系結構稱為前饋網路。 前饋表示該批資料僅從左向右流動。 其他網路架構,例如遞迴神經網路,也允許資料在網路中“向後”流動。

為了預測股票,我用TensorFlow深度學習了股市資料

設定損失函式(loss function)和優化器(Optimizer)

loss = tf.reduce_mean(tf.squared_difference(out, Y))
optimizer = tf.train.AdamOptimizer().minimize(loss)
複製程式碼

這一部分沒啥好說的,記住這麼寫就可以了,想了解的話可以去我的TensorFlow中瞭解下。

執行訓練過程

在定義好神經網路的佔位符,結構,損失函式函式和優化器之後,我們就可以開始對模型進行訓練了。訓練資料集分為n / batch_size批次,這些批次按順序送入網路。 此時佔位符X和Y開始起作用。 它們儲存輸入和目標資料,並將它們作為輸入和目標呈現給網路。

資料X分批次流經網路,直到到達輸出層。 在那裡,TensorFlow將模型預測與當前批次中實際觀察到的目標Y進行比較。 之後,TensorFlow進行優化步驟並更新與所選學習方案相對應的網路引數。 更新了權重和偏差後,對下一批進行取樣,並重復該過程。 該過程將繼續,直到所有批次都已呈現給網路。對所有資料進行一次全面掃描被稱為一個epoch(輪)

一旦達到了最大數量的epochs或使用者定義的另一個停止標準,網路的訓練就會停止。

with tf.Session() as sess:
    # 初始化所有變數
    sess.run(tf.global_variables_initializer())

    for e in range(epochs):
        # 將資料打亂
        shuffle_indices = np.random.permutation(np.arange(y_train.shape[0]))
        X_train = X_train[shuffle_indices]
        y_train = y_train[shuffle_indices]

        for i in range(y_train.shape[0] // batch_size):
            start = i * batch_size
            batch_x = X_train[start : start + batch_size]
            batch_y = y_train[start : start + batch_size]
            sess.run(optimizer, feed_dict={X: batch_x, Y: batch_y})

            if i % 50 == 0:
                print('MSE Train:', sess.run(loss, feed_dict={X: X_train, Y: y_train}))
                print('MSE Test:', sess.run(loss, feed_dict={X: X_test, Y: y_test}))
                y_pred = sess.run(out, feed_dict={X: X_test})
                y_pred = np.squeeze(y_pred)
                plt.plot(y_test, label='test')
                plt.plot(y_pred, label='pred')
                plt.title('Epoch ' + str(e) + ', Batch ' + str(i))
                plt.legend()
                plt.show()
複製程式碼

執行結果為:

MSE Train: 9.56518e-05
MSE Test: 0.0025863606
MSE Train: 6.0618047e-05
MSE Test: 0.0025002975
MSE Train: 0.00014856807
MSE Test: 0.0017371146
MSE Train: 0.00016200903
MSE Test: 0.0025396077
MSE Train: 0.00010259051
MSE Test: 0.0030134947
MSE Train: 7.979905e-05
MSE Test: 0.0023832247
MSE Train: 5.92488e-05
MSE Test: 0.0032762515
MSE Train: 8.747634e-05
MSE Test: 0.004848172
MSE Train: 8.5051965e-05
MSE Test: 0.0032768336
複製程式碼

最後測試集的loss在0.003左右,可以說是比較精確了。

視覺化訓練結果:

20190226203532

有很多方法可以進一步改善這一結果:增加隱藏層和改進神經元的設計,選擇不同的初始化和啟用方案,提前停止等等。 此外,不同型別的深度學習模型,例如迴圈神經網路,可以在此任務上實現更好的效能。 但是,這不是這篇介紹性文章的範圍。有興趣的小夥伴可以自行查詢資料。

結論

正如開頭所說,股票的價格會受到經濟環境、政府政策、人為操作多種複雜因素的影響,真正想要預測股市走向單靠這篇文章裡面所敘述的遠遠不夠,本文旨在結合時下熱點進行一次有關TensorFlow的技術推薦。

TensorFlow的釋出是深度學習研究中的一個里程碑事件。作為一個學生,筆者也在積極的學習中,有興趣學習的小夥伴可以在公眾號後臺(就是文末的那個公眾號)回覆「TensorFlow視訊」獲取一份質量較高的TensorFlow視訊,也可以新增我的微信一起交流進步。

完整原始碼可在微信公眾號:「01二進位制」後臺回覆:「股市分析」獲取

參考資料


“萬水千山都是情,給個關注行不行?”

為了預測股票,我用TensorFlow深度學習了股市資料

相關文章