说到时间序列预测,我想一定首先想到RNN,然后想到LSTM,LSTM原理就不说了,网上有很多相关文章。
下面使用tensorflow2.0来实现预测
不得不说tensorflow2.0 太香了,太简单了,真的是有手就行
在tensorflow中只需要调用已经tensorflow的LSTM模块就行了,比如下面的代码
from tensorflow.keras.layers import Dense,LSTM,Dropout
model = tf.keras.Sequential([
LSTM(80, return_sequences=True),
Dropout(0.2),
LSTM(80),
Dropout(0.2),
Dense(1)
])
model.compile(optimizer='adam',
loss='mse',)
这样就创建了一个2层LSTM,每层80个神经元的;同时添加了Droopout函数防止过拟合;使用adam激活函数;使用mse作为损失误差的神经网络。真的炒鸡简单。
主要问题是数据的处理,要做时间序列预测,原理应该是使用前n个时间去预测下一个时间,也就是所模型训练的数据应该是下面这个图这样的数据
所以处理数据才是困难的地方。
下面我使用的数据是在上一个文章中提到的英国站点数据。其他的数据也是大同小异。
百度网盘: https://pan.baidu.com/s/19vKN2eZZPbOg36YEWts4aQ
密码 4uh7
在导入数据时,不知道为什么如果有标红的这一列,就会提示错误,所以我把这个数据直接删了,这列数据对预测也没有影响
然后通过下面代码就可以得到一个包含,日期、流量的的数据
f = pd.read_csv('..\Desktop\AE86.csv')
# 从新设置列标
def set_columns():
columns = []
for i in f.loc[2]:
columns.append(i.strip())
return columns
f.columns = set_columns()
f.drop([0,1,2], inplace = True)
# data 包含要操作的列
data = pd.DataFrame()
# 想留下哪一行数据,就在这里添加到data中
data['datetime'] = f['Local Date']+' '+f['Local Time']
data['total_flow'] = f['Total Carriageway Flow']
# data['speed'] = f['Speed Value'] 速度本文没用到
data['datetime'] = pd.to_datetime(data['datetime'])
data['month'] = data['datetime'].apply(lambda date: date.month)
data['day'] = data['datetime'].apply(lambda date: date.day)
data['hour'] = data['datetime'].apply(lambda date:date.hour)
data['minute'] = data['datetime'].apply(lambda date: date.minute)
# 数据转格式
data['total_flow'] = np.array(data['total_flow']).astype(np.float64)
处理后的数据如下
之后就是划分训练集和测试集,归一化
# 一月第25天第一个时间的索引值
d25 = data.query('day==25').index[0]
# 训练集 2211个数据,2018年一月前三周
train_set = data.iloc[:d25,1:2]
# 检测集 669个数据,2018年最后一周
test_set = data.iloc[d25:,1:2]
# 归一化
sc = MinMaxScaler(feature_range=(0, 1))
train_set_sc = sc.fit_transform(train_set)
test_set_sc = sc.transform(test_set)
下面就是创建LSTM的输入数据,以time_step=5为预测间隔,即使用前5个时间段,预测下一个时间段
time_step = 5
# 按照time_step划分时间步长
x_train = []
y_train = []
x_test = []
y_test = []
for i in range(time_step, len(train_set_sc)):
x_train.append(train_set_sc[i - time_step:i])
y_train.append(train_set_sc[i:i + 1])
for i in range(time_step, len(test_set_sc)):
x_test.append(test_set_sc[i - time_step:i])
y_test.append(test_set_sc[i:i + 1])
x_test, y_test = np.array(x_test), np.array(y_test)
# 随机化,这部分可以不要
np.random.seed(7)
np.random.shuffle(x_train)
np.random.seed(7)
np.random.shuffle(y_train)
tf.random.set_seed(7)
# 转为array格式
x_train, y_train = np.array(x_train), np.array(y_train)
x_test, y_test = np.array(x_test), np.array(y_test)
x_train = np.reshape(x_train, (x_train.shape[0], time_step, 1))
x_test = np.reshape(x_test, (x_test.shape[0], time_step, 1))
下面就是构建模型,预测,误差分析,可视化之类的了
总体代码如下
import tensorflow as tf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras.layers import Dense,LSTM,Dropout,Flatten
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import mean_squared_error, mean_absolute_error
import math
from matplotlib.font_manager import FontProperties # 画图时可以使用中文
f = pd.read_csv('..\Desktop\AE86.csv')
# 从新设置列标
def set_columns():
columns = []
for i in f.loc[2]:
columns.append(i.strip())
return columns
f.columns = set_columns()
f.drop([0,1,2], inplace = True)
# data 包含要操作的列
data = pd.DataFrame()
data['datetime'] = f['Local Date']+' '+f['Local Time']
data['total_flow'] = f['Total Carriageway Flow']
# data['speed'] = f['Speed Value']
data['datetime'] = pd.to_datetime(data['datetime'])
data['month'] = data['datetime'].apply(lambda date: date.month)
data['day'] = data['datetime'].apply(lambda date: date.day)
data['hour'] = data['datetime'].apply(lambda date:date.hour)
data['minute'] = data['datetime'].apply(lambda date: date.minute)
# 数据转格式
data['total_flow'] = np.array(data['total_flow']).astype(np.float64)
# 一月第25天第一个时间的索引值
d25 = data.query('day==25').index[0]
# 训练集 2211个数据,2018年一月前三周
train_set = data.iloc[:d25,1:2]
# 检测集 669个数据,2018年最后一周
test_set = data.iloc[d25:,1:2]
# 归一化
sc = MinMaxScaler(feature_range=(0, 1))
train_set_sc = sc.fit_transform(train_set)
test_set_sc = sc.transform(test_set)
# 按照time_step划分时间步长
time_step = 5
x_train = []
y_train = []
x_test = []
y_test = []
for i in range(time_step, len(train_set_sc)):
x_train.append(train_set_sc[i - time_step:i])
y_train.append(train_set_sc[i:i + 1])
for i in range(time_step, len(test_set_sc)):
x_test.append(test_set_sc[i - time_step:i])
y_test.append(test_set_sc[i:i + 1])
x_test, y_test = np.array(x_test), np.array(y_test)
# 随机化,这部分可以不要
np.random.seed(7)
np.random.shuffle(x_train)
np.random.seed(7)
np.random.shuffle(y_train)
tf.random.set_seed(7)
# 转为array格式
x_train, y_train = np.array(x_train), np.array(y_train)
x_test, y_test = np.array(x_test), np.array(y_test)
x_train = np.reshape(x_train, (x_train.shape[0], time_step, 1))
x_test = np.reshape(x_test, (x_test.shape[0], time_step, 1))
# LSTM模型
model = tf.keras.Sequential([
LSTM(80, return_sequences=True),
Dropout(0.2),
LSTM(80),
Dropout(0.2),
Dense(1)
])
model.compile(optimizer='adam',
loss='mse',)
# 训练模型, 其中epochs,batch_size 可以自己更改
history = model.fit(x_train, y_train,
epochs=5,
validation_data=(x_test, y_test))
# 模型预测
pre_flow = model.predict(x_test)
# 反归一化
pre_flow = sc.inverse_transform(pre_flow)
real_flow = sc.inverse_transform(y_test.reshape(y_test.shape[0], 1))
# 计算误差
mse = mean_squared_error(pre_flow, real_flow)
rmse = math.sqrt(mean_squared_error(pre_flow, real_flow))
mae = mean_absolute_error(pre_flow, real_flow)
print('均方误差---', mse)
print('均方根误差---', rmse)
print('平均绝对误差--', mae)
# 画出预测结果图
font_set = FontProperties(fname=r"C:\Windows\Fonts\simsun.ttc", size=15) # 中文字体使用宋体,15号
plt.figure(figsize=(15,10))
plt.plot(real_flow, label='Real_Flow', color='r', )
plt.plot(pre_flow, label='Pre_Flow')
plt.xlabel('测试序列', fontproperties=font_set)
plt.ylabel('交通流量/辆', fontproperties=font_set)
plt.legend()
# 预测储存图片
# plt.savefig('...\Desktop\123.jpg')
上面代码是最简单的,只是用流量,同时单一节点进行流量预测。
也可以使用速度,占有率等信息,加入到模型中对流量进行预测。真要认真做起来是比较难的,但是如果只是应付应付,提供一个思虑:
可以把另外几种特征也按照time_step=5,进行划分,直接传入到模型中,只不过在模型的最后一层加一个Flatten层(将所有数据拉直成一维),这样就可以大大方方的说”本文考虑了,流量、速度、车道占有率等多种因数,相对于以前文章具有重大改进“