在线时间 514 小时 最后登录 2023-12-1 注册时间 2018-7-17 听众数 15 收听数 0 能力 0 分 体力 40331 点 威望 0 点 阅读权限 255 积分 12810 相册 0 日志 0 记录 0 帖子 1419 主题 1178 精华 0 分享 0 好友 15
TA的每日心情 开心 2023-7-31 10:17
签到天数: 198 天
[LV.7]常住居民III
自我介绍 数学中国浅夏
使用LSTM预测时间序列数据
$ m* X) K, ]) W7 s, V% i; ?% Y) u
3 x/ }( I1 N g: `( M 1 D# J! \% w9 T) y, A
文章目录 ! t! l9 x, T9 A1 p1 P, p* J9 G4 \! B
背景
. Q1 x) L8 O: d# \8 l0 X4 _8 ~ 结论
& N) |: p, X w! J7 g8 Q! M+ n! B 代码
8 r/ i3 a3 f5 H9 F* s 实验结果 % u0 W' i) l3 h8 z
RNN和DNN的区别
6 I" i* E* d, [& g7 b RNN和LSTM的区别
( S; b( C7 Y" G# ~& { 背景 ! m! y* [/ {" o$ w8 d0 D: S
复现 @“使用Keras进行LSTM实战” https://blog.csdn.net/u012735708/article/details/82769711 中的实验 , [8 N( |5 z2 w8 p/ Y
熟悉用LSTM模型训练
) _$ M6 b; G7 w( @5 y7 s 验证将时序数据 转化为分类问题后,预测是否有效果 0 x; u+ x8 a0 R3 ^7 G4 M
对比SimpleRNN与LSTM模型 哪个效果最好?
* Y( h( W* t V: ~. Z" f& L 验证LSTM相比于Dense()模型 是否有提升? 2 c4 f: }5 e$ o0 l7 a2 k
对比使用前3天的数据 和使用前1天的数据 哪个效果最好? - X& o7 h- {1 o3 x/ ?" P5 ~
结论
3 T, e- A4 l0 y6 G8 P- X1 E1 w 使用前3天的数据预测当天的空气质量的效果 没有 比只用前一天的数据 好 * y0 v6 y8 a+ m
使用LSTM的效果优于SimpleRNN
% m; f1 y: r( D& ? 代码
8 C1 C/ G1 g& o( S0 @ from pandas import read_csv 8 |& @- G4 j* V: J6 U2 h% L
from datetime import datetime
4 E7 S$ r; s4 E! \( ]9 j/ U import pandas as pd
2 d( F- X. G8 ~ from pandas import DataFrame - }2 q0 `/ a( H! D% T) r. N
from sklearn.preprocessing import LabelEncoder,MinMaxScaler " ~3 Q7 Q& g0 d1 f! [
from sklearn.metrics import mean_squared_error % e* L& L( g& h
from keras.models import Sequential ) O! T, Y- c& e$ |* R: u3 _- \! w: ~
from keras.layers import Dense, Dropout
. j; N \6 y8 _6 \5 n; }9 [9 Z1 g from keras.layers import LSTM
$ |. {$ J% w; ~/ \ from keras.layers.recurrent import SimpleRNN ' ~$ r' _* _! J& v' F, j* A
from numpy import concatenate
6 u0 t! d) h0 _6 K) [' B- a$ [3 H7 C" | from math import sqrt
$ N2 J6 e" K q3 v) U- s
/ x2 ]# D4 ]- T6 }" B% S0 e
4 c. D" Y4 i7 a$ Y, C9 ?- ]# ` - }8 M1 W# S9 h" s1 c4 j( |1 w1 @
x: T8 K/ K5 Y; V # load data
" H( q$ r- @' W6 b def parse(x):
$ r) a `6 l& X0 {. l return datetime.strptime(x, '%Y %m %d %H') + l( a3 S& E2 Y! f
. d& x V' a4 G$ y" ? def read_raw(): . q' B% y4 b7 @( ^; i, M, \9 L
dataset = pd.read_csv('raw.csv', parse_dates = [['year', 'month', 'day', 'hour']], index_col=0, date_parser=parse) + I/ D& i7 }1 a: m3 o! J2 I
dataset.drop('No', axis=1, inplace=True) 3 B" q% j" N& [+ U; |4 t$ X' Q
# manually specify column names
. v4 j- n% I* @. K5 H dataset.columns = ['pollution', 'dew', 'temp', 'press', 'wnd_dir', 'wnd_spd', 'snow', 'rain'] 2 p) p! b6 m! l# d; k
dataset.index.name = 'date'
+ b$ r; d3 {; D. X+ r |3 N # mark all NA values with 0
6 N! i6 K! \; h- V6 K dataset['pollution'].fillna(0, inplace=True) 4 r" A- U( T+ `% Q1 l
# drop the first 24 hours
0 T, G1 M8 ?) P) ` dataset = dataset[24:] * g/ ~* c" O0 ~3 N1 b
# summarize first 5 rows
5 q* g. n9 s6 }+ z print(dataset.head(5))
4 a( o$ Y" J; e9 @. ] # save to file
& S9 i8 k" O5 w+ J dataset.to_csv('pollution.csv') 8 Z4 P5 [7 i1 s! ?4 U5 q9 R+ O8 J
* z9 L8 {9 e- y: K/ T; e6 [- F
% T: c/ b- }6 c' @1 Z% O
1 x% c6 W/ W: m8 K2 `- s# u
5 a/ M" ^# ~9 z' l- ^ # convert series to supervised learning # S# |: o8 b$ x- m: i0 r
def series_to_supervised(data, n_in=1, n_out=1, dropnan=True):
# C$ |5 F- t9 ^2 z n_vars = 1 if type(data) is list else data.shape[1]
, Q: _; | }4 K$ F- \ df = DataFrame(data)
! Z) ^* C. ?$ E cols, names = list(), list()
0 Z/ C: E- s ~# u" T% i& p) p4 w4 C # input sequence (t-n, ... t-1) ; V7 S6 j3 S; k
for i in range(n_in, 0, -1):
: J- L; Q; w" e% ]6 O9 q" g cols.append(df.shift(i))
0 v: w& @+ G9 w2 x1 v4 E- h' e names += [('var%d(t-%d)' % (j+1, i)) for j in range(n_vars)]
6 @1 O; c/ B1 @% C* ^' ` # forecast sequence (t, t+1, ... t+n) ( L2 a* g2 y& [9 t) p- o+ m& |
for i in range(0, n_out):
4 @$ B% f$ V% K8 @ cols.append(df.shift(-i)) # Y/ |3 F) A2 ~* y P- d
if i == 0: 6 M+ h g# G0 P* `+ \2 b( b
names += [('var%d(t)' % (j+1)) for j in range(n_vars)] ) a! [* E' `$ }" g$ E( ?
else:
3 K Z" Z$ `0 ?( H" u5 l names += [('var%d(t+%d)' % (j+1, i)) for j in range(n_vars)] , M2 |/ [) V1 T1 n8 e, f
# put it all together ' w1 o+ b+ Y) Y( [, m' A `; `
agg = pd.concat(cols, axis=1) 3 Q3 o6 `+ R# V4 @
agg.columns = names
9 k) o: Q, f5 I+ a+ b6 h' z # drop rows with NaN values # q/ [5 w& Q, K2 q! s' H
if dropnan: 3 l% z) C' L+ f
agg.dropna(inplace=True)
( s; Z4 ^7 s+ H2 R7 S" A return agg ( d6 w- m" ^- q7 E1 Y
" \1 {/ f5 i! A, q" ]
# load dataset
- O* M& X8 J1 ]$ U dataset = read_csv('pollution.csv', header=0, index_col=0)
7 c' V5 c! m" j8 z; J values = dataset.values ; Y' A: i u: X, n' |7 G
" @* r, ~& e) W( V
1 J- ]& N# C4 y+ ` # integer encode direction
! m' i8 M- `/ v- Y0 @ encoder = LabelEncoder() + @8 W' J4 a" P5 d$ t6 ~( E) d% L
print(values[:,4]) - m! C# d7 S! b$ Z+ K* U9 ?
values[:,4] = encoder.fit_transform(values[:,4])
( n x3 N8 l8 ?* E # ensure all data is float
# }. B6 b* M: h7 Z7 e: b values = values.astype('float32') 0 j2 W6 ? @* [; X$ y
# normalize features $ j/ z# @# r! T" D
scaler = MinMaxScaler(feature_range=(0, 1))
- U, S! r1 ]- O) B scaled = scaler.fit_transform(values) & C+ ^. K; [/ I# `1 x$ k
# frame as supervised learning
" Z) p% h* |* j2 o( y( o5 C reframed = series_to_supervised(scaled, 1, 1)
( j2 ~. a/ S6 y" ^9 t #reframed = series_to_supervised(scaled, 3, 1) #用前3天的数据,预测当天的数据 c8 F( ^' ~/ L
print("columns:", reframed.columns)
2 E% Z- B+ A4 o$ k; R# u3 m # drop columns we don't want to predict / j/ F+ V h" y- z) R
reframed.drop(reframed.columns[[9,10,11,12,13,14,15]], axis=1, inplace=True) #用前1天的数据,预测当天的数据 ; O" M. w; t* V$ Z+ U- }
#reframed.drop(reframed.columns[[25,26,27,28,29,30,31]], axis=1, inplace=True)#用前3天的数据,预测当天的数据 - m X$ x3 x$ e8 y/ b+ {) D
print(reframed.head())
- ]- r3 |0 {2 g! ^8 R print("new columns:", reframed.columns) $ q0 W9 t- u& g2 i9 J# p
# split into train and test sets
* f6 |& ]5 J* n# n' N values = reframed.values ; f7 l8 I2 X) e h, G. A
n_train_hours = 365 * 24 2 u! ?9 z7 m H" E2 y
train = values[:n_train_hours, :]
0 g. G- C/ z4 K8 F5 ~% Q5 }2 V test = values[n_train_hours:, :] . [# j8 o/ o4 L: u1 c
# split into input and outputs ' A1 \- v: x; N) e! r: a
train_X, train_y = train[:, :-1], train[:, -1] 7 v! S. C7 F8 V: s# Z6 ?
test_X, test_y = test[:, :-1], test[:, -1]
4 k9 A# K% r. H: R # reshape input to be 3D [samples, timesteps, features]
9 T9 w3 F( t2 ?5 o* K+ @# ] #使用Dense()模型时不用变换
; D6 i2 i1 K% A7 @ train_X = train_X.reshape((train_X.shape[0], 1, train_X.shape[1])) & O' F: L* y6 c# A1 _
test_X = test_X.reshape((test_X.shape[0], 1, test_X.shape[1])) U3 ~, x4 g; T2 j+ e% W8 ^% e: `
print(train_X.shape, train_y.shape, test_X.shape, test_y.shape) 6 k/ Q2 n: Y w( Q, @- E) n5 X/ w
# design network ; D. d7 b$ I& b
model = Sequential() 3 X' y7 {6 w5 N- u8 Q9 ^4 l
#model.add(LSTM(50, input_shape=(train_X.shape[1], train_X.shape[2]))) : _" }& B; O: n0 {- v. r/ o
#model.add(Dense(50, activation='relu', input_dim = 8))
; z" q1 m# c( q! g @. k model.add(SimpleRNN(50, input_shape=(train_X.shape[1], train_X.shape[2]))) 7 R3 G( }3 o3 [! O/ R
model.add(Dense(1)) 8 B$ n/ y/ L8 ]; M* N/ ]
model.compile(loss='mae', optimizer='adam')
- I' Q G9 n; E' k # fit network 1 y2 n7 H% f( G- Z
history = model.fit(train_X, train_y, epochs=50, batch_size=72, validation_data=(test_X, test_y), verbose=2, shuffle=False)
6 d. h6 l% g* `0 A d- |! @ # make a prediction
( U; ?) ~- z/ U# p+ \: c yhat = model.predict(test_X)
% L: ]0 m$ H F; \9 o+ j0 p# w* q print("yhat shape:", yhat.shape) 1 Z7 y3 `, c8 o+ r) f* Q
'''
) H0 I7 ^9 ~1 C1 G 计算在测试集上的均方差
6 h! Z4 c% m3 \' {' M/ {* { test_X = test_X.reshape((test_X.shape[0], test_X.shape[2])) ( W0 B; b' N. ~: A- y' k
print("test_X shape:", test_X.shape) - a! P: J8 L8 p! P
9 ^8 F- u8 t. a' Y+ P $ V+ N/ k, u6 Y! l' n+ j
# invert scaling for forecast
( @- O/ R) D" T( G3 Z8 s! } inv_yhat = concatenate((yhat, test_X[:, 1:]), axis=1) X0 [. i5 @% ~3 S+ t3 ~
inv_yhat = scaler.inverse_transform(inv_yhat)
' ]# j- Y/ d+ n) p inv_yhat = inv_yhat[:,0]
" ?# C/ p9 N: r5 x g # invert scaling for actual
0 U! m& X$ `, D* W5 s0 m6 S test_y = test_y.reshape((len(test_y), 1)) 3 T3 M. q, P0 _$ i
inv_y = concatenate((test_y, test_X[:, 1:]), axis=1)
! A$ Q! h1 p1 t) o print("inv_y:", inv_y[:10])
: C5 [1 M* F, `) E print("inv_y shape:", inv_y.shape)
% C4 a7 U3 c I2 m# c, F# ~5 i# g 4 a/ `( y6 D2 X& T
% S3 Y+ f8 O* R+ K
inv_y = scaler.inverse_transform(inv_y) - H! E' F; }( s; x( U4 M
print(inv_y, "*"*30) a; U m: D: j4 l7 a: T5 c! K
8 P- D& M& r. @4 {0 ~9 Z& T
& C2 S K% P4 w9 ^4 N& H( P inv_y = inv_y[:,0]
+ z6 D6 h# B- `/ S # calculate RMSE / r: v, k0 G Q' f% W
rmse = sqrt(mean_squared_error(inv_y, inv_yhat)) % Z/ a8 m) P4 O. E4 q2 }# O, R
print(inv_y[:100], inv_yhat[:100]) 8 X `3 o- g- `/ |' b4 N! {$ [
print('Test RMSE: %.3f' % rmse)
" _# c/ t& A9 X% S x3 t $ R& o" U. I! E" }6 h2 G% H2 Q5 P
* S( o% h' ^# G |8 Q' z9 u
''' + `2 S0 O7 J) I: U) L9 C8 b* l/ E
实验结果 ]1 |2 v7 O1 f- r5 }
实验1:用前一天的天气数据,预测某一天的空气质量
7 N$ V% Q" e" _& C; p 使用LSTM模型
) r, E& Z! E; C( z2 }" y 结果: ( y1 t# ] c& B2 k" D2 D+ C+ d
Epoch 49/50
0 U$ ~; Y- z5 i: [; T, ]3 q 0s - loss: 0.0144 - val_loss: 0.0133 $ g. Z" k) z B
Epoch 50/50 $ ~3 f3 U: m e+ X1 G+ [9 W M1 c9 b. @
0s - loss: 0.0144 - val_loss: 0.0133 " Q6 B( }/ O3 \; Y0 K' c. r
% X7 c3 Y, Z: g% T0 K5 O8 k9 |
5 u! v4 g. \: i* W; }8 D 实验2:用前3天的天气数据,预测某一天的空气质量
" E, e0 y3 c% O5 e1 {0 T- \; c 使用LSTM模型 ! R3 C% r; T) C+ V7 n3 m6 r
; |6 ]2 y, B! ^; v9 ^! Z; S' d9 e. V
% {* G! V: O, N' s
结果:
% ~! M5 b3 z# R! `& H& S Epoch 49/50 ) ~7 e* @5 t f+ i
0s - loss: 0.0147 - val_loss: 0.0149
! R7 @9 T( \$ x6 ?: y; P Epoch 50/50
~4 X2 o: J8 O& O5 T8 J9 P 0s - loss: 0.0147 - val_loss: 0.0150
. Q: B. x7 S6 V, w) O; o
4 O. G" N V M
# X! E% e) E$ o2 Q3 ` 实验3:用前一天的天气数据,预测某一天的空气质量
1 R8 ?% C x3 I5 V5 r/ | 使用普通的全连接模型 Dense() # }2 h; N0 }, s$ F* d/ [ e
结果: 4 N5 I8 K$ |) h0 j
Epoch 49/50 $ V9 R. W# K- j$ O9 ]
0s - loss: 0.0144 - val_loss: 0.0146 8 Z7 [+ G3 g; l8 J1 k. c' F
Epoch 50/50
: T6 l: r4 o5 h6 H5 [+ r7 r 0s - loss: 0.0148 - val_loss: 0.0151 : r" }$ M$ f4 ~ T' ?
0 T# [! A, ?8 r* L
; \ D! R2 {2 Q. j3 S( A" u 实验4:用前三天的天气数据,预测某一天的空气质量
$ U+ _2 \, |/ V 使用普通的全连接模型 Dense() * w% Y+ O" `" s0 G. y" G9 }4 c
结果:
4 \7 z2 q6 }; s: B) O/ ] Epoch 49/50 6 V# Y4 }# C9 q# a- p( n0 J
0s - loss: 0.0150 - val_loss: 0.0165
0 m1 C! g7 U) Y0 i3 W; D Epoch 50/50 ) C* V6 }2 ~, m" \: n/ \& ^
0s - loss: 0.0148 - val_loss: 0.0141 ! L a; G9 n" Y9 W4 |# ~
3 j; w& [, ]2 |
. c; t" t% Z& v) s F5 d% c 实验5:用前一天的天气数据,预测某一天的空气质量
& o7 C6 u$ R1 T* I 使用SimpleRNN 9 _" I @4 n# q, Q- D4 l
Epoch 49/50 8 F4 |8 \+ \( s" I9 `) ]4 v
0s - loss: 0.0160 - val_loss: 0.0140
+ A; _9 n9 m! r' x. |+ J- f2 ~ Epoch 50/50
0 y( H; ^4 q3 h: A. a6 l# d 0s - loss: 0.0147 - val_loss: 0.0150 ' j# p) U$ S! Y" W' I5 e% B/ G3 N' ~/ p
2 c! @' H, ?( g
- h* R7 ]0 u/ I' C* H: X
实验6:用前三天的天气数据,预测某一天的空气质量 ; S9 X2 J8 ]1 T1 ?( n3 V! i {
使用SimpleRNN $ a, p! Z! `" e8 L
Epoch 49/50
" T- m# v& x3 }9 H, W 0s - loss: 0.0164 - val_loss: 0.0233 6 E2 j1 H2 U. d+ W
Epoch 50/50
) B+ o/ O) [9 ?. ~! D9 ~3 R6 y 0s - loss: 0.0166 - val_loss: 0.0227 " O9 E' i4 x. M7 b' V8 b5 b
RNN和DNN的区别 RNN中的循环是指一个序列当前的输出与前面的输出也有关系。也就是说,网络会对前面的信息进行记忆并应用于当前输出的计算中,即隐层之间的节点不再是无连接的而是有连接的,并且隐层的输入不仅包括输入层的输出还包括上一时刻隐层的输出。
+ z9 b1 u/ \) i5 x* Y
# ]& O, T0 [4 r$ Y7 P; U
1 Z/ N1 [) [: N& G2 K7 B RNN和LSTM的区别
9 X8 g! u6 j/ D6 A) s N. L' F LSTM的内部结构通过门控状态来控制传输状态,记住需要长时间记忆的,忘记不重要的信息;而不像普通的RNN那样只能够“呆萌”地仅有一种记忆叠加方式。对很多需要“长期记忆”的任务来说,尤其好用。 " s' z: K/ Y) V. z
3 [ g8 H$ [/ N K5 o( g( r8 g" S% x9 b 1 Q1 r# t9 F8 ~' g/ B9 g8 p
但也因为引入了很多内容,导致参数变多,也使得训练难度加大了很多。因此很多时候我们往往会使用效果和LSTM相当但参数更少的GRU来构建大训练量的模型。 : u' E; y! _0 W/ g7 z- W
4 J: G* i: }5 I
, r5 [# O2 g, `4 ?" U: }6 \& w9 H: t6 @ 请关注数学中国微博和数学中国公众号,如有疑问联系数学中国工作人员* v' |! i/ i, y, _
! p+ _& R4 ~; M$ K
: ~/ F/ C! Y9 q" }. h# a; v
zan