深度学习处理时间序列(1)
不同类型的时间序列任务
时间序列(timeseries)是指定期测量获得的任意数据,比如每日股价、城市每小时耗电量或商店每周销售额。无论是自然现象(如地震活动、鱼类种群的演变或某地天气)还是人类活动模式(如网站访问者、国家GDP或信用卡交易),时间序列都无处不在。与前面遇到的数据类型不同,处理时间序列需要了解系统的动力学(dynamics),包括系统的周期性循环、系统随时间如何变化、系统的周期规律与突然激增等。
目前,最常见的时间序列任务是预测:预测序列接下来会发生什么。比如提前几小时预测用电量,以便于预计需求;提前几个月预测收入,以便于制订预算计划;提前几天预测天气,以便于规划日程。预测是重点内容。但实际上,你还可以对时间序列做很多其他事情。
分类:为时间序列分配一个或多个分类标签。例如,已知一名网站访问者的活动时间序列,判断该访问者是机器人还是人类。
事件检测:识别连续数据流中特定预期事件的发生。一个特别有用的应用是“热词检测”,模型监控音频流并检测像“Ok Google”或“Hey Alexa”这样的话。
异常检测:检测连续数据流中出现的异常情况。公司网络出现异常活动?可能是有攻击者。生产线出现异常读数?是时候让人去查看一下了。异常检测通常是通过无监督学习实现的,因为你通常不知道要检测哪种异常,所以无法针对特定的异常示例进行训练。
处理时间序列时,你会遇到许多特定领域的数据表示方法。例如,你可能听说过傅里叶变换,它是指将一系列值表示为不同频率的波的叠加。对那些以周期和振荡为主要特征的数据(如声音、摩天大楼的振动或人的脑电波)进行预处理时,傅里叶变换可以发挥很大作用。对于深度学习而言,傅里叶分析(或相关的梅尔频率分析)与其他特定领域的表示可以用来做特征工程。这是一种在训练模型之前准备数据的方式,以便让模型更容易运行。然而,本章不会介绍这些技术,而是将重点放在构建模型上。
我们看看循环神经网络(recurrent neural network,RNN)及如何将其应用于时间序列预测。
温度预测示例
下面的所有代码示例都针对同一个问题:已知每小时测量的气压、湿度等数据的时间序列(数据由屋顶的一组传感器记录),预测24小时之后的温度。你会发现,这是一个相当有挑战性的问题。
利用这个温度预测任务,我们会展示时间序列数据与之前见过的各类数据集在本质上有哪些不同。你会发现,密集连接网络和卷积神经网络并不适合处理这种数据集,而另一种机器学习技术——循环神经网络——在这类问题上大放异彩。
我们将使用一个天气时间序列数据集,它由德国耶拿的马克斯•普朗克生物地球化学研究所的气象站记录。在这个数据集中,每10分钟记录14个物理量(如温度、气压、湿度、风向等),其中包含多年的记录。原始数据可追溯至2003年,但本例仅使用2009年~2016年的数据。首先下载数据并解压,如下所示。
!wget https://s3.amazonaws.com/keras-datasets/jena_climate_2009_2016.csv.zip
!unzip jena_climate_2009_2016.csv.zip
执行结果如下图所示:
解压后获得下面的文件:
下面我们来查看数据,如代码清单10-1所示。代码清单10-1 查看耶拿天气数据集
import os
fname = os.path.join("jena_climate_2009_2016.csv")
with open(fname) as f:
data = f.read()
lines = data.split("\n")
#获取数据的标题
header = lines[0].split(",")
#获取除了标题以外的所有数据
lines = lines[1:]
print(header)
#打印数据的量
print(len(lines))
运行结果
从输出可以看出,共有420 451行数据(每行数据是一个时间步,记录了1个日期和14个与天气有关的值),输出还包含以下表头。
["Date Time",
"p (mbar)",
"T (degC)",
"Tpot (K)",
"Tdew (degC)",
"rh (%)",
"VPmax (mbar)",
"VPact (mbar)",
"VPdef (mbar)",
"sh (g/kg)",
"H2OC (mmol/mol)",
"rho (g/m**3)",
"wv (m/s)",
"max. wv (m/s)",
"wd (deg)"]
接下来,我们将所有420 451行数据转换为NumPy数组,如代码清单10-2所示:一个数组包含温度(单位为摄氏度),另一个数组包含其他数据。我们将使用这些特征来预测温度。请注意,我们舍弃了"Date Time"(日期和时间)这一列。
代码清单10-2 解析数据
import numpy as np
#用于保存每个line的温度
temperature = np.zeros((len(lines),))
#用于保存原始数据中除了日期以外的特征值
raw_data = np.zeros((len(lines), len(header) - 1))
for i, line in enumerate(lines):
#丢弃日期数据
values = [float(x) for x in line.split(",")[1:]]
#保存温度
temperature[i] = values[1]
#将所有列(包括温度)保存在raw_data数组中
raw_data[i, :] = values[:]
我们来绘制温度随时间的变化曲线(单位为摄氏度),如代码清单10-3和图10-1所示。在这张图中,你可以清楚地看到温度的年度周期性变化,数据跨度为8年。
代码清单10-3 绘制温度时间序列
from matplotlib import pyplot as plt
plt.plot(range(len(temperature)), temperature)
plt.show()
如果没有安装matplotlib的库的话,执行下面的命令就行了。
pip3 install matplotlib
绘制出来的图片:
我们来绘制前10天温度数据的曲线,如代码清单10-4和图10-2所示。由于每10分钟记录一次数据,因此每天有144个数据点(24×6=144)。
代码清单10-4 绘制前10天的温度时间序列
plt.plot(range(1440), temperature[:1440])
plt.show()
从图中可以看到每天的周期性变化,尤其是最后4天特别明显。另外请注意,这10天一定是来自于寒冷的冬季月份。
本文主要的可执行代码。大家复制即可得到本文的效果。
import os
fname = os.path.join("jena_climate_2009_2016.csv")
with open(fname) as f:
data = f.read()
lines = data.split("\n")
header = lines[0].split(",")
lines = lines[1:]
print(header)
print(len(lines))
import numpy as np
temperature = np.zeros((len(lines),))
raw_data = np.zeros((len(lines), len(header) - 1))
for i, line in enumerate(lines):
values = [float(x) for x in line.split(",")[1:]]
#将第1列保存在temperature数组中
temperature[i] = values[1]
#将所有列(包括温度)保存在raw_data数组中
raw_data[i, :] = values[:]
from matplotlib import pyplot as plt
plt.plot(range(len(temperature)), temperature)
plt.show()