日元對人民幣匯率的大數據分析與預測
實驗說明
實驗內容
通過現有的數據,建立數學模型,預測未來一個月的匯率變化趨勢。本文采用日元對人民幣的匯率數據,時間是1990年1月1日到2018月8月21日。利用Tensorflow搭建模型並完成預測,數學模型用Lstm(長短期記憶)人工神經網絡,Lstm是RNN(循環神經網絡)的一種變形,是在RNN的基礎上施加了若干個門來控制,使其在長時間步的傳遞過程中減少信息失效的可能。
實驗知識點
本次試驗包含以下知識點:
1、Python基本知識
2、Python基礎庫如numpy,panda,matplotlib
3、TensorFlow模塊的使用
4、Lstm神經網絡
其中Lstm神經網絡講解如下:
要理解Lstm,首先需要了解循環神經網絡(RNN),循環神經網絡可以將信息持久化。
這個相對於原始的神經網絡,就是加了一個環,也就是X是輸入,h為輸出,A為隱藏層,如果將環展開:
循環神經網絡的一個核心思想是將以前的信息連接到當前的任務中來,但是,如果前面的信息與當前信息距離增大,RNN對於連接這些信息顯得無能為力。而Lstm是一種特殊的RNN,能學習長期依賴關系。一般的RNN,其模塊非常簡單,只有一個tanh層。
Lstm也是這種結構,但其模塊的結構不同,如下所示。
Lstm的核心是元胞狀態,Lstm通過門的結構來控制元胞狀態添加或者刪除信息,門是一種選擇性讓信息通過的方法,也就是Lstm不同於RNN的地方。Lstm也有多種版本,但核心部分都是一樣的,本文中不再詳細展開討論Lstm的每個部分。
實驗環境
運行環境window10
開發環境python3.7
調試環境jupyter notebook
適合人群
本課程難度為一般,屬於初級級別課程,適合具有 Python 基礎,想對 Python 基礎知識加深鞏固的用戶。
·具有python基礎知識、神經網絡基礎知識
·TensorFlow學習
·Lstm神經網絡學習
代碼獲取
https://www.cnblogs.com/lingxingyitiao/p/12102096.html
開發准備
安裝Anaconda,Anaconda包含有非常齊全的基礎庫,因此非常便於使用,並且安裝非常簡單,只要下載解壓,按照提示直接安裝完畢即可。安裝完成可以查看python是否可用以及python的版本。命令行輸入python即可。
輸入pip list查看庫列表,部分截圖如下
通過查看可以發現還需要安裝TensorFlow庫
實驗所需文件部分數據如下所示
項目文件結構
實驗內容及步驟
1、導入實驗所需要的庫
import numpy as np import tensorflow as tf from tensorflow.contrib import rnn import matplotlib.pyplot as plt from tensorflow.contrib.learn.python.learn.estimators.estimator import SKCompat from matplotlib import style import pandas as pd
2、數據預處理
導入數據並查看前五行數據
data = pd.read_excel('日元-人民幣.xls',header = 0, sheetname='Sheet1') data.head()
獲取時間及收盤價,這里收盤價可以用其他價格替換,本文預測收盤價。
time = data.iloc[:,0].tolist()
data = data.iloc[:,4].tolist()
觀察原數據基本特征。
style.use('ggplot') plt.figure(figsize=(16,9)) plt.rcParams['font.sans-serif'] = 'SimHei' ##設置字體為SimHei顯示中文 plt.rcParams['axes.unicode_minus'] = False ##設置正常顯示符號 plt.title('原始數據') plt.plot(time,data) plt.show()
從圖中可以知道原始數據值在4到9的范圍,連續數據值的預測需要輸出為tanh的輸出,即RNN最終經由tanh激活后輸出的值位於[-1,1]內,因此需要將原始數據進行縮放,方法主要有兩種,極差規格化和標准化。在這里先定義縮放的函數,本文使用標准化。
def data_processing(raw_data,scale=True): if scale == True: return (raw_data-np.mean(raw_data))/np.std(raw_data)#標准化 else: return (raw_data-np.min(raw_data))/(np.max(raw_data)-np.min(raw_data))#極差規格化
3、數據預處理
設置隱層層數,因為數據集較簡單,設置一層即可,神經元個數設為32,時間步設為12,訓練輪數設為2000,訓練批尺寸也就是每一輪抽取的樣本數量為64。
'''設置隱層神經元個數''' HIDDEN_SIZE = 32 '''設置隱層層數''' NUM_LAYERS = 1 '''設置一個時間步中折疊的遞歸步數''' TIMESTEPS = 12 '''設置訓練輪數''' TRAINING_STEPS = 2000 '''設置訓練批尺寸''' BATCH_SIZE = 64
4、樣本生成函數
為了將原始的單變量時序數據處理成lstm可以接受的數據類型(有x輸入和有y標簽),需要將原始數據做進一步處理,將原始數據從第一個開始,依次采樣長度為12的連續序列作為x輸入,第13個數據作為y標簽。
def generate_data(seq): X = []#初始化輸入序列X Y= []#初始化輸出序列Y '''生成連貫的時間序列類型樣本集,每一個X內的一行對應指定步長的輸入序列,Y內的每一行對應比X滯后一期的目標數值''' for i in range(len(seq) - TIMESTEPS - 1): X.append([seq[i:i + TIMESTEPS]])#從輸入序列第一期出發,等步長連續不間斷采樣 Y.append([seq[i + TIMESTEPS]])#對應每個X序列的滯后一期序列值 return np.array(X, dtype=np.float32), np.array(Y, dtype=np.float32)
5、構建lstm模型主體
'''定義LSTM cell組件,該組件將在訓練過程中被不斷更新參數''' def LstmCell(): lstm_cell = rnn.BasicLSTMCell(HIDDEN_SIZE, state_is_tuple=True) # return lstm_cell '''定義LSTM模型''' def lstm_model(X, y): '''以前面定義的LSTM cell為基礎定義多層堆疊的LSTM,這里只有1層''' cell = rnn.MultiRNNCell([LstmCell() for _ in range(NUM_LAYERS)]) '''將已經堆疊起的LSTM單元轉化成動態的可在訓練過程中更新的LSTM單元''' output, _ = tf.nn.dynamic_rnn(cell, X, dtype=tf.float32) '''根據預定義的每層神經元個數來生成隱層每個單元''' output = tf.reshape(output, [-1, HIDDEN_SIZE]) '''通過無激活函數的全連接層計算線性回歸,並將數據壓縮成一維數組結構''' predictions = tf.contrib.layers.fully_connected(output, 1, None) '''統一預測值與真實值的形狀''' labels = tf.reshape(y, [-1]) predictions = tf.reshape(predictions, [-1]) '''定義損失函數,這里為正常的均方誤差''' loss = tf.losses.mean_squared_error(predictions, labels) '''定義優化器各參數''' train_op = tf.contrib.layers.optimize_loss(loss, tf.contrib.framework.get_global_step(), optimizer='Adagrad', learning_rate=0.6) '''返回預測值、損失函數及優化器''' return predictions, loss, train_op '''載入tf中仿sklearn訓練方式的模塊''' learn = tf.contrib.learn
實驗數據記錄和處理
1、模型保存
'''初始化LSTM模型,並保存到工作目錄下以方便進行增量學習''' regressor = SKCompat(learn.Estimator(model_fn=lstm_model, model_dir='Models/model_1'))
2、數據處理
調用前面定義好的縮放函數處理原始數據,這里先用7000個數據作為訓練樣本,這7000個訓練數據做處理將得到6989個數據,因為每12步取一組x,第13步取為y,假設希望剩余的73個數據在測試時都預測出來,則我們需要取第6989個數據到最后一個數據,用來轉換為測試樣本。
'''對原數據進行尺度縮放''' data = data_processing(data) '''將7000個數據來作為訓練樣本''' train_X, train_y = generate_data(data[0:7000]) '''將剩余數據作為測試樣本''' test_X, test_y = generate_data(data[6989:-1])
3、訓練數據
以仿sklearn的形式訓練模型,這里指定了訓練批尺寸和訓練輪數。
regressor.fit(train_X, train_y, batch_size=BATCH_SIZE, steps=TRAINING_STEPS)
實驗結果與分析
1、訓練數據
用訓練好的模型來計算處理過的測試集,可以得到對應預測值,預測出來的數據為標准化之后的,並非原始數據,畫出對比圖如下。
'''利用已訓練好的LSTM模型,來生成對應測試集的所有預測值''' predicted = np.array([pred for pred in regressor.predict(test_X)]) '''繪制反標准化之前的真實值與預測值對比圖''' plt.plot(predicted, label='預測值') plt.plot(test_y, label='真實值') plt.title('反標准化之前') plt.legend() plt.show()
為了能看到真實數值,再定義一個反標准化函數。
'''自定義反標准化函數''' def scale_inv(raw_data,scale=True): '''讀入原始數據並轉為list''' data = pd.read_excel('日元-人民幣.xls',header = 0, sheetname='Sheet1') data = data.iloc[:, 4].tolist() if scale == True: return raw_data*np.std(data)+np.mean(data) else: return raw_data*(np.max(data)-np.min(data))+np.min(data)
調用反標准化函數即可得到原始值,並畫圖觀察。
sp = scale_inv(predicted) sy = scale_inv(test_y) '''繪制反標准化之后的真實值與預測值對比圖''' plt.figure(figsize=(12,8)) plt.plot(sp, label='預測值') plt.plot(sy, label='真實值') plt.title('反標准化之后') plt.legend() plt.show()
將預測值與前面的值連起來畫圖,並與原始圖做對比。
plt.show() p = plt.figure(figsize=(16, 9)) ax = p.add_subplot(1, 2, 1) plt.plot(time[7002:-1], sp) plt.plot(time[0:7000], scale_inv(data[0:7000])) plt.title('預測圖') ax = p.add_subplot(1, 2, 2) plt.plot(time, scale_inv(data)) plt.title('原圖') plt.show()
2、計算准確值
設預測數據與原數據誤差小於0.05,則算准確,由此可以按照下面方式得到准確率。
acc_num = 0 for i in range(len(sy)): if (abs(sp[i]-sy[i])) < 0.05: acc_num += 1 print('准確率為:',acc_num/len(sp))
3、預測未來20天的值
按照前面的思路,可以使用12個數據預測后一天的值,如果需要預測20天的值,可以用前面已知的12天數據預測下一天的值,這個值又放入數據中作為已知值來繼續預測下一天的值,打印出預測結果。
day=20 l=len(data) for i in range(day): P=[] P.append([data[l-TIMESTEPS-1+i:l-1+i]]) P=np.array(P, dtype=np.float32) pre=regressor.predict(P) data=np.append(data,pre) pre=data[len(data)-day:len(data)+1] print(pre)
同樣這個值是標准化的值,可以打印出反標准化的值和畫出預測圖。
#反標准化的值 print(scale_inv(pre)) #預測圖 p = plt.figure() plt.plot(scale_inv(pre)) plt.show()
問題與討論
1、分析結果
用訓練好的模型,應用在測試集時,得到的預測結果還是令人滿意的,預測出的數據誤差都是小於0.1的,在0.05的誤差范圍內,准確率也無限接近達到100%。
對於預測未來20天的值,從預測圖可以看到,數值呈上升的趨勢且上升幅度較快,預測的結果其實是不准確的,原因也比較明顯,在前面的測試集中,雖然是預測73個數據,但是每一次的預測都是用已知的真實值來計算的,也就是說,預測出來的值並不會加入模型中繼續訓練,也不會用預測出來的值作為輸入參數。這預測的73個需要預測的值,本身已經在輸入中了。
預測未來20天值,第一個還算是比較准確的,按照前面的做過的測試,准確率應該是無限接近達到百分百的,后面的數據預測時,輸入是用預測出來的數據補充的,所以可能會不太准確。
2、不足與改進
1、預測未來多天的值不准確
關於這個,可以嘗試測試的時候采用預測的方法來測試,也就是輸入的值用預測的值來補充,並看測試的准確率,顯然這個不是很合理。另一個方法是可以在生成樣本時候,y標簽不要設置為1個數值,可以設置y為滯后5天或10天或其他的數據。這樣預測時,即可以直接預測未來x天的數據。
2、單變量輸入
在本文中,只取收盤價作為輸入,在實際中,也是不合理的,因為影響匯率的因素有很多,可以嘗試加入其他變量,預測結果可能會更好。