一、简介

  上一篇中我们较为详细地铺垫了关于RNN及其变种LSTM的一些基本知识,也提到了LSTM在时间序列预测上优越的性能,本篇就将对如何利用tensorflow,在实际时间序列预测任务中搭建模型来完成任务,若你对RNN及LSTM不甚了解,请移步上一篇数据科学学习手札39;

二、数据说明及预处理

2.1 数据说明

  我们本文使用到的第一个数据来自R中自带的数据集AirPassengers,这个数据集记录了Box & Jenkins航空公司1949-1960年共144个观测值(对应每个月的国际航线乘客数),是一个经典的时间序列数据集,你可以从R中导出或去uci的网站下载;

2.2 数据预处理

  我们都知道,RNN最终经由tanh激活后输出的值位于[-1,1]内,若为分类任务则可以经由softmax进行处理,但我们这里要做的是对连续数值的预测,因此需要的输出即为tanh的输出,因此需要将原始数据进行尺度放缩,而尺度放缩的方法主要有两种,一种是极差规格化,即将原数据通过下面的公式无损地映射到[0,1]之间:

  另一种是标准化,将原数据通过下面的公式转换为均值为0,标准差为1的服从正态分布的随机变量:

我们这里选择标准化(选极差规格化也可以,读者们可以自己尝试,我懒得写了。。。);

三、模型建立及训练

数据预处理部分:

  这一部分,我们完成原始数据的导入和预处理,为了配合之后的采样过程,这里选择列表作为预处理后原始数据的储存对象:

import numpy as np
import tensorflow as tf
from tensorflow.contrib import rnn
import matplotlib.pyplot as plt
from tensorflow.contrib.learn.python.learn.estimators.estimator import SKCompat
from matplotlib import style
import pandas as pd '''读入原始数据并转为list'''
path = 'C:\\Users\\windows\\Desktop\\' data = pd.read_csv(path+'AirPassenger.csv') data = data.iloc[:,0].tolist() '''自定义数据尺度缩放函数'''
def data_processing(raw_data,scale=True):
if scale == True:
return (raw_data-np.mean(raw_data))/np.std(raw_data)#标准化
else:
return (raw_data-np.min(raw_data))/(np.max(raw_data)-np.min(raw_data))#极差规格化

数据观察部分:

  这一部分,我们需要初步观察到原数据的一些基本特性,以便确定之后的一些参数,如LSTM单元内一个时间步内的递归次数:

'''观察数据'''

'''设置绘图风格'''
style.use('ggplot') plt.plot(data)

可以看出,我们的数据集具有很明显的周期性与上升趋势,下面就基于此,对LSTM的一些基本参数进行设置;

LSTM基本参数设置:

  这里我们需要设置的参数有隐层层数,因为数据集比较简单,我们设置为1;隐层神经元个数,这里我随意设置为40个;时间步中递归次数,这里根据上面观察的结论,设置为12;训练轮数,这里也是随意设置的不宜过少,2000;训练批尺寸,这里随意设置为20,表示每一轮从训练集中抽出20组序列样本进行训练:

'''设置隐层神经元个数'''
HIDDEN_SIZE = 40
'''设置隐层层数'''
NUM_LAYERS = 1
'''设置一个时间步中折叠的递归步数'''
TIMESTEPS = 12
'''设置训练轮数'''
TRAINING_STEPS = 2000
'''设置训练批尺寸'''
BATCH_SIZE = 20

生成训练集数据:

  这里为了将原始的单变量时序数据处理成LSTM可以接受的数据类型(有X输入,有真实标签Y),我们通过自编函数,将原数据(144个)从第一个开始,依次采样长度为12的连续序列作为一个时间步内部的输入序列X,并采样其之后一期的数据作为一个Y,具体过程如下:

'''样本数据生成函数'''
def generate_data(seq):
X = []#初始化输入序列X
Y= []#初始化输出序列Y
'''生成连贯的时间序列类型样本集,每一个X内的一行对应指定步长的输入序列,Y内的每一行对应比X滞后一期的目标数值'''
for i in range(len(seq) - TIMESTEPS - 1):
X.append([seq[i:i + TIMESTEPS]])#从输入序列第一期出发,等步长连续不间断采样
Y.append([seq[i + TIMESTEPS]])#对应每个X序列的滞后一期序列值
return np.array(X, dtype=np.float32), np.array(Y, dtype=np.float32)

构造LSTM模型主体

'''定义LSTM cell组件,该组件将在训练过程中被不断更新参数'''
def LstmCell():
lstm_cell = rnn.BasicLSTMCell(HIDDEN_SIZE, state_is_tuple=True)#
return lstm_cell '''定义LSTM模型'''
def lstm_model(X, y):
'''以前面定义的LSTM cell为基础定义多层堆叠的LSTM,我们这里只有1层'''
cell = rnn.MultiRNNCell([LstmCell() for _ in range(NUM_LAYERS)]) '''将已经堆叠起的LSTM单元转化成动态的可在训练过程中更新的LSTM单元'''
output, _ = tf.nn.dynamic_rnn(cell, X, dtype=tf.float32) '''根据预定义的每层神经元个数来生成隐层每个单元'''
output = tf.reshape(output, [-1, HIDDEN_SIZE]) '''通过无激活函数的全连接层计算线性回归,并将数据压缩成一维数组结构'''
predictions = tf.contrib.layers.fully_connected(output, 1, None) '''统一预测值与真实值的形状'''
labels = tf.reshape(y, [-1])
predictions = tf.reshape(predictions, [-1]) '''定义损失函数,这里为正常的均方误差'''
loss = tf.losses.mean_squared_error(predictions, labels) '''定义优化器各参数'''
train_op = tf.contrib.layers.optimize_loss(loss,
tf.contrib.framework.get_global_step(),
optimizer='Adagrad',
learning_rate=0.6)
'''返回预测值、损失函数及优化器'''
return predictions, loss, train_op '''载入tf中仿sklearn训练方式的模块'''
learn = tf.contrib.learn '''初始化我们的LSTM模型,并保存到工作目录下以方便进行增量学习'''
regressor = SKCompat(learn.Estimator(model_fn=lstm_model, model_dir='Models/model_2'))

训练部分:

'''对原数据进行尺度缩放'''
data = data_processing(data) '''将所有样本来作为训练样本'''
train_X, train_y = generate_data(data) '''将所有样本作为测试样本'''
test_X, test_y = generate_data(data) '''以仿sklearn的形式训练模型,这里指定了训练批尺寸和训练轮数'''
regressor.fit(train_X, train_y, batch_size=BATCH_SIZE, steps=TRAINING_STEPS)

评价部分:

  这里我们将原数据(尺度缩放之后的)feed进我们已经训练好的模型中,得到对应的预测值:

'''利用已训练好的LSTM模型,来生成对应测试集的所有预测值'''
predicted = np.array([pred for pred in regressor.predict(test_X)]) '''绘制反标准化之前的真实值与预测值对比图'''
plt.plot(predicted, label='预测值')
plt.plot(test_y, label='真实值')
plt.title('反标准化之前')
plt.legend()
plt.show()

可以看到,预测值与真实值非常的吻合,但这并不是我们需要的形式,我们需要的是反标准化后的真实数值,下面进行相关操作;

'''自定义反标准化函数'''
def scale_inv(raw_data,scale=True):
'''读入原始数据并转为list'''
path = 'C:\\Users\\windows\\Desktop\\' data = pd.read_csv(path + 'AirPassenger.csv') data = data.iloc[:, 0].tolist() if scale == True:
return raw_data*np.std(data)+np.mean(data)
else:
return raw_data*(np.max(data)-np.min(data))+np.min(data) '''绘制反标准化之前的真实值与预测值对比图'''
plt.figure()
plt.plot(scale_inv(predicted), label='预测值')
plt.plot(scale_inv(test_y), label='真实值')
plt.title('反标准化之后')
plt.legend()
plt.show()

实际使用中,若想利用已训练好的LSTM模型来预测未出现的下一期,则直接输入最后12步(这里是12步)即可得到未来的一步预测值,若想要获得更远更多期的预测值,则可以逐步将预测值积累起来,相当于用预测值当作真实发生的值进行预测,这样的坏处是越往后可能越不准,以上这个过程的完整代码如下:

import numpy as np
import tensorflow as tf
from tensorflow.contrib import rnn
import matplotlib.pyplot as plt
from tensorflow.contrib.learn.python.learn.estimators.estimator import SKCompat
from matplotlib import style
import pandas as pd '''读入原始数据并转为list'''
path = 'C:\\Users\\windows\\Desktop\\' data = pd.read_csv(path+'AirPassenger.csv') data = data.iloc[:,0].tolist() '''自定义数据尺度缩放函数'''
def data_processing(raw_data,scale=True):
if scale == True:
return (raw_data-np.mean(raw_data))/np.std(raw_data)#标准化
else:
return (raw_data-np.min(raw_data))/(np.max(raw_data)-np.min(raw_data))#极差规格化 '''观察数据''' '''设置绘图风格'''
style.use('ggplot') plt.plot(data) '''设置隐层神经元个数'''
HIDDEN_SIZE = 40
'''设置隐层层数'''
NUM_LAYERS = 1
'''设置一个时间步中折叠的递归步数'''
TIMESTEPS = 12
'''设置训练轮数'''
TRAINING_STEPS = 10000
'''设置训练批尺寸'''
BATCH_SIZE = 20 '''样本数据生成函数'''
def generate_data(seq):
X = []#初始化输入序列X
Y= []#初始化输出序列Y
'''生成连贯的时间序列类型样本集,每一个X内的一行对应指定步长的输入序列,Y内的每一行对应比X滞后一期的目标数值'''
for i in range(len(seq) - TIMESTEPS - 1):
X.append([seq[i:i + TIMESTEPS]])#从输入序列第一期出发,等步长连续不间断采样
Y.append([seq[i + TIMESTEPS]])#对应每个X序列的滞后一期序列值
return np.array(X, dtype=np.float32), np.array(Y, dtype=np.float32) '''定义LSTM cell组件,该组件将在训练过程中被不断更新参数'''
def LstmCell():
lstm_cell = rnn.BasicLSTMCell(HIDDEN_SIZE, state_is_tuple=True)#
return lstm_cell '''定义LSTM模型'''
def lstm_model(X, y):
'''以前面定义的LSTM cell为基础定义多层堆叠的LSTM,我们这里只有1层'''
cell = rnn.MultiRNNCell([LstmCell() for _ in range(NUM_LAYERS)]) '''将已经堆叠起的LSTM单元转化成动态的可在训练过程中更新的LSTM单元'''
output, _ = tf.nn.dynamic_rnn(cell, X, dtype=tf.float32) '''根据预定义的每层神经元个数来生成隐层每个单元'''
output = tf.reshape(output, [-1, HIDDEN_SIZE]) '''通过无激活函数的全连接层计算线性回归,并将数据压缩成一维数组结构'''
predictions = tf.contrib.layers.fully_connected(output, 1, None) '''统一预测值与真实值的形状'''
labels = tf.reshape(y, [-1])
predictions = tf.reshape(predictions, [-1]) '''定义损失函数,这里为正常的均方误差'''
loss = tf.losses.mean_squared_error(predictions, labels) '''定义优化器各参数'''
train_op = tf.contrib.layers.optimize_loss(loss,
tf.contrib.framework.get_global_step(),
optimizer='Adagrad',
learning_rate=0.6)
'''返回预测值、损失函数及优化器'''
return predictions, loss, train_op '''载入tf中仿sklearn训练方式的模块'''
learn = tf.contrib.learn '''初始化我们的LSTM模型,并保存到工作目录下以方便进行增量学习'''
regressor = SKCompat(learn.Estimator(model_fn=lstm_model, model_dir='Models/model_2')) '''对原数据进行尺度缩放'''
data = data_processing(data) '''将所有样本来作为训练样本'''
train_X, train_y = generate_data(data) '''将所有样本作为测试样本'''
test_X, test_y = generate_data(data) '''以仿sklearn的形式训练模型,这里指定了训练批尺寸和训练轮数'''
regressor.fit(train_X, train_y, batch_size=BATCH_SIZE, steps=TRAINING_STEPS) '''利用已训练好的LSTM模型,来生成对应测试集的所有预测值'''
predicted = np.array([pred for pred in regressor.predict(test_X)]) '''绘制反标准化之前的真实值与预测值对比图'''
plt.figure()
plt.plot(predicted, label='预测值')
plt.plot(test_y, label='真实值')
plt.title('反标准化之前')
plt.legend()
plt.show() '''自定义反标准化函数'''
def scale_inv(raw_data,scale=True):
'''读入原始数据并转为list'''
path = 'C:\\Users\\windows\\Desktop\\' data = pd.read_csv(path + 'AirPassenger.csv') data = data.iloc[:, 0].tolist() if scale == True:
return raw_data*np.std(data)+np.mean(data)
else:
return raw_data*(np.max(data)-np.min(data))+np.min(data) '''绘制反标准化之前的真实值与预测值对比图'''
plt.figure()
plt.plot(scale_inv(predicted), label='预测值')
plt.plot(scale_inv(test_y), label='真实值')
plt.title('反标准化之后')
plt.legend()
plt.show()

  以上就是本篇文章的全部内容,如有笔误或混淆不清之处,望指出。

(数据科学学习手札40)tensorflow实现LSTM时间序列预测的更多相关文章

  1. (数据科学学习手札36)tensorflow实现MLP

    一.简介 我们在前面的数据科学学习手札34中也介绍过,作为最典型的神经网络,多层感知机(MLP)结构简单且规则,并且在隐层设计的足够完善时,可以拟合任意连续函数,而除了利用前面介绍的sklearn.n ...

  2. (数据科学学习手札44)在Keras中训练多层感知机

    一.简介 Keras是有着自主的一套前端控制语法,后端基于tensorflow和theano的深度学习框架,因为其搭建神经网络简单快捷明了的语法风格,可以帮助使用者更快捷的搭建自己的神经网络,堪称深度 ...

  3. (数据科学学习手札55)利用ggthemr来美化ggplot2图像

    一.简介 R中的ggplot2是一个非常强大灵活的数据可视化包,熟悉其绘图规则后便可以自由地生成各种可视化图像,但其默认的色彩和样式在很多时候难免有些过于朴素,本文将要介绍的ggthemr包专门针对原 ...

  4. (数据科学学习手札50)基于Python的网络数据采集-selenium篇(上)

    一.简介 接着几个月之前的(数据科学学习手札31)基于Python的网络数据采集(初级篇),在那篇文章中,我们介绍了关于网络爬虫的基础知识(基本的请求库,基本的解析库,CSS,正则表达式等),在那篇文 ...

  5. (数据科学学习手札49)Scala中的模式匹配

    一.简介 Scala中的模式匹配类似Java中的switch语句,且更加稳健,本文就将针对Scala中模式匹配的一些基本实例进行介绍: 二.Scala中的模式匹配 2.1 基本格式 Scala中模式匹 ...

  6. (数据科学学习手札47)基于Python的网络数据采集实战(2)

    一.简介 马上大四了,最近在暑期实习,在数据挖掘的主业之外,也帮助同事做了很多网络数据采集的内容,接下来的数篇文章就将一一罗列出来,来续写几个月前开的这个网络数据采集实战的坑. 二.马蜂窝评论数据采集 ...

  7. (数据科学学习手札42)folium进阶内容介绍

    一.简介 在上一篇(数据科学学习手札41)中我们了解了folium的基础内容,实际上folium在地理信息可视化上的真正过人之处在于其绘制图像的高度可定制化上,本文就将基于folium官方文档中的一些 ...

  8. (数据科学学习手札32)Python中re模块的详细介绍

    一.简介 关于正则表达式,我在前一篇(数据科学学习手札31)中已经做了详细介绍,本篇将对Python中自带模块re的常用功能进行总结: re作为Python中专为正则表达式相关功能做出支持的模块,提供 ...

  9. (数据科学学习手札69)详解pandas中的map、apply、applymap、groupby、agg

    *从本篇开始所有文章的数据和代码都已上传至我的github仓库:https://github.com/CNFeffery/DataScienceStudyNotes 一.简介 pandas提供了很多方 ...

随机推荐

  1. CountDownLatch的简单使用

    from https://www.jianshu.com/p/cef6243cdfd9 1.CountDownLatch是什么? CountDownLatch是一个同步工具类,它允许一个或多个线程一直 ...

  2. July 18th 2017 Week 29th Tuesday

    My heart is stronger now that you are in it. 我的心里有了你,从此变得更强大. You will no longer feel lonely if ther ...

  3. Shodan搜索引擎介绍

    from:http://www.exploit-db.com/wp-content/themes/exploit/docs/33859.pdf 0x00 概要 这篇文章可以作为渗透测试人员和安全工作者 ...

  4. 洗牌算法shuffle

    对这个问题的研究始于一次在群里看到朋友发的洗牌面试题.当时也不知道具体的解法如何,于是随口回了一句:每次从剩下的数字中随机一个.过后找相关资料了解了下,洗牌算法大致有3种,按发明时间先后顺序如下: 一 ...

  5. PhoneGap 的存储 API_localStorage 和 sessionStorage

    一.介绍 1.为了替代Cookile这门古老的客户端存储技术,Html5的WEB Storage Api 提供了俩中在 客户端存储数据库的方法:localStorage 和 sessionStorag ...

  6. hdu-3388 Coprime---容斥定理&&DFS版

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3388 题目大意: 求同时与m,n互质的第k个数是多少! 解题思路: 和HDU-4135类似,将m和n ...

  7. #20145238荆玉茗《网络对抗》-逆向及Bof进阶实践

    20145238荆玉茗<网络对抗>-逆向及Bof进阶实践 实践目的:注入shellcode 准备一段shellcode代码 Shellcode实际是一段代码(也可以是填充数据),是用来发送 ...

  8. jenkins没安装git报错

    Jenkins新建项目中源码管理使用Git时遇到如下问题: 在安装jenkins服务器上查看一下git版本,可能没有安装git  也可能是git版本太低 [root@localhost nnnnn]# ...

  9. byte转换字符串(string)+字符串转换byte

    C# 中字符串string和字节数组byte[]的转换 //string转byte[]: byte[] byteArray = System.Text.Encoding.Default.GetByte ...

  10. Android 进价5_自定义广播 通过广播更新ListView的适配器 下载管理

    1.在处理下载管理时,服务在后台运行,下载完成后要更新listview列表的按钮,将“下载”改成“打开”这样一个功能. 在Activity里面写一个静态内部类,继承广播.其中属性text_button ...