数学建模社区-数学中国
标题: 使用LSTM预测空气质量pm2.5 [打印本页]
作者: 1047521767 时间: 2021-10-15 10:53
标题: 使用LSTM预测空气质量pm2.5
使用LSTM预测时间序列数据& V( U Z3 H% e6 n! Y" w
5 e1 u: B, a5 t* M, D( C
_0 ]1 E) Q* `+ t8 {# O) X文章目录
: c3 \. d# G9 @8 `1 g, a背景( u4 }0 |, D% e, \* L- L0 k# f4 R' U4 P
结论
- }" G% C2 D) M; Y( t0 i代码( S1 a8 I) @2 u1 V9 J
实验结果/ }8 q! O9 N9 B8 @
RNN和DNN的区别
1 U5 R( [+ |! @RNN和LSTM的区别
" ~* ?' H0 w P% D. v. A背景
# C( J$ g$ @! ?, J& Y. u" [复现 @“使用Keras进行LSTM实战” https://blog.csdn.net/u012735708/article/details/82769711 中的实验
2 `5 y( T- h" W+ C3 z熟悉用LSTM模型训练
' x0 [) S9 k- t, f, O! S: k( y4 l+ e验证将时序数据 转化为分类问题后,预测是否有效果
+ P$ _; b+ u& P; \. A. g. f1 f对比SimpleRNN与LSTM模型 哪个效果最好?
4 f4 b* G5 e# g1 b- ?" r3 r+ v+ j验证LSTM相比于Dense()模型 是否有提升?7 k( w2 L2 `9 O" ^1 k/ O9 [, p+ w
对比使用前3天的数据 和使用前1天的数据 哪个效果最好?7 n" c4 k- Q6 ^6 z6 G+ \) n
结论
) g4 s: ]. p2 ^ _: E- m0 z6 s0 j使用前3天的数据预测当天的空气质量的效果 没有 比只用前一天的数据 好1 x# m- u/ g' K. g5 B( d2 f
使用LSTM的效果优于SimpleRNN
% s" s) b, k4 m2 w0 |" r+ N' D代码
7 n H( L. z# \9 ]; h, Gfrom pandas import read_csv
- l2 V: Z) r: H0 v; rfrom datetime import datetime9 N( E& U: B: g, G5 i2 e9 d* K: s' j1 _
import pandas as pd
: [2 @3 L& m0 Bfrom pandas import DataFrame
# o9 R& U; R( |9 ~) Gfrom sklearn.preprocessing import LabelEncoder,MinMaxScaler6 I3 m4 h$ Z4 ]+ h& ]
from sklearn.metrics import mean_squared_error" h# v$ H7 p! |3 [; v5 W
from keras.models import Sequential
% A1 ?4 t0 U% }3 q9 h* v! |( Wfrom keras.layers import Dense, Dropout7 G' v; G. A5 B4 \
from keras.layers import LSTM6 q7 e8 V. _4 A& {
from keras.layers.recurrent import SimpleRNN
: T+ u6 F1 R% X c' |% xfrom numpy import concatenate
" G8 g" w" r5 v3 l& s4 wfrom math import sqrt
! Q- h' {5 q. T, \! E7 b
0 Z8 j' G6 w5 ]# Q. b: \/ x) S" N( j
Q! e' P4 q( W3 S" c
I& U7 `5 G. } b5 h9 U- p# load data
$ h6 E& H9 v& {# \def parse(x):
h! m( N* C+ [) U2 N) F return datetime.strptime(x, '%Y %m %d %H')
1 o( {3 r1 U( r$ F
1 c J/ @! {0 m6 P' Hdef read_raw():
$ @/ T' L" [" s8 t. ] dataset = pd.read_csv('raw.csv', parse_dates = [['year', 'month', 'day', 'hour']], index_col=0, date_parser=parse); `# `. a9 y6 D' O0 ~
dataset.drop('No', axis=1, inplace=True)2 x2 Q. f: d6 i9 Z7 p+ c
# manually specify column names
8 j9 k$ y# H" U+ v% s4 ? dataset.columns = ['pollution', 'dew', 'temp', 'press', 'wnd_dir', 'wnd_spd', 'snow', 'rain']
% r: |9 G' D0 m dataset.index.name = 'date'
9 y$ S; Y! `5 w0 X. C# `" t # mark all NA values with 0
* y6 y& Y9 ?8 _: ? dataset['pollution'].fillna(0, inplace=True)
" |$ c& V0 {5 r& P7 }7 E # drop the first 24 hours
2 |/ m& e9 B8 ? dataset = dataset[24:]
/ F9 u6 g! R! B2 L' X7 | # summarize first 5 rows+ W' K6 @, |. @/ z( m- ?
print(dataset.head(5)): \. i9 S" B& m( M1 k" n
# save to file
# z+ G5 G( L& a, S/ |- u# @( g dataset.to_csv('pollution.csv')
" |2 I2 ~) _( v- J$ e+ X5 Y) o9 Q. _; o. j8 [
+ K, d5 y5 }/ z4 ]1 R6 J
3 k. t: P% C# l) @, J4 X- g' Q
w3 k5 Q. k( `7 s, U$ }' h$ E' z& {# ^+ B# convert series to supervised learning
& h" E9 U2 I3 @5 F+ @0 A6 Vdef series_to_supervised(data, n_in=1, n_out=1, dropnan=True): Q1 v9 w5 v2 N- C9 j0 h2 v) T
n_vars = 1 if type(data) is list else data.shape[1]0 A1 V& Z7 I0 n& [ f/ t3 ^
df = DataFrame(data)
8 w. n6 J# ^2 P- P0 e( J' [ cols, names = list(), list()
+ k- L; Z7 g k/ X2 p4 {$ d # input sequence (t-n, ... t-1)
5 r& g4 h. U+ e for i in range(n_in, 0, -1):
) r" T7 G# H1 J; u. P cols.append(df.shift(i))
& X1 N. x2 v. J! I K$ o6 d names += [('var%d(t-%d)' % (j+1, i)) for j in range(n_vars)]
8 [6 ]% n7 C' i8 Y # forecast sequence (t, t+1, ... t+n)0 b; z# t2 Z+ h; O8 K' x" r
for i in range(0, n_out):6 R0 _+ m* O/ M( J) E& F
cols.append(df.shift(-i))
" h- j. Z+ e4 m$ l4 N if i == 0:
% i1 K9 A, B) S+ D; M1 ` names += [('var%d(t)' % (j+1)) for j in range(n_vars)]# X' b1 v- K: c* c
else:( \2 G3 v5 Q9 C" C. N
names += [('var%d(t+%d)' % (j+1, i)) for j in range(n_vars)]
6 L) h( O9 _) f t # put it all together% e9 a( S$ M+ }0 c# s3 n0 d$ A8 C
agg = pd.concat(cols, axis=1)
8 _0 x2 \8 p* V) H1 O! G, k3 j agg.columns = names7 O* y, j" Q+ |; p ?+ @9 k% z
# drop rows with NaN values
+ t. `: p" _5 k- X! y) f if dropnan:3 H: A E) {5 }' o/ y$ F: |% m
agg.dropna(inplace=True); _" e. o- F' V1 C" p L# l
return agg- b, N0 S/ i9 t7 V9 l
: B2 s- k! U- Q" F# load dataset
& K$ J1 A" a& U' fdataset = read_csv('pollution.csv', header=0, index_col=0)5 B* S" X0 {+ O% l+ w' }4 W2 J
values = dataset.values8 G1 f2 [5 G- j- Z+ ^- e
" z' E' E) c4 b9 d8 d
" L: k2 Y: G1 ?7 [* O4 P- j# integer encode direction) ?$ W1 I# X ?, h
encoder = LabelEncoder()! C4 R6 a, C$ F
print(values[:,4])& N* U6 \2 n, ~
values[:,4] = encoder.fit_transform(values[:,4]); h3 t4 A5 ^0 p. a3 G; C
# ensure all data is float
2 F) Q) Y, Y" U. N; Nvalues = values.astype('float32')( y2 A; h4 t2 Q/ ?2 @5 h
# normalize features
# |' i: b, L4 a/ f' ~" f' Hscaler = MinMaxScaler(feature_range=(0, 1))% g2 |: m$ n; |; t: }) T! R: M& S
scaled = scaler.fit_transform(values)$ v7 `% V9 R# K; m; A% ?# N. v
# frame as supervised learning
6 i6 ]9 N, z9 ?reframed = series_to_supervised(scaled, 1, 1)
/ e, k$ N* ~9 p#reframed = series_to_supervised(scaled, 3, 1) #用前3天的数据,预测当天的数据
' l2 Q2 N, y: {& j1 cprint("columns:", reframed.columns)
& Y: q* J5 q O1 B" X- o! Y# drop columns we don't want to predict
4 X0 R @+ W& ^7 K1 p% b9 rreframed.drop(reframed.columns[[9,10,11,12,13,14,15]], axis=1, inplace=True) #用前1天的数据,预测当天的数据" ~2 W* O6 R$ t. Y j) b
#reframed.drop(reframed.columns[[25,26,27,28,29,30,31]], axis=1, inplace=True)#用前3天的数据,预测当天的数据
' K" {, u7 n H+ h% x- Kprint(reframed.head())
5 x/ Y, p+ e% e Pprint("new columns:", reframed.columns)5 C. M6 p9 [1 {
# split into train and test sets
4 y+ @* g8 H. D- b/ qvalues = reframed.values
1 J$ L" F5 r. c* an_train_hours = 365 * 24! N: E. e7 D. K4 ^6 m' B* K
train = values[:n_train_hours, :]( |! g7 t- U0 Z: m: v. C8 ~
test = values[n_train_hours:, :]
) ?. q* n& L! V4 ^6 _) d# split into input and outputs
- ]% |" D* @) D7 R2 Otrain_X, train_y = train[:, :-1], train[:, -1]2 z6 ]0 o8 w! q% ^
test_X, test_y = test[:, :-1], test[:, -1]
0 L1 g w& o7 C) {# K# ]# reshape input to be 3D [samples, timesteps, features]/ X. C% T$ S$ Z h2 Q5 Y) u ~
#使用Dense()模型时不用变换- H) v1 x. V& s' F+ G& a z
train_X = train_X.reshape((train_X.shape[0], 1, train_X.shape[1]))% i- h) d+ a. ?& Z& X/ K
test_X = test_X.reshape((test_X.shape[0], 1, test_X.shape[1]))8 h2 \$ g- d9 R Q. |
print(train_X.shape, train_y.shape, test_X.shape, test_y.shape)
9 n; j8 f# ]- q" N# design network8 c2 q J8 {8 ?: `
model = Sequential()
$ D' f% x/ r; U9 H/ [#model.add(LSTM(50, input_shape=(train_X.shape[1], train_X.shape[2]))), i2 j q& x2 E) D0 k( }7 u g1 p
#model.add(Dense(50, activation='relu', input_dim = 8))( B1 D" A8 w4 ^& t
model.add(SimpleRNN(50, input_shape=(train_X.shape[1], train_X.shape[2])))
* @# U. `8 t& [& H7 H8 J) Imodel.add(Dense(1))3 j1 X, g2 u, E6 a+ v) C
model.compile(loss='mae', optimizer='adam')9 Z0 n7 P8 X% M3 K0 L
# fit network$ I5 O4 E+ F: h) z/ X. C3 A
history = model.fit(train_X, train_y, epochs=50, batch_size=72, validation_data=(test_X, test_y), verbose=2, shuffle=False)
) {# A$ ?% A! t8 _9 z% z- |# make a prediction$ q: \7 t, c5 O& W
yhat = model.predict(test_X)2 p4 e2 }- E/ ]2 _4 S& ^
print("yhat shape:", yhat.shape)
8 {: Q0 b/ ]& A" _7 ~'''
+ }: ]. W- `5 @. ^/ ^" H计算在测试集上的均方差/ j3 _! K) s n4 N6 E& { w
test_X = test_X.reshape((test_X.shape[0], test_X.shape[2]))$ \1 T. j5 \8 h8 L* y
print("test_X shape:", test_X.shape)
3 N: ]# [- @: ~: E# ^* B9 {( b! a9 d4 ?; S( S
2 J; {# Y, P" E1 a# invert scaling for forecast/ B. k( k% n' U4 G+ o, j
inv_yhat = concatenate((yhat, test_X[:, 1:]), axis=1)
' W3 t1 i5 z1 w- t- Pinv_yhat = scaler.inverse_transform(inv_yhat)' ~* M6 d# ^$ r3 v$ Z5 f" W' Q
inv_yhat = inv_yhat[:,0]
: D! t3 ?6 p( S# W% _ d& ^3 ~) ` N# invert scaling for actual
! |. \- @# O% R0 Ztest_y = test_y.reshape((len(test_y), 1))
( \% v1 c1 I9 D) a% U; o. M, uinv_y = concatenate((test_y, test_X[:, 1:]), axis=1)* F5 K1 V/ g8 v) C
print("inv_y:", inv_y[:10])" t6 z e5 X) u0 K2 F, A, G
print("inv_y shape:", inv_y.shape)" e$ h4 g+ j! A" r7 z8 [$ c# Q
* x1 f: H. m; ?* s- ]
4 Y8 E, I9 e) v8 F9 `* _inv_y = scaler.inverse_transform(inv_y)& m7 l9 c& `) Q1 p' v* N+ P B: }
print(inv_y, "*"*30), }) K8 w+ c& i
0 _0 f2 \4 A: C. g! [ ]3 ]2 x8 D* h
inv_y = inv_y[:,0]
$ v+ b4 Y; J p; r# calculate RMSE9 q2 Q4 G) e* f- W
rmse = sqrt(mean_squared_error(inv_y, inv_yhat))2 m4 Z& S9 W8 c5 e& V$ w1 C& F+ \
print(inv_y[:100], inv_yhat[:100])
& w' f* n: j9 Yprint('Test RMSE: %.3f' % rmse)7 s! J1 g8 R& Q& Y; Q4 S
6 q; j7 { Y0 a
^, Q# K, s ^1 g5 M$ Y' l9 n4 h
''': G4 ?$ o6 E9 r+ D" ]
实验结果
! \( D3 u. c* G) @ z; C实验1:用前一天的天气数据,预测某一天的空气质量$ g" |. K$ m5 }) t
使用LSTM模型
- x6 n3 L7 w3 _, a: Q _结果:0 R& m; u" _) G
Epoch 49/50 Y1 @" Y& P" D, Q* w5 ]8 L
0s - loss: 0.0144 - val_loss: 0.0133
! Y( D) y/ {8 V0 x7 p0 Q, cEpoch 50/50! e2 u+ h: \4 c5 I& ^" v) p
0s - loss: 0.0144 - val_loss: 0.0133: s6 a; _2 ^4 T1 l) O0 C& u
$ J4 O, u1 S* ?- g! n- S9 E: X' l- m) _/ `4 v3 N' y) O" `1 u# ~# g
实验2:用前3天的天气数据,预测某一天的空气质量
! y6 e4 ~; i, ], [# B8 ?3 i使用LSTM模型
6 ~9 c$ q3 }7 H6 e/ e6 V9 b" `5 F' W% h2 E& s% x/ Q: p
% O8 W$ C6 J/ h/ R" ]结果:& b5 O Z' v- F, x m
Epoch 49/50% Z& @% G- G) O& d2 g. f' f
0s - loss: 0.0147 - val_loss: 0.0149* a' I- H# j( Y6 E* J, N$ f" Y# K
Epoch 50/509 g6 I3 Y( ] O$ i5 q
0s - loss: 0.0147 - val_loss: 0.0150' K: D! ]% d. t. k: H/ c
9 D# `/ ?4 e- R( [0 K
$ h) N6 k4 C+ b实验3:用前一天的天气数据,预测某一天的空气质量% u e7 U* W0 L: i6 {
使用普通的全连接模型 Dense()" L3 z* C. A; l0 l( n; N
结果:1 n: U/ m# X! L2 ^6 n# p
Epoch 49/50' U( c; X& a% ?9 ^4 z
0s - loss: 0.0144 - val_loss: 0.0146- k1 k6 }6 m& u* z$ ?4 b
Epoch 50/507 W5 F q3 ~) G! y& ?3 x
0s - loss: 0.0148 - val_loss: 0.0151
( M& X+ ?5 y$ I# v# Y" Z3 p" q: L9 ?
' A# _( @$ I" c% Q' r实验4:用前三天的天气数据,预测某一天的空气质量
% m0 {& h) C5 a使用普通的全连接模型 Dense()
: h3 _4 t: w4 v+ N5 K0 x) t- R结果:8 E) E% t+ @& u" a
Epoch 49/50, a' [* L! S' J# m5 |7 X
0s - loss: 0.0150 - val_loss: 0.01659 L8 p4 D6 W7 m; [" z; P
Epoch 50/50/ F2 {" C8 C' A e& i& y T+ F9 \. D
0s - loss: 0.0148 - val_loss: 0.0141% {8 j' l; m' i9 R* H
2 | w0 B8 V7 d C$ k& V4 t( Z
3 K6 o" {& y- J: \0 F& ]: Q
实验5:用前一天的天气数据,预测某一天的空气质量4 e% t: X: d5 H" X3 T" q# p9 L
使用SimpleRNN
% T1 r! b6 [9 S" M& s. F5 |# rEpoch 49/508 @% P( y& t" G' e, g2 L2 H
0s - loss: 0.0160 - val_loss: 0.0140
9 j1 S+ D" c6 `: FEpoch 50/50
9 W# f4 A1 e r7 Q9 {* D0s - loss: 0.0147 - val_loss: 0.0150
, |( C( S" u/ ^/ p, _! b1 s# k: N2 }
7 o; N8 O# N! W& v% T& v' I
实验6:用前三天的天气数据,预测某一天的空气质量7 e+ N4 V0 g$ j# A/ u
使用SimpleRNN
! V& X0 U) J" z: s8 j% z4 M" cEpoch 49/50
# \+ f0 }( B" a/ m7 x0s - loss: 0.0164 - val_loss: 0.02330 ~5 d# P4 t" I. }7 V) p/ P5 {' e' C
Epoch 50/50
$ P0 h6 ~- Y+ k0s - loss: 0.0166 - val_loss: 0.0227
} G+ l, n8 _$ l1 y I, C NRNN和DNN的区别RNN中的循环是指一个序列当前的输出与前面的输出也有关系。也就是说,网络会对前面的信息进行记忆并应用于当前输出的计算中,即隐层之间的节点不再是无连接的而是有连接的,并且隐层的输入不仅包括输入层的输出还包括上一时刻隐层的输出。
+ y8 c `& N* d3 c5 E
% h6 k ?& n6 U% \/ J( h( Z
% [ d( [# ^" H5 _1 ]) G& Q8 i# L, PRNN和LSTM的区别( k: [- X4 u2 X9 d9 V: @
LSTM的内部结构通过门控状态来控制传输状态,记住需要长时间记忆的,忘记不重要的信息;而不像普通的RNN那样只能够“呆萌”地仅有一种记忆叠加方式。对很多需要“长期记忆”的任务来说,尤其好用。
- i" |7 b: b' n% f+ ]9 u% _& s- c8 I |+ w- N8 U
' N0 r8 v2 D' i; s. c
但也因为引入了很多内容,导致参数变多,也使得训练难度加大了很多。因此很多时候我们往往会使用效果和LSTM相当但参数更少的GRU来构建大训练量的模型。
3 D$ _$ ]* `. [! G6 T6 T# H) ?' i
* I8 u+ u, o- i' ?/ R
6 n9 ^& c# Y/ C请关注数学中国微博和数学中国公众号,如有疑问联系数学中国工作人员
) @3 R# m+ s& }& U. J. A! h" a
3 p0 q6 |( g1 b+ b( O: s" A3 E: F) _$ a) T/ x+ K9 K3 F
作者: sjlxdn 时间: 2021-10-23 14:51
1111111111111+ r4 ~& ]9 c- i
| 欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) |
Powered by Discuz! X2.5 |