使用LSTM预测时间序列数据4 s% v% N& V/ g9 O% c7 w
" g2 g/ Y( [8 L
& u6 d9 J S7 k& x, ^文章目录# J& T3 k4 L# K% Y
背景 % x, U% X) g* h7 r9 q1 b结论 v u* E# J; U. R2 C) J! j
代码4 `0 }! F! p4 I- Y- `
实验结果 9 ]. E5 y; n& V$ XRNN和DNN的区别 1 q% o# A" K' j8 g5 L [) aRNN和LSTM的区别4 Q: O" g& r4 X) x1 f
背景' M# b0 I- E- V. W3 h8 a% W9 K
复现 @“使用Keras进行LSTM实战” https://blog.csdn.net/u012735708/article/details/82769711 中的实验 & p$ |; X8 Y1 h. L0 m熟悉用LSTM模型训练. W) {4 t! ?' z& L, w
验证将时序数据 转化为分类问题后,预测是否有效果! `# s+ V; a" z" Z1 q7 F
对比SimpleRNN与LSTM模型 哪个效果最好?& B. [) e% ?6 J* M
验证LSTM相比于Dense()模型 是否有提升?$ \! c5 [9 O- X% f' F+ ~& Q: l
对比使用前3天的数据 和使用前1天的数据 哪个效果最好? ! ?: S3 ~1 S5 I" v, |1 a; @) h; T# F结论 ! I% A0 e7 \2 D" Y4 D& Q& f使用前3天的数据预测当天的空气质量的效果 没有 比只用前一天的数据 好 6 ^: k2 [7 O0 P+ q A9 Z: q) w1 @- g! C使用LSTM的效果优于SimpleRNN & { l5 u$ m8 _. w代码 ' m: H* v ]9 `* n- Ofrom pandas import read_csv : y: z( W1 Q+ p( N- nfrom datetime import datetime 9 i) L3 _4 N. N. uimport pandas as pd - C1 p, H5 k- R" Zfrom pandas import DataFrame$ C0 e! w7 E' G0 Z
from sklearn.preprocessing import LabelEncoder,MinMaxScaler " Y! @$ Z }6 |! T" o1 E% I9 p( Bfrom sklearn.metrics import mean_squared_error$ W; I* J. p, o
from keras.models import Sequential$ p3 L. s3 o' }" N9 ~9 v4 K* q
from keras.layers import Dense, Dropout / [* h0 Z% ^/ P% |& r* [from keras.layers import LSTM. }6 ?; X* O0 i
from keras.layers.recurrent import SimpleRNN + Z* @3 A: e9 u0 \; ofrom numpy import concatenate; ~! E p4 `& ]" I5 S
from math import sqrt # e% y8 \* H& i0 c3 i+ v) f& R+ z" T( o7 P6 S! {; b
& ?! I- _5 l& o& j% k ( G. { n" l F2 r ; c, Q2 w8 F1 C G6 l8 K# load data 7 Y! b% D. D p; qdef parse(x): 9 o) u. c% @/ @: |: a+ d return datetime.strptime(x, '%Y %m %d %H')) Y- K- H+ o9 T& n, \
9 \" m9 G1 V" {) Fdef read_raw():2 k' j3 Z2 x# }* Y* a" f% |
dataset = pd.read_csv('raw.csv', parse_dates = [['year', 'month', 'day', 'hour']], index_col=0, date_parser=parse)0 L6 U( d+ Z* U2 e
dataset.drop('No', axis=1, inplace=True) # g `1 F: n% f* ?9 r0 { # manually specify column names* U2 u4 M0 {9 ~+ B3 ^
dataset.columns = ['pollution', 'dew', 'temp', 'press', 'wnd_dir', 'wnd_spd', 'snow', 'rain']8 \5 B% r/ a2 {2 i A3 Q) n
dataset.index.name = 'date' : W2 R& ], X3 j # mark all NA values with 08 I) r" O& z5 ~" l; G
dataset['pollution'].fillna(0, inplace=True)2 D4 h; o1 t1 e. Z( W! w
# drop the first 24 hours$ ]8 A r+ V% H. u
dataset = dataset[24:]( Y, V4 ~+ v- S8 j! |7 ^5 f
# summarize first 5 rows - A9 w1 M8 Y5 M print(dataset.head(5))8 S) t2 w* {5 l2 d
# save to file& o* R0 J* B ^! I: g
dataset.to_csv('pollution.csv')$ t j( _: ^9 F3 F$ e5 j0 I" w
1 G. B- O2 u8 f. S
! t% L# M: Y/ g * t+ D4 y0 W/ Y% ]( y& W' f1 z9 [% F5 N& L$ c
# convert series to supervised learning% q3 c% p8 S1 k5 l% v
def series_to_supervised(data, n_in=1, n_out=1, dropnan=True): + t" Y3 V. o) E t1 z5 Y n_vars = 1 if type(data) is list else data.shape[1] ! w2 Z* W' S* v, f& |0 Z- W df = DataFrame(data)- `6 O! _% f1 H7 d: ~- |, L% W
cols, names = list(), list()1 {1 D2 M' X! b! W& k, t) h
# input sequence (t-n, ... t-1)- w, V: C1 G' D* U8 }1 i2 S( e
for i in range(n_in, 0, -1): 7 U+ J* B3 C! k( }& \ cols.append(df.shift(i)) . Q8 ?0 I" n# Q2 ]: C names += [('var%d(t-%d)' % (j+1, i)) for j in range(n_vars)]' ~7 X/ H7 T5 \- B O0 U4 i
# forecast sequence (t, t+1, ... t+n) 2 ~! H! E% P6 f- o4 M for i in range(0, n_out):3 G1 X+ Q+ ~- e9 F4 O, q* x
cols.append(df.shift(-i)); |* w9 m' T# ^. |$ L
if i == 0:/ S2 ?% i8 q; G: W2 P% s
names += [('var%d(t)' % (j+1)) for j in range(n_vars)] 1 c2 D: ~1 n2 e1 ~ else:; Q6 r6 t% J5 M6 v; x
names += [('var%d(t+%d)' % (j+1, i)) for j in range(n_vars)] l( U+ R! E7 E1 f1 w- T
# put it all together) u8 g" k9 v/ J6 P" t4 L: E
agg = pd.concat(cols, axis=1)" z" n: m7 y) f ]- F' \7 C: Z, U U
agg.columns = names , d' L) w4 |& k! o3 J9 Z L8 q. P # drop rows with NaN values) w+ C3 A+ c2 @8 a7 v& F
if dropnan: ; S3 C$ A( `, A- U) C4 e agg.dropna(inplace=True)+ k) M# J4 X2 C4 V, U! i
return agg; j+ E' R% `. A
) q& U2 z0 r& k" ]# load dataset$ W# C- f+ A1 k# J6 n4 h
dataset = read_csv('pollution.csv', header=0, index_col=0)5 J) m6 ]+ |. X8 c5 G- D
values = dataset.values- [, P u1 U w3 d) ~5 i
4 q; y3 p, D: {' c+ C
% a% L( t+ w- L9 g# integer encode direction * p- ], M* i# T/ }3 L6 c4 s( o: Fencoder = LabelEncoder() ' { Y: v: \ E( m8 aprint(values[:,4])+ N7 _7 Z/ d" V ~* T% Z4 f
values[:,4] = encoder.fit_transform(values[:,4]) . o# v. K# Y# `6 ^1 X. S8 e# ensure all data is float & U: G2 |7 k6 |6 I# Rvalues = values.astype('float32') ) b$ E3 l _9 @0 y/ i( N& E8 q1 ]( S: t# normalize features 1 b, h8 b5 y7 ~. o& P0 Rscaler = MinMaxScaler(feature_range=(0, 1)) - U6 U6 J; S" o# M5 B3 _scaled = scaler.fit_transform(values)# c$ i: ]" A0 a% J
# frame as supervised learning 4 [* E: G/ H1 z& C/ @: ^reframed = series_to_supervised(scaled, 1, 1) & b+ X$ I, m4 D* R( Y* s4 W: n
#reframed = series_to_supervised(scaled, 3, 1) #用前3天的数据,预测当天的数据6 q; x+ n" F2 t, L4 R
print("columns:", reframed.columns)+ Y, \2 _! ]! t Z3 Y8 p/ C! H0 i8 ^
# drop columns we don't want to predict * f* }. H2 i ] u' W: Areframed.drop(reframed.columns[[9,10,11,12,13,14,15]], axis=1, inplace=True) #用前1天的数据,预测当天的数据 2 f# m! N# s8 D#reframed.drop(reframed.columns[[25,26,27,28,29,30,31]], axis=1, inplace=True)#用前3天的数据,预测当天的数据 " f( G9 u1 R# z; f, w2 y' E4 l% a8 R. `% Aprint(reframed.head()) 2 {" {: ~8 w1 Sprint("new columns:", reframed.columns)) l) D" ?8 `" r: K* O9 W! Y
# split into train and test sets- o$ J3 b+ o) N) Z
values = reframed.values ) N5 s* J+ G* o( K0 mn_train_hours = 365 * 24 2 ~- j: |, C+ Jtrain = values[:n_train_hours, :]0 x! E5 b0 k- d$ J% i; o
test = values[n_train_hours:, :]$ h, Q; _4 ^; `: e, e8 p, T
# split into input and outputs( q- C4 b1 B7 ^0 U
train_X, train_y = train[:, :-1], train[:, -1] 8 H0 R* f% M" L8 C- n& Ptest_X, test_y = test[:, :-1], test[:, -1] , y" ?" r" m3 M. z# reshape input to be 3D [samples, timesteps, features], } ?8 Q! g7 t6 B3 C2 r L
#使用Dense()模型时不用变换 ) b% ]3 H" k( |# P9 J/ ctrain_X = train_X.reshape((train_X.shape[0], 1, train_X.shape[1]))7 A7 \; C- Q$ Q! ], I' ^
test_X = test_X.reshape((test_X.shape[0], 1, test_X.shape[1])) 6 f$ j8 j G7 Bprint(train_X.shape, train_y.shape, test_X.shape, test_y.shape) % s: b4 T! _* T0 H J7 Q3 Q! W# design network2 @9 Y" [: y* T+ n/ t
model = Sequential()$ R" a/ B9 q# Y
#model.add(LSTM(50, input_shape=(train_X.shape[1], train_X.shape[2])))% ^, Y' s( i; c
#model.add(Dense(50, activation='relu', input_dim = 8))- i, {" I( q" F+ W
model.add(SimpleRNN(50, input_shape=(train_X.shape[1], train_X.shape[2])))$ J2 J% i6 g0 K" _; ]- H2 {
model.add(Dense(1)). n: M( j$ f0 H' g6 ?
model.compile(loss='mae', optimizer='adam') : O3 |, x. j; M0 `! }; G0 c# fit network ) {, ]" F9 U; }' F1 y8 ~5 @history = model.fit(train_X, train_y, epochs=50, batch_size=72, validation_data=(test_X, test_y), verbose=2, shuffle=False)( ]% T/ `7 j0 D u2 H& b
# make a prediction& J9 P( @9 K4 \* _; d/ n
yhat = model.predict(test_X); E' w1 l1 e# M: s: X# Y: Y
print("yhat shape:", yhat.shape)4 p" A- c, v$ c6 ~0 @( W& I
'''9 u# [9 O, U0 s, k' f
计算在测试集上的均方差6 k6 |0 H$ _- v8 X$ N
test_X = test_X.reshape((test_X.shape[0], test_X.shape[2])) ' y) ?, h* A* C" n/ gprint("test_X shape:", test_X.shape) " j7 ]9 \5 p! B8 t' [6 s2 y- o3 j3 M1 N* L3 S6 ?! |/ a
$ v4 `4 ^0 Q: T X/ N
# invert scaling for forecast # b3 A4 z8 S, @# C! finv_yhat = concatenate((yhat, test_X[:, 1:]), axis=1)7 ]6 C* N' J6 E0 W
inv_yhat = scaler.inverse_transform(inv_yhat) . m3 U' @7 V5 v- k# M( N) x; e0 ]inv_yhat = inv_yhat[:,0]8 Y" m9 v- I9 s1 j0 l# G0 P
# invert scaling for actual 2 L. d7 j3 h! j5 P6 C3 ?3 S( F) ctest_y = test_y.reshape((len(test_y), 1)) : G! z i' ~* ` Ginv_y = concatenate((test_y, test_X[:, 1:]), axis=1) & Y& @& E4 [7 I& v: E, P: pprint("inv_y:", inv_y[:10]) 8 M6 A" [6 u! J# yprint("inv_y shape:", inv_y.shape)0 @+ B# F9 S ^4 W
6 }* L+ f' D, B% Q% {2 b8 G ) L3 k9 d0 X2 B( E5 U7 L: D# Y5 iinv_y = scaler.inverse_transform(inv_y) 8 I, N; [4 G! H. @$ v& j9 |$ a1 c$ O5 aprint(inv_y, "*"*30) ' U& `, ?2 L9 k1 U! W 5 b. w. x( ~- w/ u) P0 p1 G5 p v9 `0 ?, K( c* f8 t+ Yinv_y = inv_y[:,0] + `7 S& x$ \' j" P. n& v& `# calculate RMSE7 ^9 |$ ?% u5 n# ] Q9 J9 I8 G
rmse = sqrt(mean_squared_error(inv_y, inv_yhat)) 0 ?& F8 s# t& p$ Z+ {; _print(inv_y[:100], inv_yhat[:100])1 |: {( F0 @0 {- L/ T
print('Test RMSE: %.3f' % rmse)- F. D |% K' W" ~3 \3 g8 L* ^
- u' E) k: H0 T! F" k# |2 s5 C
) a2 ^+ U v. e4 r0 C& t9 [' D
'''6 p$ H! d7 U9 w9 m* G 实验结果 8 a) @- c# T9 v: B6 q3 F4 i4 Z/ L+ n实验1:用前一天的天气数据,预测某一天的空气质量# I; {, e1 f3 H$ J$ v, r; m
使用LSTM模型& j3 B# ^% l; a0 {( j
结果:& q! k2 n6 W3 a2 \6 ?+ @8 J
Epoch 49/50& \. s9 B# @& X3 L8 ^! S
0s - loss: 0.0144 - val_loss: 0.0133 p$ B' Q7 m: N0 m$ T! o' X$ iEpoch 50/50& y. l; p4 f) c% _) F
0s - loss: 0.0144 - val_loss: 0.0133, a9 T) s! u1 W1 ~+ \& B+ E
7 c) W; Q. s2 T3 h7 e9 @! N
$ h6 b/ G0 m. W% J* S6 \/ x# @实验2:用前3天的天气数据,预测某一天的空气质量 5 |0 @' ^) F$ y" L4 p: K6 ~使用LSTM模型$ q) @/ e8 E8 A( q; S2 N, U
* @- u. |* Z/ P4 e4 R
- R( v. M5 \% P9 w }
结果: n6 Y0 f( b& W1 A- {9 dEpoch 49/50 s6 ~) {6 O9 {1 r% J
0s - loss: 0.0147 - val_loss: 0.0149. o, h1 B1 l; Q p, ]6 S& Y' i
Epoch 50/50 3 `; L% Q5 o* K4 l" G$ o* g6 q0s - loss: 0.0147 - val_loss: 0.0150 ( N' S/ Y a& d7 q 2 ^1 M- o3 H( m3 P4 i1 s4 i! d( A: Z, K * F1 K9 {3 ^: w D' Y实验3:用前一天的天气数据,预测某一天的空气质量: e. l- d4 n1 G2 x0 W D8 k. C
使用普通的全连接模型 Dense() : W( ?& n2 r9 k) g/ B结果: 4 V5 r$ ` x6 U9 T2 G7 a0 m. I. p; AEpoch 49/50 % e* s4 q( r5 G1 M0s - loss: 0.0144 - val_loss: 0.0146 + s2 u/ g) z8 O# R( s; f5 {' ZEpoch 50/50 ( R5 G1 a1 w( q1 J0s - loss: 0.0148 - val_loss: 0.0151 - v X& j: a+ n- ^6 i + X& Q" {) e3 e0 R4 p/ t5 y2 H# y- i' w: Z5 d; G; O
实验4:用前三天的天气数据,预测某一天的空气质量2 g$ l: `8 g5 T& J) |7 Z
使用普通的全连接模型 Dense()3 B* i. u, t! d2 }) Q' @; d" K
结果: 9 t: u. h, e/ f0 b3 UEpoch 49/50; _' O `( H+ V6 \( K* g) O
0s - loss: 0.0150 - val_loss: 0.0165 ! O1 W3 n5 F# }" a1 d( P& }Epoch 50/50 * {9 l8 Q2 Y) X0s - loss: 0.0148 - val_loss: 0.0141' @% V9 b, l0 W& {
2 K# f& ~* d; i V) g- ^/ S" p4 \实验5:用前一天的天气数据,预测某一天的空气质量 # z( c) a0 h( o使用SimpleRNN% t& v' T/ I d0 u9 i& N" Y
Epoch 49/50# ^2 _. t. i8 v' C5 d6 \) a
0s - loss: 0.0160 - val_loss: 0.01402 P/ K1 ?6 R- Q) N- u. m: n
Epoch 50/50 ; R2 X; @0 P7 \; B0s - loss: 0.0147 - val_loss: 0.01500 R3 S/ A. R; O8 {4 e( c
: V1 E# M0 q5 W! ?: Y 9 V j' n' g* v* F' n- A, B实验6:用前三天的天气数据,预测某一天的空气质量 - `! J5 R' c" c& z' @ s使用SimpleRNN! ]! n W7 Y0 G; Z
Epoch 49/50 " r' Q( P; K. g( T- c0s - loss: 0.0164 - val_loss: 0.0233 ( s+ [ C8 v( P9 S0 l$ WEpoch 50/50* [) _7 E" d6 E( G
0s - loss: 0.0166 - val_loss: 0.0227 + q% }! \) A' P' Y+ s; \( Q' j' X( LRNN和DNN的区别