使用tensorflow的lstm网络进行时间序列预测

标签: lstm tensorflow 时间序列 机器学习
2017年12月20日 14:25:283370人阅读 评论(1) 收藏 举报
使用tensorflow的lstm网络进行时间序列预测 分类:
机器学习(13) 使用tensorflow的lstm网络进行时间序列预测 TensorFlow(2) 使用tensorflow的lstm网络进行时间序列预测

这篇文章将讲解如何使用lstm进行时间序列方面的预测,重点讲lstm的应用,原理部分可参考以下两篇文章:

Understanding LSTM Networks       LSTM学习笔记

编程环境:python3.5,tensorflow 1.0

本文所用的数据集来自于kesci平台,由云脑机器学习实战训练营提供:真实业界数据的时间序列预测挑战

数据集采用来自业界多组相关时间序列(约40组)与外部特征时间序列(约5组)。本文只使用其中一组数据进行建模。

加载常用的库:

[python] view plain copy
  1. <span style="font-size:14px;">#加载数据分析常用库  
  2. import pandas as pd  
  3. import numpy as np  
  4. import tensorflow as tf  
  5. from sklearn.metrics import mean_absolute_error,mean_squared_error  
  6. from sklearn.preprocessing import MinMaxScaler  
  7. import matplotlib.pyplot as plt  
  8. % matplotlib inline  
  9. import warnings   
  10. warnings.filterwarnings('ignore')</span>  
数据显示:
[python] view plain copy
  1. path = '../input/industry/industry_timeseries/timeseries_train_data/11.csv'  
  2. data11 = pd.read_csv(path,names=['年','月','日','当日最高气温','当日最低气温','当日平均气温','当日平均湿度','输出'])  
  3. data11.head()  
  当日最高气温 当日最低气温 当日平均气温 当日平均湿度 输出
0 2015 2 1 1.9 -0.4 0.7875 75.000 814.155800
1 2015 2 2 6.2 -3.9 1.7625 77.250 704.251112
2 2015 2 3 7.8 2.0 4.2375 72.750 756.958978
3 2015 2 4 8.5 -1.2 3.0375 65.875 640.645401
4 2015 2 5 7.9 -3.6 1.8625 55.375 631.725130

加载数据:
[python] view plain copy
  1. ##load data(本文以第一个表为例,其他表类似,不再赘述)  
  2. f=open('../input/industry/industry_timeseries/timeseries_train_data/11.csv')   
  3. df=pd.read_csv(f)     #读入数据  
  4. data=df.iloc[:,3:8].values   #取第3-7列  
定义常量并初始化权重:
[python] view plain copy
  1. #定义常量  
  2. rnn_unit=10       #hidden layer units  
  3. input_size=4        
  4. output_size=1  
  5. lr=0.0006         #学习率  
  6. tf.reset_default_graph()  
  7. #输入层、输出层权重、偏置  
  8. weights={  
  9.          'in':tf.Variable(tf.random_normal([input_size,rnn_unit])),  
  10.          'out':tf.Variable(tf.random_normal([rnn_unit,1]))  
  11.          }  
  12. biases={  
  13.         'in':tf.Variable(tf.constant(0.1,shape=[rnn_unit,])),  
  14.         'out':tf.Variable(tf.constant(0.1,shape=[1,]))  
  15.         }  
分割数据集,将数据分为训练集和验证集(最后90天做验证,其他做训练):
[python] view plain copy
  1. def get_data(batch_size=60,time_step=20,train_begin=0,train_end=487):  
  2.     batch_index=[]  
  3.           
  4.     scaler_for_x=MinMaxScaler(feature_range=(0,1))  #按列做minmax缩放  
  5.     scaler_for_y=MinMaxScaler(feature_range=(0,1))  
  6.     scaled_x_data=scaler_for_x.fit_transform(data[:,:-1])  
  7.     scaled_y_data=scaler_for_y.fit_transform(data[:,-1])  
  8.       
  9.     label_train = scaled_y_data[train_begin:train_end]  
  10.     label_test = scaled_y_data[train_end:]  
  11.     normalized_train_data = scaled_x_data[train_begin:train_end]  
  12.     normalized_test_data = scaled_x_data[train_end:]  
  13.       
  14.     train_x,train_y=[],[]   #训练集x和y初定义  
  15.     for i in range(len(normalized_train_data)-time_step):  
  16.         if i % batch_size==0:  
  17.             batch_index.append(i)  
  18.         x=normalized_train_data[i:i+time_step,:4]  
  19.         y=label_train[i:i+time_step,np.newaxis]  
  20.         train_x.append(x.tolist())  
  21.         train_y.append(y.tolist())  
  22.     batch_index.append((len(normalized_train_data)-time_step))  
  23.       
  24.     size=(len(normalized_test_data)+time_step-1)//time_step  #有size个sample   
  25.     test_x,test_y=[],[]    
  26.     for i in range(size-1):  
  27.         x=normalized_test_data[i*time_step:(i+1)*time_step,:4]  
  28.         y=label_test[i*time_step:(i+1)*time_step]  
  29.         test_x.append(x.tolist())  
  30.         test_y.extend(y)  
  31.     test_x.append((normalized_test_data[(i+1)*time_step:,:4]).tolist())  
  32.     test_y.extend((label_test[(i+1)*time_step:]).tolist())      
  33.       
  34.     return batch_index,train_x,train_y,test_x,test_y,scaler_for_y  

定义LSTM的网络结构:
[python] view plain copy
  1. #——————————————————定义神经网络变量——————————————————  
  2. def lstm(X):    
  3.     batch_size=tf.shape(X)[0]  
  4.     time_step=tf.shape(X)[1]  
  5.     w_in=weights['in']  
  6.     b_in=biases['in']    
  7.     input=tf.reshape(X,[-1,input_size])  #需要将tensor转成2维进行计算,计算后的结果作为隐藏层的输入  
  8.     input_rnn=tf.matmul(input,w_in)+b_in  
  9.     input_rnn=tf.reshape(input_rnn,[-1,time_step,rnn_unit])  #将tensor转成3维,作为lstm cell的输入  
  10.     cell=tf.contrib.rnn.BasicLSTMCell(rnn_unit)  
  11.     #cell=tf.contrib.rnn.core_rnn_cell.BasicLSTMCell(rnn_unit)  
  12.     init_state=cell.zero_state(batch_size,dtype=tf.float32)  
  13.     output_rnn,final_states=tf.nn.dynamic_rnn(cell, input_rnn,initial_state=init_state, dtype=tf.float32)  #output_rnn是记录lstm每个输出节点的结果,final_states是最后一个cell的结果  
  14.     output=tf.reshape(output_rnn,[-1,rnn_unit]) #作为输出层的输入  
  15.     w_out=weights['out']  
  16.     b_out=biases['out']  
  17.     pred=tf.matmul(output,w_out)+b_out  
  18.     return pred,final_states  

模型训练与预测:
[python] view plain copy
  1. #——————————————————训练模型——————————————————  
  2. def train_lstm(batch_size=80,time_step=15,train_begin=0,train_end=487):  
  3.     X=tf.placeholder(tf.float32, shape=[None,time_step,input_size])  
  4.     Y=tf.placeholder(tf.float32, shape=[None,time_step,output_size])  
  5.     batch_index,train_x,train_y,test_x,test_y,scaler_for_y = get_data(batch_size,time_step,train_begin,train_end)  
  6.     pred,_=lstm(X)  
  7.     #损失函数  
  8.     loss=tf.reduce_mean(tf.square(tf.reshape(pred,[-1])-tf.reshape(Y, [-1])))  
  9.     train_op=tf.train.AdamOptimizer(lr).minimize(loss)    
  10.     with tf.Session() as sess:  
  11.         sess.run(tf.global_variables_initializer())  
  12.         #重复训练5000次  
  13.         iter_time = 5000  
  14.         for i in range(iter_time):  
  15.             for step in range(len(batch_index)-1):  
  16.                 _,loss_=sess.run([train_op,loss],feed_dict={X:train_x[batch_index[step]:batch_index[step+1]],Y:train_y[batch_index[step]:batch_index[step+1]]})  
  17.             if i % 100 == 0:      
  18.                 print('iter:',i,'loss:',loss_)  
  19.         ####predict####  
  20.         test_predict=[]  
  21.         for step in range(len(test_x)):  
  22.             prob=sess.run(pred,feed_dict={X:[test_x[step]]})     
  23.             predict=prob.reshape((-1))  
  24.             test_predict.extend(predict)  
  25.               
  26.         test_predict = scaler_for_y.inverse_transform(test_predict)  
  27.         test_y = scaler_for_y.inverse_transform(test_y)  
  28.         rmse=np.sqrt(mean_squared_error(test_predict,test_y))  
  29.         mae = mean_absolute_error(y_pred=test_predict,y_true=test_y)  
  30.         print ('mae:',mae,'   rmse:',rmse)  
  31.     return test_predict  

调用train_lstm()函数,完成模型训练与预测的过程,并统计验证误差(mae和rmse):
[python] view plain copy
  1. test_predict = train_lstm(batch_size=80,time_step=15,train_begin=0,train_end=487)  
迭代5000次后的结果:
[python] view plain copy
  1. iter: 3900 loss: 0.000505382  
  2. iter: 4000 loss: 0.000502154  
  3. iter: 4100 loss: 0.000503413  
  4. iter: 4200 loss: 0.00140424  
  5. iter: 4300 loss: 0.000500015  
  6. iter: 4400 loss: 0.00050004  
  7. iter: 4500 loss: 0.000498159  
  8. iter: 4600 loss: 0.000500861  
  9. iter: 4700 loss: 0.000519379  
  10. iter: 4800 loss: 0.000499999  
  11. iter: 4900 loss: 0.000501265  
  12. mae: 121.183626208    rmse: 162.049017904  

画图分析:

[python] view plain copy
  1. plt.figure(figsize=(24,8))  
  2. plt.plot(data[:, -1])  
  3. plt.plot([None for _ in range(487)] + [x for x in test_predict])  
  4. plt.show()  

结果如下:

使用tensorflow的lstm网络进行时间序列预测

可以看到,lstm模型基本能预测出序列的趋势。
为了简化流程,本文在特征工程及参数调优方面并没有下功夫,适合初学者探索lstm模型在时间序列问题上的应用。
ps:数据的归一化很重要,必须保证把训练集跟验证集规范在同一个空间内,否则得到的效果会很差。(我以前做天池的降雨量预测问题时一开始用的就是lstm,就是这一步没做好,导致最后得到的结果基本很相近,最后这个模型被我放弃了。我在做这个数据集的时候一开始也遇到这个问题,后来在归一化时把样本都设置在同个空间范畴,就解决问题了)。
数据集提供了大概45组数据,所以我们可以使用multi-task learning探索各组数据之间的关联性,这部分我还没具体了解,就不贻笑大方了。

这篇文章将讲解如何使用lstm进行时间序列方面的预测,重点讲lstm的应用,原理部分可参考以下两篇文章:

Understanding LSTM Networks       LSTM学习笔记

编程环境:python3.5,tensorflow 1.0

本文所用的数据集来自于kesci平台,由云脑机器学习实战训练营提供:真实业界数据的时间序列预测挑战

数据集采用来自业界多组相关时间序列(约40组)与外部特征时间序列(约5组)。本文只使用其中一组数据进行建模。

加载常用的库:

[python] view plain copy
  1. <span style="font-size:14px;">#加载数据分析常用库  
  2. import pandas as pd  
  3. import numpy as np  
  4. import tensorflow as tf  
  5. from sklearn.metrics import mean_absolute_error,mean_squared_error  
  6. from sklearn.preprocessing import MinMaxScaler  
  7. import matplotlib.pyplot as plt  
  8. % matplotlib inline  
  9. import warnings   
  10. warnings.filterwarnings('ignore')</span>  
数据显示:
[python] view plain copy
  1. path = '../input/industry/industry_timeseries/timeseries_train_data/11.csv'  
  2. data11 = pd.read_csv(path,names=['年','月','日','当日最高气温','当日最低气温','当日平均气温','当日平均湿度','输出'])  
  3. data11.head()  
  当日最高气温 当日最低气温 当日平均气温 当日平均湿度 输出
0 2015 2 1 1.9 -0.4 0.7875 75.000 814.155800
1 2015 2 2 6.2 -3.9 1.7625 77.250 704.251112
2 2015 2 3 7.8 2.0 4.2375 72.750 756.958978
3 2015 2 4 8.5 -1.2 3.0375 65.875 640.645401
4 2015 2 5 7.9 -3.6 1.8625 55.375 631.725130

加载数据:
[python] view plain copy
  1. ##load data(本文以第一个表为例,其他表类似,不再赘述)  
  2. f=open('../input/industry/industry_timeseries/timeseries_train_data/11.csv')   
  3. df=pd.read_csv(f)     #读入数据  
  4. data=df.iloc[:,3:8].values   #取第3-7列  
定义常量并初始化权重:
[python] view plain copy
  1. #定义常量  
  2. rnn_unit=10       #hidden layer units  
  3. input_size=4        
  4. output_size=1  
  5. lr=0.0006         #学习率  
  6. tf.reset_default_graph()  
  7. #输入层、输出层权重、偏置  
  8. weights={  
  9.          'in':tf.Variable(tf.random_normal([input_size,rnn_unit])),  
  10.          'out':tf.Variable(tf.random_normal([rnn_unit,1]))  
  11.          }  
  12. biases={  
  13.         'in':tf.Variable(tf.constant(0.1,shape=[rnn_unit,])),  
  14.         'out':tf.Variable(tf.constant(0.1,shape=[1,]))  
  15.         }  
分割数据集,将数据分为训练集和验证集(最后90天做验证,其他做训练):
[python] view plain copy
  1. def get_data(batch_size=60,time_step=20,train_begin=0,train_end=487):  
  2.     batch_index=[]  
  3.           
  4.     scaler_for_x=MinMaxScaler(feature_range=(0,1))  #按列做minmax缩放  
  5.     scaler_for_y=MinMaxScaler(feature_range=(0,1))  
  6.     scaled_x_data=scaler_for_x.fit_transform(data[:,:-1])  
  7.     scaled_y_data=scaler_for_y.fit_transform(data[:,-1])  
  8.       
  9.     label_train = scaled_y_data[train_begin:train_end]  
  10.     label_test = scaled_y_data[train_end:]  
  11.     normalized_train_data = scaled_x_data[train_begin:train_end]  
  12.     normalized_test_data = scaled_x_data[train_end:]  
  13.       
  14.     train_x,train_y=[],[]   #训练集x和y初定义  
  15.     for i in range(len(normalized_train_data)-time_step):  
  16.         if i % batch_size==0:  
  17.             batch_index.append(i)  
  18.         x=normalized_train_data[i:i+time_step,:4]  
  19.         y=label_train[i:i+time_step,np.newaxis]  
  20.         train_x.append(x.tolist())  
  21.         train_y.append(y.tolist())  
  22.     batch_index.append((len(normalized_train_data)-time_step))  
  23.       
  24.     size=(len(normalized_test_data)+time_step-1)//time_step  #有size个sample   
  25.     test_x,test_y=[],[]    
  26.     for i in range(size-1):  
  27.         x=normalized_test_data[i*time_step:(i+1)*time_step,:4]  
  28.         y=label_test[i*time_step:(i+1)*time_step]  
  29.         test_x.append(x.tolist())  
  30.         test_y.extend(y)  
  31.     test_x.append((normalized_test_data[(i+1)*time_step:,:4]).tolist())  
  32.     test_y.extend((label_test[(i+1)*time_step:]).tolist())      
  33.       
  34.     return batch_index,train_x,train_y,test_x,test_y,scaler_for_y  

定义LSTM的网络结构:
[python] view plain copy
  1. #——————————————————定义神经网络变量——————————————————  
  2. def lstm(X):    
  3.     batch_size=tf.shape(X)[0]  
  4.     time_step=tf.shape(X)[1]  
  5.     w_in=weights['in']  
  6.     b_in=biases['in']    
  7.     input=tf.reshape(X,[-1,input_size])  #需要将tensor转成2维进行计算,计算后的结果作为隐藏层的输入  
  8.     input_rnn=tf.matmul(input,w_in)+b_in  
  9.     input_rnn=tf.reshape(input_rnn,[-1,time_step,rnn_unit])  #将tensor转成3维,作为lstm cell的输入  
  10.     cell=tf.contrib.rnn.BasicLSTMCell(rnn_unit)  
  11.     #cell=tf.contrib.rnn.core_rnn_cell.BasicLSTMCell(rnn_unit)  
  12.     init_state=cell.zero_state(batch_size,dtype=tf.float32)  
  13.     output_rnn,final_states=tf.nn.dynamic_rnn(cell, input_rnn,initial_state=init_state, dtype=tf.float32)  #output_rnn是记录lstm每个输出节点的结果,final_states是最后一个cell的结果  
  14.     output=tf.reshape(output_rnn,[-1,rnn_unit]) #作为输出层的输入  
  15.     w_out=weights['out']  
  16.     b_out=biases['out']  
  17.     pred=tf.matmul(output,w_out)+b_out  
  18.     return pred,final_states  

模型训练与预测:
[python] view plain copy
  1. #——————————————————训练模型——————————————————  
  2. def train_lstm(batch_size=80,time_step=15,train_begin=0,train_end=487):  
  3.     X=tf.placeholder(tf.float32, shape=[None,time_step,input_size])  
  4.     Y=tf.placeholder(tf.float32, shape=[None,time_step,output_size])  
  5.     batch_index,train_x,train_y,test_x,test_y,scaler_for_y = get_data(batch_size,time_step,train_begin,train_end)  
  6.     pred,_=lstm(X)  
  7.     #损失函数  
  8.     loss=tf.reduce_mean(tf.square(tf.reshape(pred,[-1])-tf.reshape(Y, [-1])))  
  9.     train_op=tf.train.AdamOptimizer(lr).minimize(loss)    
  10.     with tf.Session() as sess:  
  11.         sess.run(tf.global_variables_initializer())  
  12.         #重复训练5000次  
  13.         iter_time = 5000  
  14.         for i in range(iter_time):  
  15.             for step in range(len(batch_index)-1):  
  16.                 _,loss_=sess.run([train_op,loss],feed_dict={X:train_x[batch_index[step]:batch_index[step+1]],Y:train_y[batch_index[step]:batch_index[step+1]]})  
  17.             if i % 100 == 0:      
  18.                 print('iter:',i,'loss:',loss_)  
  19.         ####predict####  
  20.         test_predict=[]  
  21.         for step in range(len(test_x)):  
  22.             prob=sess.run(pred,feed_dict={X:[test_x[step]]})     
  23.             predict=prob.reshape((-1))  
  24.             test_predict.extend(predict)  
  25.               
  26.         test_predict = scaler_for_y.inverse_transform(test_predict)  
  27.         test_y = scaler_for_y.inverse_transform(test_y)  
  28.         rmse=np.sqrt(mean_squared_error(test_predict,test_y))  
  29.         mae = mean_absolute_error(y_pred=test_predict,y_true=test_y)  
  30.         print ('mae:',mae,'   rmse:',rmse)  
  31.     return test_predict  

调用train_lstm()函数,完成模型训练与预测的过程,并统计验证误差(mae和rmse):
[python] view plain copy
  1. test_predict = train_lstm(batch_size=80,time_step=15,train_begin=0,train_end=487)  
迭代5000次后的结果:
[python] view plain copy
  1. iter: 3900 loss: 0.000505382  
  2. iter: 4000 loss: 0.000502154  
  3. iter: 4100 loss: 0.000503413  
  4. iter: 4200 loss: 0.00140424  
  5. iter: 4300 loss: 0.000500015  
  6. iter: 4400 loss: 0.00050004  
  7. iter: 4500 loss: 0.000498159  
  8. iter: 4600 loss: 0.000500861  
  9. iter: 4700 loss: 0.000519379  
  10. iter: 4800 loss: 0.000499999  
  11. iter: 4900 loss: 0.000501265  
  12. mae: 121.183626208    rmse: 162.049017904  

画图分析:

[python] view plain copy
  1. plt.figure(figsize=(24,8))  
  2. plt.plot(data[:, -1])  
  3. plt.plot([None for _ in range(487)] + [x for x in test_predict])  
  4. plt.show()  

结果如下:

使用tensorflow的lstm网络进行时间序列预测

可以看到,lstm模型基本能预测出序列的趋势。
为了简化流程,本文在特征工程及参数调优方面并没有下功夫,适合初学者探索lstm模型在时间序列问题上的应用。
ps:数据的归一化很重要,必须保证把训练集跟验证集规范在同一个空间内,否则得到的效果会很差。(我以前做天池的降雨量预测问题时一开始用的就是lstm,就是这一步没做好,导致最后得到的结果基本很相近,最后这个模型被我放弃了。我在做这个数据集的时候一开始也遇到这个问题,后来在归一化时把样本都设置在同个空间范畴,就解决问题了)。
数据集提供了大概45组数据,所以我们可以使用multi-task learning探索各组数据之间的关联性,这部分我还没具体了解,就不贻笑大方了。