关于RNN可以参考这篇文章博文地址
背景
时间序列是一个比较场景的问题,
获取数据
从UIC下载学习库下载地址下载其中的csv文件

其各个数据特征如下

处理数据
先导入需要用到的模块
这里用到了keras的API关于keras的使用可以看官方教程点击前往
from tensorflow import keras
from tensorflow.keras import layers
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
导入数据
data = pd.read_csv('D:\machine\project/testbeijinpm2.5/PRSA_data_2010.1.1-2014.12.31.csv')
查看下列信息看是否导入成功
data.columns

查看数据情况可以用data.head在jupyter会显示前5行
data.head()

pm2.5就是我们需要的label通过下面操作查看是否有空的数据
data['pm2.5'].isna().sum()
可以看到有2067行数据包含空的pm2.5

对于这些空的数据,如果采取删除的动作,那样会导致数据不连续,可能对于训练的结果产生影响,这里采用的处理方式是讲空值处理成它最近的点的值,这样可以保证数据的连续性和前后关联性,有不至于有太大误差
运行如下操作处理
data=data.iloc[24:].fillna(method='ffill')
可以观察到时间的年月日小时分布在不同列
它们应该分布在同一列属于同一个特征
这里导入python的时间模块进行处理
import datetime
将数据 中的year,month,day,hour整合成一条数据赋值给data['time']
#时间组合
data['time']=data.apply(lambda x: datetime.datetime(year=x['year'],
month=x['month'],
day=x['day'],
hour=x['hour']),
axis=1
)
删除原本的year,month,day,no列
data.drop(columns=['year','month','day','hour','No'],inplace=True)
查看下数据的情况

设置成按照时间索引
#设置成按时间索引
data=data.set_index('time')
从数据中可以看到cbwd不是一些数值标量,这需要对它进行转换,先查看cbwd有哪些内容
#找到cbwd有哪些内容
data.cbwd.unique()

将这几个标识编码
#把风向编码化
data=data.join(pd.get_dummies(data.cbwd))
编码化完成后删除cbwd列
del data['cbwd']
查看下表格,可以看到4个标识已经编码化了
data.tail()

可以下面代码查看最后1000次pm2.5变化情况
data['pm2.5'][-1000:].plot()

最后1000次温度变化情况
data['TEMP'][-1000:].plot()

可以通过查看列数查看特征数量
#特征数量
len(data.columns)

时间序列预测是观测过去多久的值,来预测未来多久的值,因此这里定义两个变量seq_length代表过去5×24小时的数据,来预测未来24小时的数据。
seq_length = 5*24
delay = 24
然后我们就可以采用数据,以seq_length和delay来采样
#采样的数据
data_ = []
for t in range(len(data) - seq_length - delay):
data_.append(data.iloc[t:t + seq_length + delay ])
查看下采样后的数据形状
data_[0].shape
可以看到144个样例,11个特征

将采样的数据转换成np的array
data_ = np.array([df.values for df in data_])
data_.shape

洗牌数据
np.random.shuffle(data_)
特征切片
#特征切片
x = data_[:, :5*24, :]
# label
y = data_[:,-1, 0]
查看下x,y的数据形状
x.shape
y.shape

划分80%数据用于训练集 20%用于测试集合
split_b = data_.shape[0]*0.8
split_b = int(split_b)
train_x = x[ :split_b]
train_y = y[ :split_b]
test_x = x[split_b: ]
test_y = y[split_b: ]
数据归一化,让不同特征规范统一范围,有效利用神经网络的训练避免引起误差。
#计算均值
#数据归一化,
mean = test_x.mean(axis = 0)
std = train_x.std(axis = 0)
train_x = (train_x - mean)/std
test_x = (test_x - mean) / std
搭建神经网络
全链接神经网络方式
batch_size = 128 #每次训练128个数据
model = keras.Sequential()
model.add(layers.Flatten(input_shape=(train_x.shape[1:])))
model.add(layers.Dense(32,activation='relu'))
model.add(layers.Dense(1))
model.compile(
optimizer='adam', #优化算法
loss = 'mse', #均方差
metrics= ['mae'] #平均绝对误差
)
history = model.fit(train_x, train_y,
batch_size =batch_size,
epochs = 50,
validation_data=(test_x,test_y)
)

#画图看情况
import matplotlib.pyplot as plt
%matplotlib inline
plt.plot(history.epoch,history.history['mean_absolute_error'],c='r') #训练数据
plt.plot(history.epoch,history.history['val_mean_absolute_error'],c='g') #测试数据

LSTM方式
在训练过程中可以看到速度明显要比全连接的方式要好慢上许多,而训练的效果也比全链接网络的要要很多。
train_x.shape #第一维度大小,第二维度观测次数,第三维度每次观测的特征
这只有一层的LSTM
model = keras.Sequential()
model.add(layers.LSTM(32,input_shape=(120,11)))
model.add(layers.Dense(1))
编译选择模型的优化方式
model.compile(
optimizer='adam', #优化算法
loss = 'mse', #均方差
metrics= ['mae'] #平均绝对误差
)

history = model.fit(train_x, train_y,
batch_size =batch_size,
epochs = 200,
validation_data=(test_x,test_y)
)
plt.plot(history.epoch,history.history.get('mean_absolute_error'),'y',label='Training loss')
plt.plot(history.epoch,history.history.get('val_mean_absolute_error'),'b',label= 'Test loss')
plt.legend()
LSTM层优化
添加多层优化拟合能力,需要添加
return_sequences,最后一层不需要
可以观察到训练速度更加缓慢,但训练效果却是跨越式的进展。
model = keras.Sequential()
model.add(layers.LSTM(32,input_shape=(120,11),return_sequences=True))
model.add(layers.LSTM(32,return_sequences=True))
model.add(layers.LSTM(32,return_sequences=True))
model.add(layers.LSTM(32))
model.add(layers.Dense(1))
#在训练过程中降低学习速率,加快训练速度同时增加训练的效果
#连续的3个val_LOSS没有降低则降低学习速率0.3,最小的学习速率为0.000001
lr_reduce = keras.callbacks.ReduceLROnPlateau('val_loss',patience=3,factor=0.3,min_lr=0.00001)
model.compile(
optimizer='adam', #优化算法
loss = 'mse', #均方差
metrics= ['mae'] #平均绝对误差
)
history = model.fit(train_x, train_y,
batch_size =batch_size,
epochs = 200,
callbacks = [lr_reduce],
validation_data=(test_x,test_y)
)
plt.plot(history.epoch,history.history.get('mean_absolute_error'),'y',label='Training loss')
plt.plot(history.epoch,history.history.get('val_mean_absolute_error'),'b',label= 'Test loss')
plt.legend()
可以很明显的看到效果的提升


网友评论