美元對人民幣匯率的大數據分析與預測


一、實驗說明

文獻參考:http://www.dataguru.cn/article-11339-1.html(lstm詳細介紹)

https://blog.csdn.net/u011974639/article/details/77856388#?tdsourcetag=s_pcqq_aiomsg(TensorFlow及lstm代碼參考)

附:本文數據不便放出,需要做實驗可以自己在excel中編輯數據,數據在“二、開發准備”中有樣本參考。

1.1實驗內容

通過現有的數據,建立數學模型,預測出未來一個月的匯率變化趨勢。本文采用美元對人民幣的匯率數據,時間是199011日到2018821日。利用Tensorflow搭建模型並完成預測,數學模型用Lstm(長短期記憶)人工神經網絡,LstmRNN(循環神經網絡)的一種變形,是在RNN的基礎上施加了若干個門來控制,使其在長時間步的傳遞過程中減少信息失效的可能。

1.2實驗知識點

1.2.1本次實驗中將學習和實踐以下知識點:

  1. Python基本知識
  2. Python基礎庫如numpypandamatplotlib
  3. TensorFlow模塊的使用
  4. Lstm神經網絡

1.2.2Lstm神經網絡

要理解Lstm,首先需要了解循環神經網絡(RNN),循環神經網絡可以將信息持久化。

 

這個相對於原始的神經網絡,就是加了一個環,也就是X是輸入,h為輸出,A為隱藏層,如果將環展開:

 

循環神經網絡的一個核心思想是將以前的信息連接到當前的任務中來,但是,如果前面的信息與當前信息距離增大,RNN對於連接這些信息顯得無能為力。而Lstm是一種特殊的RNN,能學習長期依賴關系。一般的RNN,其模塊非常簡單,只有一個tanh層。

 

Lstm也是這種結構,但其模塊的結構不同,如下所示。

 

Lstm的核心是元胞狀態,Lstm通過門的結構來控制元胞狀態添加或者刪除信息,門是一種選擇性讓信息通過的方法,也就是Lstm不同於RNN的地方。Lstm也有多種版本,但核心部分都是一樣的,本文中不再詳細展開討論Lstm的每個部分。

1.3實驗環境

  1. 運行環境window7
  2. 開發環境python3.6
  3. 調試環境jupyter notebook

1.4適合人群

  1. 具有python基礎知識、神經網絡基礎知識
  2. TensorFlow學習
  3. Lstm神經網絡學習

二、開發准備

安裝AnacondaAnaconda包含有非常齊全的基礎庫,因此非常便於使用,並且安裝非常簡單,只要下載解壓,按照提示直接安裝完畢即可。安裝完成可以查看python是否可用以及python的版本。命令行輸入python即可。

 

輸入pip list查看庫列表,部分截圖如下

 

通過查看可以發現還需要安裝TensorFlow

 

實驗所需文件部分數據如下所示

 

三、項目文件結構

 

四、實驗內容及步驟

4.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

4.2數據預處理

導入數據並查看前五行數據

data = pd.read_excel('美元-人民幣.xlsx',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()

 

從圖中可以知道原始數據值在49的范圍,連續數據值的預測需要輸出為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))#極差規格化

4.3設置基本參數

設置隱層層數,因為數據集較簡單,設置一層即可,神經元個數設為32,時間步設為12,訓練輪數設為2000,訓練批尺寸也就是每一輪抽取的樣本數量為64

'''設置隱層神經元個數'''

HIDDEN_SIZE = 32

'''設置隱層層數'''

NUM_LAYERS = 1

'''設置一個時間步中折疊的遞歸步數'''

TIMESTEPS = 12

'''設置訓練輪數'''

TRAINING_STEPS = 2000

'''設置訓練批尺寸'''

BATCH_SIZE = 64

4.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)

4.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

 

五、實驗數據記錄和處理

5.1模型保存

'''初始化LSTM模型,並保存到工作目錄下以方便進行增量學習'''

regressor = SKCompat(learn.Estimator(model_fn=lstm_model, model_dir='Models/model_1'))

5.2數據處理

調用前面定義好的縮放函數處理原始數據,這里先用7000個數據作為訓練樣本,這7000個訓練數據做處理將得到6989個數據,因為每12步取一組x,第13步取為y,假設希望剩余的447個數據在測試時都預測出來,則我們需要取第6989個數據到最后一個數據,用來轉換為測試樣本。

'''對原數據進行尺度縮放'''

data = data_processing(data)

'''7000個數據來作為訓練樣本'''

train_X, train_y = generate_data(data[0:7000])

'''將剩余數據作為測試樣本'''

test_X, test_y = generate_data(data[6989:-1])

5.3訓練數據

以仿sklearn的形式訓練模型,這里指定了訓練批尺寸和訓練輪數。

regressor.fit(train_X, train_y, batch_size=BATCH_SIZE, steps=TRAINING_STEPS)

訓練結果如下:

 

六、實驗結果與分析

6.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('美元-人民幣.xlsx',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()

將預測值與前面的值連起來畫圖,並與原始圖做對比。

p = plt.figure(figsize=(16,9))

ax = p.add_subplot(1,2,1)

plt.plot(time[7001:-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()

 

6.3計算准確率

設預測數據與原數據誤差小於0.05,則算准確,由此可以按照下面方式得到准確率。

acc_num = 0

for i in range(len(sy)):

    if (abs(sp[i]-st[i])) < 0.05:

        acc_num += 1

print('准確率為:',acc_num/len(sp))

6.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()

 

七、問題與討論

7.1分析結果

用訓練好的模型,應用在測試集時,得到的預測結果還是令人滿意的,預測出的數據誤差都是小於0.1的,在0.05的誤差范圍內,准確率也達到97%

對於預測未來20天的值,從預測圖可以看到,數值呈下降的趨勢且下降幅度較快,預測的結果其實是不准確的,原因也比較明顯,在前面的測試集中,雖然是預測447個數據,但是每一次的預測都是用已知的真實值來計算的,也就是說,預測出來的值並不會加入模型中繼續訓練,也不會用預測出來的值作為輸入參數。這預測的447個需要預測的值,本身已經在輸入中了。

預測未來20天值,第一個還算是比較准確的,按照前面的做過的測試,准確率應該是達到百分九十七的,后面的數據預測時,輸入是用預測出來的數據補充的,所以可能會不太准確。

7.2不足與改進

1、預測未來多天的值不准確

關於這個,可以嘗試測試的時候采用預測的方法來測試,也就是輸入的值用預測的值來補充,並看測試的准確率,顯然這個不是很合理。另一個方法是可以在生成樣本時候,y標簽不要設置為1個數值,可以設置y為滯后5天或10天或其他的數據。這樣預測時,即可以直接預測未來x天的數據。

2、單變量輸入

在本文中,只取收盤價作為輸入,在實際中,也是不合理的,因為影響匯率的因素有很多,可以嘗試加入其他變量,預測結果可能會更好。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM