数学建模社区-数学中国

标题: 使用LSTM预测空气质量pm2.5 [打印本页]

作者: 1047521767    时间: 2021-10-15 10:53
标题: 使用LSTM预测空气质量pm2.5
使用LSTM预测时间序列数据, X  v) `- U" u& }
0 s! n0 b5 E9 U

7 r; G) s5 u: `2 t文章目录
% Z+ a* j* y; J2 ~背景
6 `, f$ _7 T# m. I7 B/ {: J6 f结论! |) h$ \4 A: U5 q2 j
代码/ p/ I# B7 |; }) f( e% l* f8 o
实验结果( `! f# ?. d+ b) Z7 ]* x* w
RNN和DNN的区别
& x- s2 r1 d: T  f- J; S6 a: URNN和LSTM的区别" m. {" E9 a$ C% y; W: V
背景
; S+ Y) e! ]9 b/ x, c  U复现 @“使用Keras进行LSTM实战” https://blog.csdn.net/u012735708/article/details/82769711 中的实验, H% j& w% o& M% U% Z9 l* t
熟悉用LSTM模型训练
2 C) F3 O3 }" `1 F& L4 l验证将时序数据 转化为分类问题后,预测是否有效果
5 G  k" m$ Y: n# g5 N0 S- w对比SimpleRNN与LSTM模型 哪个效果最好?
2 }9 n: C: e" T, l8 Y0 F验证LSTM相比于Dense()模型 是否有提升?& V3 B4 S, e. i, o$ t$ E5 D
对比使用前3天的数据 和使用前1天的数据 哪个效果最好?
8 i$ d- \. D8 e3 t结论: s7 E5 p. d% Z4 V* Z
使用前3天的数据预测当天的空气质量的效果 没有 比只用前一天的数据 好: z( }+ D& Y1 z- s/ n# g+ ^# y
使用LSTM的效果优于SimpleRNN
2 T! w  I7 w9 F/ o$ Z% v! m( {! G代码
' @" s: b; T, m0 Q8 Vfrom pandas import read_csv" e  ~( Q, g2 T/ q. v- I& O
from datetime import datetime
5 h( A6 r3 h; y7 X; pimport pandas as pd3 L# I$ M" z( _
from pandas import DataFrame
! r  U7 B; \. [9 x7 W8 qfrom sklearn.preprocessing import LabelEncoder,MinMaxScaler5 L+ S) C4 @  F- P, _
from sklearn.metrics import mean_squared_error
0 r% S$ t2 `% A  N! K5 V6 `! c3 N8 H- Tfrom keras.models import Sequential# }; ]+ o- U' D  }$ w
from keras.layers import Dense, Dropout8 h# i4 F) d5 G$ t# L8 A
from keras.layers import LSTM
: M& D8 Z% D" Z4 s0 a, b: z6 |from keras.layers.recurrent import SimpleRNN- i2 n7 n- w, b* _
from numpy import concatenate
" J& M8 o- f3 t% Efrom math import sqrt4 ~3 n3 h& ]! q6 B) L( v3 P: a
! s( r  W# T7 G
7 c) s; x2 ]5 k' {% ?) S2 B9 }
: B0 `) ~5 [% h
: d+ H# Z9 `0 ~5 c1 b! F" G2 }
# load data& b3 H3 B0 q* [- A, j) s+ M
def parse(x):! O. P, H, D" j; m% w
        return datetime.strptime(x, '%Y %m %d %H')
% r2 Z. R( U1 c6 M  |0 Z4 i! C
4 _7 F: c3 m8 G; bdef read_raw():5 c! {( i% T$ d% l; u6 ~3 J' s
    dataset = pd.read_csv('raw.csv',  parse_dates = [['year', 'month', 'day', 'hour']], index_col=0, date_parser=parse)
, n( `: G$ @7 F3 H+ F" j    dataset.drop('No', axis=1, inplace=True)
6 c8 J% [3 S9 G5 M, j: p    # manually specify column names  F: I, p* K8 Q, D$ x# u
    dataset.columns = ['pollution', 'dew', 'temp', 'press', 'wnd_dir', 'wnd_spd', 'snow', 'rain']
0 G/ s: D: }: g    dataset.index.name = 'date') F7 ]! x  i6 Y- ?! G
    # mark all NA values with 0
$ ^7 e  u1 ?0 h& r8 V; j( o2 U    dataset['pollution'].fillna(0, inplace=True)
% M2 W) }" g$ y2 D$ E    # drop the first 24 hours  b  W3 p0 z4 ^8 q0 \
    dataset = dataset[24:]
6 {5 y- A& I# ]: x: ~& ]9 v    # summarize first 5 rows  J; l8 B' p/ ?- ]$ t) ^
    print(dataset.head(5))' ]1 j$ q( a/ \2 b' q. M
    # save to file( S# u* z( T8 _5 Z4 e. W
    dataset.to_csv('pollution.csv')
" R; K% X4 A5 u3 Z" i8 s' J" v9 C- S- i3 Z9 `6 v  c' Q

0 d) b9 l4 {3 S2 w9 u
! @4 r: E, ]9 r3 ^4 \

) g$ @# P) X, B0 r9 O/ q9 ?# convert series to supervised learning
# L8 |" R; C+ P3 R: c6 d& z5 i4 w* Mdef series_to_supervised(data, n_in=1, n_out=1, dropnan=True):
# A! v. e, k. g" N9 {    n_vars = 1 if type(data) is list else data.shape[1]
" [% _2 Y5 x  a6 D( Z9 p3 O( U    df = DataFrame(data)
& c5 P0 ]1 Z5 ]    cols, names = list(), list()- G# W  a$ G, n# F
    # input sequence (t-n, ... t-1): J3 e6 W0 i% G  U, g
    for i in range(n_in, 0, -1):# k; N+ ^# F# x& D4 S
        cols.append(df.shift(i))6 D& [. y3 U( S
        names += [('var%d(t-%d)' % (j+1, i)) for j in range(n_vars)]
# \9 g; y1 ]/ ^3 z& s4 Z    # forecast sequence (t, t+1, ... t+n)
# ^1 b' d: R' L+ P, O    for i in range(0, n_out):& Y9 |( _/ E+ D3 D: q+ l
        cols.append(df.shift(-i))
% w# D8 `% l2 P2 z" |        if i == 0:7 k/ P; _, j4 a  w
            names += [('var%d(t)' % (j+1)) for j in range(n_vars)]
  _& Y% j) Y1 Y5 E, O) ?( L3 k        else:
- t8 e! T! T" ?* ^            names += [('var%d(t+%d)' % (j+1, i)) for j in range(n_vars)]
4 g5 B7 o- `( Y0 v  K3 V3 i/ e! W, \    # put it all together5 v: u7 N  p: K1 U1 j; _" f  @
    agg = pd.concat(cols, axis=1)
9 k, q/ j; f' A4 T9 y6 f4 _- S# l. }    agg.columns = names6 u4 V# x- [3 b6 O# X$ Y; N" h
    # drop rows with NaN values) t8 ?, w# c1 }/ y
    if dropnan:
& N" M2 ~- v# x* Y* t        agg.dropna(inplace=True)
* U+ v* i$ [- c6 }% C2 e. G8 d    return agg* p* v& V4 }0 N
3 [, O/ T% F' q' {$ C
# load dataset0 k; S' N9 L, q8 Y3 K+ ~
dataset = read_csv('pollution.csv', header=0, index_col=0)- V. R4 r( X. ~/ D/ a- T
values = dataset.values
( _/ @* b; S- x$ K# n4 T) M" T  l* r& f' l9 `$ s2 F: M/ S2 q
4 Z, V& B! ^' w+ g7 z; e
# integer encode direction
4 K' Y" x7 r) y) V* Sencoder = LabelEncoder()8 T( i6 {4 e# J( d( V) ], M
print(values[:,4]), y5 ]; ^, W. b
values[:,4] = encoder.fit_transform(values[:,4])5 v7 t& K# {# j5 T0 J
# ensure all data is float' c' F$ B. S6 A  W8 }
values = values.astype('float32')! l1 j8 A+ v9 m! R
# normalize features! F0 A+ Z+ |) U) f+ c
scaler = MinMaxScaler(feature_range=(0, 1)); B3 U* f* ~# u8 P/ i( d' l: B
scaled = scaler.fit_transform(values). k: m! y4 ^4 h6 ~) ^' B
# frame as supervised learning
/ J, H2 q; ^: qreframed = series_to_supervised(scaled, 1, 1) - n1 j; {/ }8 j4 E
#reframed = series_to_supervised(scaled, 3, 1) #用前3天的数据,预测当天的数据
- }1 M9 Y, l4 p9 g- \/ {1 {print("columns:", reframed.columns)
# m9 d6 b& b2 i3 N7 {# drop columns we don't want to predict2 W. `. O' ]0 Y/ T; P9 r5 e$ O
reframed.drop(reframed.columns[[9,10,11,12,13,14,15]], axis=1, inplace=True) #用前1天的数据,预测当天的数据
* U' h. J' n- h) `6 R3 c% D#reframed.drop(reframed.columns[[25,26,27,28,29,30,31]], axis=1, inplace=True)#用前3天的数据,预测当天的数据$ t  \. t# |8 r+ \! [& q
print(reframed.head())9 J6 v& v) {" m) N1 l0 s
print("new columns:", reframed.columns)& r: b# P5 b( f$ a
# split into train and test sets
" G% ]0 ], t! G' }+ u7 H4 J8 _, Mvalues = reframed.values
' f/ W9 s* Q8 [) R! P7 {) en_train_hours = 365 * 24+ w2 H( o* ~4 }* w
train = values[:n_train_hours, :]
1 ?& R- I0 I, I* Ftest = values[n_train_hours:, :]
: \) J% F1 ?- ~$ l# split into input and outputs
+ @+ S7 R# R" G4 Q5 ytrain_X, train_y = train[:, :-1], train[:, -1]
. z6 r2 n  g0 Ztest_X, test_y = test[:, :-1], test[:, -1]& u, y4 c  T4 u- n3 }2 @
# reshape input to be 3D [samples, timesteps, features]: k% u8 Z( i# f$ m$ r# R( M, j
#使用Dense()模型时不用变换% Y# t, l0 g! i$ W1 ?
train_X = train_X.reshape((train_X.shape[0], 1, train_X.shape[1]))6 A1 ~/ [) c1 m: U# R  y
test_X = test_X.reshape((test_X.shape[0], 1, test_X.shape[1]))/ U4 W9 i8 K4 {' y! Z( U7 y; z9 a: o
print(train_X.shape, train_y.shape, test_X.shape, test_y.shape)5 U/ N: N6 j: ]5 w# w. a' V: l
# design network- h5 P" |  {# E8 c: f# F+ l
model = Sequential()
9 e9 ?* y- \2 h3 U5 w#model.add(LSTM(50, input_shape=(train_X.shape[1], train_X.shape[2])))9 A, b/ S; y# H+ a3 T  A- o
#model.add(Dense(50, activation='relu', input_dim = 8))3 M( n9 V1 \6 [+ N
model.add(SimpleRNN(50, input_shape=(train_X.shape[1], train_X.shape[2])))3 I7 t" j4 M( X3 u  w- N  S! @
model.add(Dense(1))1 C' t5 E3 f3 e0 @( p( g5 K& g% V
model.compile(loss='mae', optimizer='adam'): o) d; R3 P& P; x2 `6 e/ N, r
# fit network
8 @( C9 Q7 P- b& N& Ohistory = model.fit(train_X, train_y, epochs=50, batch_size=72, validation_data=(test_X, test_y), verbose=2, shuffle=False): D/ T* c) ^7 \
# make a prediction# v" `1 f/ B) o3 J  I& P: ^
yhat = model.predict(test_X)9 `- P: ]4 M3 W) [2 F$ _, @
print("yhat shape:", yhat.shape)
7 v7 H3 b8 Q: w+ `'''
+ u4 p% M5 _: D' X计算在测试集上的均方差
% N1 Y9 n$ P, M( p/ z; u/ u& S( ~# F" o. Xtest_X = test_X.reshape((test_X.shape[0], test_X.shape[2]))
1 h" Q- S: p! \( v0 {print("test_X shape:", test_X.shape)" g$ F5 V3 s+ u
. p& [9 U/ F4 c& A, K6 i3 D$ g$ H

" r8 l9 K+ `8 n+ `! G  C' d: d# invert scaling for forecast2 b& V) m4 w2 G+ w$ }0 S
inv_yhat = concatenate((yhat, test_X[:, 1:]), axis=1)8 i/ j, F# }1 \/ a2 E
inv_yhat = scaler.inverse_transform(inv_yhat)
/ p1 s$ Y" u& k; L6 _- q2 @) Winv_yhat = inv_yhat[:,0]3 L2 {% [. B- ^1 u5 p' E
# invert scaling for actual
# I5 r5 m* h) W: P7 P0 t+ Jtest_y = test_y.reshape((len(test_y), 1))
* ~0 C7 C9 J& k9 T  S, Zinv_y = concatenate((test_y, test_X[:, 1:]), axis=1)
2 R, [5 N+ ^/ q+ _9 mprint("inv_y:", inv_y[:10])+ J! k: Z% G) }. Q; K7 m0 L
print("inv_y shape:", inv_y.shape)3 ~) u( u  {. b+ G/ {
: U+ t* ^% U- X8 H6 n$ U
& a* a. q9 J2 Q) K4 I  q" ~4 W; G3 U
inv_y = scaler.inverse_transform(inv_y)
  o* Q7 |5 c* h4 e% e' d: u# jprint(inv_y, "*"*30)
/ s/ f8 _9 }: s* A* S& Z5 b" F' C4 G8 P

* b" K; h. `2 \, i- b* C& Tinv_y = inv_y[:,0]9 i9 z, d1 C# S* E& j% p
# calculate RMSE
" v2 I" j, Q+ U4 I' n# _rmse = sqrt(mean_squared_error(inv_y, inv_yhat))4 S! i: p9 J" G. t' ^, j* M9 r% |
print(inv_y[:100], inv_yhat[:100])
- G% \% C7 T& [7 K# a8 z/ T2 Gprint('Test RMSE: %.3f' % rmse)
3 Z  a) W! t4 a1 ^
" n: e( h( R8 C3 p9 P

6 F3 q# F- n1 e) L( c'''3 @! Q8 L5 Y  R% p1 `' I
实验结果* Q$ O+ h3 _5 z, J8 g  `2 G
实验1:用前一天的天气数据,预测某一天的空气质量1 i% d: c4 j" X7 t/ ~, \! m( a
使用LSTM模型" o4 i6 Q+ R8 i6 F; p
结果:
/ N. t: ^5 B! u6 o" B0 y$ h# WEpoch 49/50
7 T. n/ x( k9 `6 O. p0s - loss: 0.0144 - val_loss: 0.0133
/ D/ ?, F  ^. s2 K4 kEpoch 50/50" x" n9 Y1 U, U0 b( x& R
0s - loss: 0.0144 - val_loss: 0.01331 Y2 h1 I3 S- n- `4 C+ l/ o* A8 u+ h* I

/ i8 v; E% s; B

. a8 @! k/ W! @: L) p& u5 d: t实验2:用前3天的天气数据,预测某一天的空气质量6 M3 |! L8 u/ f1 W
使用LSTM模型
" n. |* E1 A9 Q; ~7 ?$ J7 C; t
0 `+ ], W5 A5 i5 _  _

; r% m( s2 {! u1 V结果:6 q( }! G+ H' U' N4 v5 W  f
Epoch 49/50
2 D7 Y; |2 m5 e) M3 k5 O0s - loss: 0.0147 - val_loss: 0.0149! e) w$ k1 f8 y+ _5 @
Epoch 50/500 m0 t( d3 C6 [2 x5 d
0s - loss: 0.0147 - val_loss: 0.0150. K- r! Y+ M2 t4 K! l. E) e

. x. x; t0 T9 Q+ ?

  ^) V6 e/ q5 [. d实验3:用前一天的天气数据,预测某一天的空气质量- i$ i( y, m" R0 @6 I" ^" _6 w
使用普通的全连接模型 Dense()
% l8 ~% C# X3 M, o6 g- Q  Q结果:
) I! F( c" h5 s4 mEpoch 49/50( @* x) m+ U$ ]0 B' [) E! x
0s - loss: 0.0144 - val_loss: 0.01460 L5 y1 t; ^; i6 i# D
Epoch 50/500 Z/ `- g. Q8 h3 P" N; N& L
0s - loss: 0.0148 - val_loss: 0.0151
) X0 B6 y# o# C' T/ m1 i! _5 d9 V" z: k, E& b. |  ^
' H( V1 J+ z: b% R
实验4:用前三天的天气数据,预测某一天的空气质量3 a" o. ~) t8 H6 y8 {+ ~+ k9 L. s
使用普通的全连接模型 Dense()  z0 z5 J$ d% `/ n6 _
结果:. a/ r1 S6 `' \) M( W3 E' V8 Z0 ^
Epoch 49/50
& F2 M* p$ ^% |& s: K$ P0s - loss: 0.0150 - val_loss: 0.01652 F+ T8 \) d; Q% @$ |' O
Epoch 50/501 f5 Q/ Y9 W1 j  F9 V( O/ k; h
0s - loss: 0.0148 - val_loss: 0.0141
' i! f) Y. C4 W" L6 R% p7 y$ e! y. z8 A

3 k* S" ?6 l: z$ ^* V  S实验5:用前一天的天气数据,预测某一天的空气质量# i9 j) W* O2 m
使用SimpleRNN& ^, N; g. T+ G0 D
Epoch 49/50
! l9 o8 S& W1 |8 S6 g2 H' {0s - loss: 0.0160 - val_loss: 0.0140: x$ ~* j) _7 v% n
Epoch 50/50
/ `' s9 L7 B8 ?3 M' Y0s - loss: 0.0147 - val_loss: 0.01500 u1 C, x/ n2 j, {" ]) z
4 S% `) w' E. t% G6 h" y7 U

2 u6 X* q$ q& z/ h( r+ M/ h$ G实验6:用前三天的天气数据,预测某一天的空气质量
( w) X. d. U7 i8 q/ U: F使用SimpleRNN
) ]% M7 N5 ~" uEpoch 49/50; K, h5 l  T/ l
0s - loss: 0.0164 - val_loss: 0.0233
# \8 I' @6 E! y7 @! B9 u0 e3 Y1 GEpoch 50/50+ b+ `6 @) h, S, W$ o
0s - loss: 0.0166 - val_loss: 0.0227" u# a) _, [% n/ r( `
RNN和DNN的区别

RNN中的循环是指一个序列当前的输出与前面的输出也有关系。也就是说,网络会对前面的信息进行记忆并应用于当前输出的计算中,即隐层之间的节点不再是无连接的而是有连接的,并且隐层的输入不仅包括输入层的输出还包括上一时刻隐层的输出。

  R0 |1 P8 \4 A

$ B: G# i* R. e% L7 s2 P' f+ F8 B% x
RNN和LSTM的区别2 n( ?% `+ Y' ^9 T7 _$ K
LSTM的内部结构通过门控状态来控制传输状态,记住需要长时间记忆的,忘记不重要的信息;而不像普通的RNN那样只能够“呆萌”地仅有一种记忆叠加方式。对很多需要“长期记忆”的任务来说,尤其好用。
. m% g- d3 V" w( h
" Q8 b1 B, t' f7 W
! G0 {# ^. E% u7 s* q
但也因为引入了很多内容,导致参数变多,也使得训练难度加大了很多。因此很多时候我们往往会使用效果和LSTM相当但参数更少的GRU来构建大训练量的模型。
# ^, y' G* V0 a. I4 O5 N% R- @5 g9 s) l
+ g, h4 P6 ?' ^7 n: \/ C/ \1 _4 Z
请关注数学中国微博和数学中国公众号,如有疑问联系数学中国工作人员
1 F& u! ^- |. h' r8 f! O2 Q
& k6 C+ s% y; H! i4 w$ G, N' Y2 u
2 F2 A) u3 d3 l4 B$ y. M# u

作者: sjlxdn    时间: 2021-10-23 14:51
1111111111111: g" c' V$ M9 l" k, \  P





欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) Powered by Discuz! X2.5