Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

利用LSTM框架实时预测比特币价格

Cherry95
1133 0 0

) }( D9 _4 @' o: n比特币的价格数据是基于时间序列的,因此比特币的价格预测大多采用LSTM模型来实现。
, T/ B8 s4 b1 L长期短期记忆(LSTM)是一种特别适用于时间序列数据(或具有时间 / 空间 / 结构顺序的数据,例如电影、句子等)的深度学习模型,是预测加密货币的价格走向的理想模型。5 u; D' K, d+ F. n7 r, g
本文主要写了通过LSTM进行数据拟合,从而预测比特币的未来价格。# v9 T  b& ?$ k: t" J. d) b: Y
import需要使用的库7 a& A5 N* z+ N; n( C6 X" q
import pandas as pd2 x9 w: i0 G+ f; s
import numpy as np
0 |: `6 B) E5 O; L7 p  M% efrom sklearn.preprocessing import MinMaxScaler, LabelEncoder
# e  {/ {4 w1 q9 T9 R. Tfrom keras.models import Sequential
9 p" A2 d* ]5 v9 g0 V+ Afrom keras.layers import LSTM, Dense, Dropout; C- Q0 D# [: h, N1 ~
from matplotlib import pyplot as plt
! s. L7 h1 }# [3 C  [& S, N8 X%matplotlib inline! L1 A0 A5 @! T) s) \6 Q
数据分析
8 ?* x+ S4 i: B0 s2 c! Y. c数据加载
4 h# W8 l& F6 }; Q" C& U读取BTC的日交易数据
8 ]8 p: W, A9 C7 Y+ e! kdata = pd.read_csv(filepath_or_buffer="btc_data_day")
; t& C4 u$ E8 s. W3 \7 k查看数据可得,现在的数据一共有1380条,数据由Date、Open、High、Low、Close、Volume(BTC)、Volume(Currency)、Weighted Price这几列组成。其中除去Date列以外,其余的数据列都是float64数据类型。
, R) E# w2 D3 x* G4 R+ m1 ~data.info()3 d. ^( `4 c; @5 l0 R- [) g
查看下前10行的数据
* \7 U* x! v( D' s* C8 Bdata.head(10)
! U  ]( g+ z# S) b$ F& ~' l5 ^; @; Y4 y! R
数据可视化$ ^* N2 i* a& v# _. h! @# K
使用matplotlib将Weighted Price绘制出来,看下数据的分布跟走势。在图中我们发现了有一段数据0的部分,我们需要确认下数据是否有异常。5 R+ w' [  S- k2 G
plt.plot(data['Weighted Price'], label='Price')
! [3 g. J6 h" Y' o9 j4 E5 K" g3 T1 qplt.ylabel('Price')- b' Y1 H2 Q  D" J+ q& `
plt.legend()& N$ d: ~" B: Y" i
plt.show()
, O' k% w) i* C# `; u; a% H
' K6 n* k1 v* W异常数据处理5 n' o( P6 `% q& ~
先查看下数据是否含有nan的数据,可以看到我们的数据中没有nan的数据0 d" A" [" Z) V3 l
data.isnull().sum()0 _3 ~( w) i# f/ |& U+ X% g0 q
Date                 0
  B) q( N' D5 U1 F3 B, K! {. N- rOpen                 0
; G9 i) t- U% l( ZHigh                 0
- j, l2 Y; r, t5 w" }% I  M% |Low                  0# t! U& p/ r8 S# e! R
Close                0
5 l: E2 s' [" J# q, @; ^Volume (BTC)         0
4 U7 C9 _' F. u3 R; `1 P0 \Volume (Currency)    0
9 ~3 Z  d8 Z, l6 L$ h) JWeighted Price       0: p2 {% P5 A+ ?: `4 k& {
dtype: int64- S4 Z, B! g6 k: Q/ f
再查看下0数据,可以看到我们的数据中含有0值,我们需要对0值做下处理+ x5 w# u& p4 k* r3 r% w
(data == 0).astype(int).any()6 ^9 s: {9 X, ]( \3 {% {
Date                 False
' f) e# y4 Y5 T. Q  hOpen                  True
: i! b7 q2 S* O* {0 zHigh                  True# @; c. `$ d$ B
Low                   True
+ G1 K* P$ A- y" H% @! A5 \Close                 True' Z9 W3 x0 U3 E' h9 z
Volume (BTC)          True2 `# G% {  H- m4 [% q
Volume (Currency)     True' r5 c* s% E( o) W
Weighted Price        True
1 r) f, r6 W6 ^0 |0 b+ Zdtype: bool+ \  L& a2 o5 s7 T- [6 }8 u
data['Weighted Price'].replace(0, np.nan, inplace=True)5 O2 i8 _4 w* q: t
data['Weighted Price'].fillna(method='ffill', inplace=True)
+ x8 q: V! ^+ m" k, T. zdata['Open'].replace(0, np.nan, inplace=True)
) Z2 Q7 [) J3 Q$ @# m2 @- qdata['Open'].fillna(method='ffill', inplace=True), e2 ^5 ^$ t& a8 r) q4 h4 S
data['High'].replace(0, np.nan, inplace=True)" z2 v4 z( _7 Q& W$ K5 o
data['High'].fillna(method='ffill', inplace=True)
( D) k6 C4 W6 ^# B! cdata['Low'].replace(0, np.nan, inplace=True)
! {# m: z, [; i6 K9 q! [- ndata['Low'].fillna(method='ffill', inplace=True)
! y2 @) q, J# [( s9 \* U1 jdata['Close'].replace(0, np.nan, inplace=True)! h4 G2 Z1 s! Z$ ^2 ~2 h5 {
data['Close'].fillna(method='ffill', inplace=True)5 U& _9 F+ h, P8 J
data['Volume (BTC)'].replace(0, np.nan, inplace=True)
6 `" E0 {( I" S, S% Odata['Volume (BTC)'].fillna(method='ffill', inplace=True)/ r+ v; n) a% |2 r$ Y
data['Volume (Currency)'].replace(0, np.nan, inplace=True)  l6 v& D" {1 M
data['Volume (Currency)'].fillna(method='ffill', inplace=True)
& J* R- I. Q. {! u0 }& R(data == 0).astype(int).any()6 w" g  M, j* L( s3 p
Date                 False
8 r, J4 A2 w+ dOpen                 False: \) N+ w" r0 M* B
High                 False7 B7 C$ l* t/ `9 a9 l+ d. w
Low                  False
+ V8 G9 m, G  H* v1 H, C0 WClose                False
) P$ g1 t- n$ u! \2 L+ |Volume (BTC)         False. B: s; X+ K: Q2 A
Volume (Currency)    False
0 o1 w) X5 t0 y7 d& G1 WWeighted Price       False$ j- \- s5 c# E- E! O
dtype: bool
) L7 g, K0 I: `2 Z3 I8 |, ~8 |再看下数据的分布跟走势,这个时候曲线已经非常的连续( |; }4 @+ _  W" c6 M- E- T
plt.plot(data['Weighted Price'], label='Price')5 {4 L0 q2 g, J2 j5 c, p. ~4 a2 k
plt.ylabel('Price')7 M; ^" C5 ?; M; M* Q# v, O
plt.legend()
& Z1 ]( t" `, T$ hplt.show()
* n( _2 Z# k- g1 p! F1 k, b. t* z, s) k; A4 g
训练数据集和测试数据集划分; c- N7 M/ ~9 @, _; k- m
将数据归一化到0-1
3 O4 q/ |' Y" f: j  ldata_set = data.drop('Date', axis=1).values
4 y5 z7 e& u0 }: ]6 t. \+ X* Ldata_set = data_set.astype('float32')
. [  |8 ~5 [& X5 z% X4 l7 t) Fmms = MinMaxScaler(feature_range=(0, 1))
8 z/ j; F" Z+ L) odata_set = mms.fit_transform(data_set)
" ?: C4 h( S5 Y% W/ v以2:8划分测试数据集跟训练数据集- h2 d7 {* L. G
ratio = 0.8
' A' W( ^/ }/ ]9 f" a: U' Otrain_size = int(len(data_set) * ratio)( N/ J* {2 m/ l- C4 k
test_size = len(data_set) - train_size
! g- \1 C( ~- \5 R7 }7 vtrain, test = data_set[0:train_size,:], data_set[train_size:len(data_set),:]6 J  a2 G7 X8 u0 h2 A, L
创建训练数据集跟测试数据集,以1天作为窗口期来创建我们的训练数据集跟测试数据集。
; |$ a, \- w& X$ |+ N" J6 [" y& Qdef create_dataset(data):
, }& N5 f' H# f    window = 1
: ?2 C. T( o0 O" @% V7 @! c    label_index = 6
( U/ K$ y7 M+ W7 l  S; ~* b* R' O  X    x, y = [], []
" U' N% a, V! ^* S8 t: s9 Y5 W    for i in range(len(data) - window):
$ E1 D( V8 g) a" c. T* w        x.append(data[i:(i + window), :])
& w. p, m) N2 B. Q        y.append(data[i + window, label_index])3 p$ v' l* Q+ a9 [" F& j
    return np.array(x), np.array(y)6 m1 s  N. Q5 p! P7 T
train_x, train_y = create_dataset(train)
, v; N3 o& D7 N# w  d+ Htest_x, test_y = create_dataset(test)
& E7 p/ s) |  J  _定义模型并训练
) Y) g: w* j5 D这次我们使用一个简单的模型,这个模型结构如下1. LSTM2. Dense。
4 B$ [0 M; x/ N0 _- E, K这里需要对LSTM的inputh shape做下说明, Input Shape的输入维度为(batch_size, time steps, features)。其中,time steps值的是数据输入的时候的时间窗口间隔,这里我们使用1天作为时间窗口,并且我们的数据都是日数据,因此这里我们的time steps为1。
8 T' Z+ U4 I3 P+ q长短期记忆(Long short-term memory, LSTM)是一种特殊的RNN,主要是为了解决长序列训练过程中的梯度消失和梯度爆炸问题,这里先简单介绍下LSTM。
9 c  T$ ?& {3 b3 U/ ^$ _/ L
; ?, v, [5 v# Y! x1 V从LSTM的网络结构示意图中,可以看到LSTM其实是一个小型的模型,他包含了3个sigmoid激活函数,2个tanh激活函数,3个乘法,1个加法。
( n% R4 s# x' L* ]* ]细胞状态0 r! R6 m7 p# K% F, O; m% N) y
细胞状态是LSTM的核心,他是上图中最上面的那根黑线, 在这根黑线下面是一些门,我们在后面介绍。细胞状态会根据每个门的结果,来得到更新。下面我们介绍下这些门,你就会理解细胞状态的流程。
6 O) n9 C+ a: W& q! QLSTM网络能通过一种被称为门的结构对细胞状态进行删除或者添加信息。门能够有选择性的决定让哪些信息通过。门的结构是一个sigmoid层和一个点乘操作的组合。因为sigmoid层的输出是0-1的值,0表示都不能通过,1表示都能通过。一个LSTM里面包含三个门来控制细胞状态。下面我们来一一介绍下这些门。' j! b- b$ b: N  I$ r
遗忘门8 D5 t0 I% M( Z! K* j
LSTM的第一步就是决定细胞状态需要丢弃哪些信息。这部分操作是通过一个称为忘记门的sigmoid单元来处理的。我们来看下动画示意图,  t8 v3 a4 ]7 x

( J  }" G4 B' `- w我们可以看到,遗忘门通过查看$h_{l-1}$和$x_{t}$信息来输出一个0-1之间的向量,该向量里面的0-1值表示细胞状态$C_{t-1}$中的哪些信息保留或丢弃多少。0表示不保留,1表示都保留。
2 ^; K7 B& W6 j! X9 \( c2 @2 E数学表达式: $f_{t}=\sigma\left(W_{f} \cdot\left[h_{t-1}, x_{t}\right]+b_{f}\right)$
( ~6 K6 a/ {3 Z" g3 U/ m输入门, A- f$ `  w, g8 }+ G
下一步是决定给细胞状态添加哪些新的信息,这个步骤是通过输入门开完成的。我们先来看下动画示意图,3 u0 r  Y9 v6 y' I
5 f3 ~) I/ x" `8 p
我们看到了$h_{l-1}$和$x_{t}$的信息又被放入了一个遗忘门(sigmoid)跟输入门(tanh)中。因为遗忘门的输出结果是0-1的值,因此,如果遗忘门输出的是0的话,输入门后的结果$C_{i}$将不会被添加到当前的细胞状态中,如果是1,会全部的被添加到细胞状态中,因此这里的遗忘门的作用是将输入门的结果选择性的添加到细胞状态中。
2 |0 r) \- ?6 a+ H; W! H数学公式为: $C_{t}=f_{t} * C_{t-1}+i_{t} * \tilde{C}_{t}$1 K" Q( I$ @( A6 b/ {, R
输出门
6 Y# X6 {: z" Z) ^更新完细胞状态后需要根据$h_{l-1}$和$x_{t}$输入的和来判断输出细胞的哪些状态特征,这里需要将输入经过一个称为输出门的sigmoid层得到判断条件,然后将细胞状态经过tanh层得到一个-1~1之间值的向量,该向量与输出门得到的判断条件相乘就得到了最终该RNN单元的输出, 动画示意图如下& S% ?% Q) v8 p& O7 T3 l6 v

2 y* c9 f. ~2 C) t( a. s6 T1 _def create_model():
: Z4 j! ?2 P3 D! L  J, \+ [    model = Sequential()  d8 B  O* o* `- w
    model.add(LSTM(50, input_shape=(train_x.shape[1], train_x.shape[2])))
" ^) j9 e% C7 _8 _( ?& l    model.add(Dense(1))1 p0 o; D, A0 l- F1 t
    model.compile(loss='mae', optimizer='adam')3 M- ]% E% q( h& t
    model.summary()! Q: q# L0 ]+ a' _5 m! Z
    return model" i) C+ [3 \) c+ X& U" ^
model = create_model()# M9 t3 w& \3 Y$ O( P* B& d' X
) S& ~+ ]/ f7 l1 ~
history = model.fit(train_x, train_y, epochs=80, batch_size=64, validation_data=(test_x, test_y), verbose=1, shuffle=False)! G$ m% @& K& p
plt.plot(history.history['loss'], label='train')9 e$ l4 K: y' W8 S" c- l
plt.plot(history.history['val_loss'], label='test'). Y) q3 o; _8 S* @& N
plt.legend()
# {! p  I9 f2 K+ B: S3 fplt.show()0 @. c/ n+ u5 O' m; S

4 h: n# x; \9 f8 jtrain_x, train_y = create_dataset(train)
$ [' \+ V+ R$ Z8 `1 m3 x3 {test_x, test_y = create_dataset(test)( D. S/ g1 y; n5 q5 i
预测
7 v! b  o! N2 T3 C, \( I( }2 K1 Ipredict = model.predict(test_x)" P$ q; p1 L& m
plt.plot(predict, label='predict')
' Q2 m0 d7 o( r% y6 w0 M0 ~$ Dplt.plot(test_y, label='ground true')9 b+ x1 y8 f; W6 y# C! k0 I* |" p
plt.legend()1 B1 b  Z5 N% c  M7 D' n3 b! C) Q) w
plt.show()
% d; P$ t- ~% h* j9 @3 w) \0 X0 @7 e. t: R
当前利用机器学习预测比特币长期价格走势还是非常困难的,本文只能作为学习案例使用。该案例之后会上线与矩池云的Demo镜像之中,感兴趣的用户可以直接体验。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

Cherry95 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    2