Keras实现LSTM预测时间序列(一)

最近在一些文章中看到用LSTM预测时间序列,通过使用网络上的数据并且借鉴网上的代码,对LSTM模型的搭建有了一定的了解。本篇文章使用的数据数据来自用Python预测「周期性时间序列」的正确姿势

在数据中,部分时间的数据值是缺失的,上方链接中的作者通过取平均值的方法填补了缺失数据,折线图如下:

在折线图中,能看到在开头的数据和其它数据差异较大,由于数据是周期性的,于是对开头“不合群”的数据做处理,处理方式是使用后6个相同时间点的数据取平均值,代码如下:

def api_dataset():
    with open('api_access_fix.csv',encoding = 'utf-8-sig') as f:
        reader = csv.reader(f)
        dataset = []
        for item in reader:
            try:
                dataset.append([int(float(item[2]))])
            except:
                pass
    for i in range(len(dataset)):
        if dataset[i][0]<=500 and i < 1440:
            dataset[i][0] = int(sum([dataset[i+x*1440][0] for x in range(1,7)])/6)
    return np.array(dataset)

当然,本文所使用的处理方式还是比较草率的,未经过深入的调研与分析,处理后的折线图如下:

数据归一化函数,便于模型学习:

# 归一化函数
def sc_fit_transform(nDlist):
    # 将所有数据归一化为0-1的范围
    sc = MinMaxScaler(feature_range=(0, 1))
    dataset_transform = sc.fit_transform(X=nDlist)
    # 归一化后的数据
    return sc, np.array(dataset_transform)

准备训练数据,将前6天的数据作为训练,即 training_num = 8640:

# 需要之前60次的访问数据来预测下一次的数据,
timestep = 60
# 训练数据的大小
training_num = 8640
# 迭代训练10次
epoch = 10
# 每次取数据数量
batch_size = 100
###############################################################################
listDataset = api_dataset()
# print(listDataset.shape)
# 生成训练集访问数据集
xTrainDataset = listDataset[0:training_num]
# 每次的下次访问次数是训练结果
yTrainDataset = listDataset[1:training_num+1]

# 原始数据归一化
scTrainDataseX, xTrainDataset  = sc_fit_transform(xTrainDataset)
scTrainDataseY, yTrainDataset  = sc_fit_transform(yTrainDataset)

将数据处理为LSTM输入的形式:

# 生成lstm模型需要的训练集数据
xTrain = []
for i in range(timestep, training_num):
    xTrain.append(xTrainDataset[i-timestep : i])
xTrain = np.array(xTrain)
# print(xTrain.shape)

yTrain = []
for i in range(timestep, training_num):
    yTrain.append(yTrainDataset[i])
yTrain = np.array(yTrain)
# print(yTrain.shape)

构建网络:

# 构建网络,使用的是序贯模型
model = Sequential()
model.add(LSTM(units=128, input_shape=[xTrain.shape[1], 1]))
model.add(Dense(1))
# 进行配置
model.compile(optimizer='adam',
              loss='mean_squared_error',
              metrics=['accuracy'])
model.fit(x=xTrain, y=yTrain, epochs=epoch, batch_size=batch_size)
# 保存模型
model.save('my_model.h5')

准备测试数据:

# 此步骤与准备训练数据基本一致
xTestDataset = listDataset[training_num:10080-2]
scTesDatasetX, xTestDataset  = sc_fit_transform(xTestDataset)

yTestDataset = listDataset[training_num+1:10080-1]
scTestDataseY, yTestDataset  = sc_fit_transform(yTestDataset)
# 生成lstm模型需要的训练集数据和
xTest = []
for i in range(timestep, len(xTestDataset)):
    xTest.append(xTestDataset[i-timestep : i])
xTest = np.array(xTest)
# print(xTest.shape)
yTest = []
for i in range(timestep, len(xTestDataset)):
    yTest.append(yTestDataset[i])
# 反归一化
yTest = scTestDataseY.inverse_transform(X= yTest)
# print(yTest.shape)
# print(yTest)

进行预测:

# 进行预测
yPredictes = model.predict(x=xTest)
# 反归一化
yPredictes = scTestDataseY.inverse_transform(X=yPredictes)
# print(yPredictes.shape)
# print(yPredictes)

结果评价:

# 评估标准: mae, rmse, r2_score
mae = mean_absolute_error(yTest, yPredictes)
rmse = mean_squared_error(yTest, yPredictes, squared=False)
r2 = r2_score(yTest, yPredictes)
# print(mae, rmse, r2)
# 45.70792188492153 74.77525176850149 0.9880226807229917

完整代码如下:

import csv
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import MinMaxScaler
from keras.models import Sequential
from keras.layers import Dense, LSTM
from sklearn.metrics import mean_absolute_error
from sklearn.metrics import mean_squared_error
from sklearn.metrics import r2_score

def api_dataset():
    with open('api_access_fix.csv',encoding = 'utf-8-sig') as f:
        reader = csv.reader(f)
        dataset = []
        for item in reader:
            try:
                dataset.append([int(float(item[2]))])
            except:
                pass
    for i in range(len(dataset)):
        if dataset[i][0]<=500 and i < 1440:
            dataset[i][0] = int(sum([dataset[i+x*1440][0] for x in range(1,7)])/6)
    return np.array(dataset)

# 归一化函数
def sc_fit_transform(nDlist):
    # 将所有数据归一化为0-1的范围
    sc = MinMaxScaler(feature_range=(0, 1))
    dataset_transform = sc.fit_transform(X=nDlist)
    # 归一化后的数据
    return sc, np.array(dataset_transform)

###############################################################################
# 需要之前60次的访问数据来预测下一次的数据,
timestep = 60
# 训练数据的大小
training_num = 8640
# 迭代训练10次
epoch = 10
# 每次取数据数量
batch_size = 100
###############################################################################
listDataset = api_dataset()
# print(listDataset.shape)
# 生成训练集访问数据集
xTrainDataset = listDataset[0:training_num]
# 每次的下次访问次数是训练结果
yTrainDataset = listDataset[1:training_num+1]

# 原始数据归一化
scTrainDataseX, xTrainDataset  = sc_fit_transform(xTrainDataset)
scTrainDataseY, yTrainDataset  = sc_fit_transform(yTrainDataset)

###############################################################################
# 生成lstm模型需要的训练集数据
xTrain = []
for i in range(timestep, training_num):
    xTrain.append(xTrainDataset[i-timestep : i])
xTrain = np.array(xTrain)
# print(xTrain.shape)

yTrain = []
for i in range(timestep, training_num):
    yTrain.append(yTrainDataset[i])
yTrain = np.array(yTrain)
# print(yTrain.shape)
###############################################################################
# 构建网络,使用的是序贯模型
model = Sequential()
#return_sequences=True返回的是全部输出,LSTM做第一层时,需要指定输入shape
model.add(LSTM(units=128, input_shape=[xTrain.shape[1], 1]))
model.add(Dense(1))
# 进行配置
model.compile(optimizer='adam',
              loss='mean_squared_error',
              metrics=['accuracy'])
model.fit(x=xTrain, y=yTrain, epochs=epoch, batch_size=batch_size)
model.save('my_model.h5')
###############################################################################
xTestDataset = listDataset[training_num:10080-2]
scTesDatasetX, xTestDataset  = sc_fit_transform(xTestDataset)

yTestDataset = listDataset[training_num+1:10080-1]
scTestDataseY, yTestDataset  = sc_fit_transform(yTestDataset)
# 生成lstm模型需要的训练集数据
xTest = []
for i in range(timestep, len(xTestDataset)):
    xTest.append(xTestDataset[i-timestep : i])
xTest = np.array(xTest)
print(xTest.shape)
yTest = []
for i in range(timestep, len(xTestDataset)):
    yTest.append(yTestDataset[i])
# 反归一化
yTest = scTestDataseY.inverse_transform(X= yTest)
print(yTest.shape)
print(yTest)
###############################################################################
# 进行预测
yPredictes = model.predict(x=xTest)
# 反归一化
yPredictes = scTestDataseY.inverse_transform(X=yPredictes)
print(yPredictes.shape)
print(yPredictes)
############################################################################### 
#对比结果,绘制数据图表,红色是真实数据,蓝色是预测数据
plt.plot(yTest, color='red', label='Real')
plt.plot(yPredictes, color='blue', label='Predict')
plt.title(label='Prediction')
plt.xlabel(xlabel='Time')
plt.ylabel(ylabel='Api_access_num')
plt.legend()
plt.show()

# 评估标准: mae, rmse, r2_score
mae = mean_absolute_error(yTest, yPredictes)
rmse = mean_squared_error(yTest, yPredictes, squared=False)
r2 = r2_score(yTest, yPredictes)
print(mae, rmse, r2)
# 72.02636248234026 98.38626354602893 0.9791679689516253
# 45.70792188492153 74.77525176850149 0.9880226807229917

测试集和预测数据折线图:

最终得分,选择了MAE、RMSE 和 R2三个指标,得分如下:
mae:45.70792188492153
rmse:74.77525176850149
r2:0.9880226807229917

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352