如何将时间序列问题转化为监督学习问题
1.学习目标:
- 如何创建一个函数能将时间序列数据集转化为监督学习数据集
- 如何转变单变量的时间序列数据集为机器学习所用
- 如何转变多变量的时间序列数据集为机器学习所用
2.时间序列 vs 监督学习
时间序列数据集是按时间索引排序的一系列数字,也可被认为是有序的list或column
而监督学习数据集由输入模式 X 和输出模式 Y 组成,从输入模式里学习如何预测输出模式
3.pandas shift() 函数
这是一个在将时间序列数据集转型为机器学习数据集中的 关键函数!
给定一个DataFrame, shift() 函数可以被用来创建向下平移的各列副本(前面空了的行用NaN填充)或向上平移的各列副本(后端空行用NaN填充)
这就相当于创建了各列的滞后观察以及前驱观察,这就转化为了监督学习的数据格式!!
看一个shift()的小栗子,这里模拟一个10个数字的序列为时间序列数据,它只有一列:
# 导入前驱包
import sys
sys.path.append("C:\\python\\lib\\site-packages")
from pandas import DataFrame
df = DataFrame()
df["t"] = [x for x in range(10)]
df
t | |
---|---|
0 | 0 |
1 | 1 |
2 | 2 |
3 | 3 |
4 | 4 |
5 | 5 |
6 | 6 |
7 | 7 |
8 | 8 |
9 | 9 |
我们可以通过在顶部插入一个新的行来将所有的观察结果向下移动一步。 由于新行没有数据,我们可以使用NaN来表示“无数据”。
而 shift() 可以为我们做到这一点:
from pandas import DataFrame
df = DataFrame()
df["t"] = [x for x in range(10)]
df["t-1"] = df.shift(1) # 向下平移一行,对每一行的视角来看这一列代表之前一个时段的数据
df
t | t-1 | |
---|---|---|
0 | 0 | NaN |
1 | 1 | 0.0 |
2 | 2 | 1.0 |
3 | 3 | 2.0 |
4 | 4 | 3.0 |
5 | 5 | 4.0 |
6 | 6 | 5.0 |
7 | 7 | 6.0 |
8 | 8 | 7.0 |
9 | 9 | 8.0 |
可以看到,如果我们重复shift() 2或3… ,将会生成一个长序列 X 以预测 y
shift() 函数同样可以接收一个负数,代表向上平移多少步:
df["t+1"] = df["t"].shift(-1) # shift() 传入负数代表向上平移
df
t | t-1 | t+1 | |
---|---|---|---|
0 | 0 | NaN | 1.0 |
1 | 1 | 0.0 | 2.0 |
2 | 2 | 1.0 | 3.0 |
3 | 3 | 2.0 | 4.0 |
4 | 4 | 3.0 | 5.0 |
5 | 5 | 4.0 | 6.0 |
6 | 6 | 5.0 | 7.0 |
7 | 7 | 6.0 | 8.0 |
8 | 8 | 7.0 | 9.0 |
9 | 9 | 8.0 | NaN |
在时间序列预测的术语中,当前时间 t 和未来时间 (t+1,..,t+n) 是预测时间,而过去的观测值 (t-1, ..,t-m) 用于预测
我们可以看到shift()一个正数与负数是如何创建一个新的DataFrame, 它将时间序列数据转化为适用于监督学习的输入序列和输出序列
它不仅可以转化成经典的 X->y 预测, 也可以进行 X->Y 这样序列间的预测
此外,shift() 函数也适用于所谓的多变量时间预测问题, 这时有多个变量而不只是一个,处理思路类似
4.series_to_supervised() 函数
我们希望创建一个函数,给定输入、输出序列的长度,它可以自动地将时间序列数据转型为适用于监督学习的数据
这将是一个非常有用的工具,因为它允许我们尝试不同的数据帧格式,看哪个在机器学习模型中performance比较好
因此,我们将定义一个series_to_supervised() 函数, 它可以将单变量或多变量的时间序列数据帧转化为适用于监督学习的数据帧
它包含4个参数:
- data: 观测序列。格式是一个 list 或 2维 Numpy Array required
- n_in: 观测数据input(X)的步长,范围[1, len(data)], 默认为1
- n_out: 观测数据output(y)的步长, 范围为[0, len(data)-1], 默认为1
- dropnan: 是否删除存在NaN的行,默认为True
它的返回值只有一个, 即转型后适用于监督学习的 DataFrame
新的DataFrame每一列名字都可被变量编号与时间步长适当的命名,我们就可以用它来进行不同时间步长的时间序列预测了
我们可以自行决定如何分割DataFrame为 X 和 Y 部分进行监督训练
函数完整代码如下:
from pandas import DataFrame
from pandas import concat
def series_to_supervised(data, n_in=1, n_out=1, dropnan=True):
n_vars = 1 if type(data) is list else data.shape[1]
df = DataFrame(data)
cols, names = [], []
# i: n_in, n_in-1, ..., 1
# 代表t-n_in, ... ,t-1
for i in range(n_in, 0, -1):
cols.append(df.shift(i))
names += [('var%d(t-%d)' % (j+1, i)) for j in range(n_vars)]
for i in range(0, n_out):
cols.append(df.shift(-i))
if i == 0:
names += [('var%d(t)' % (j+1)) for j in range(n_vars)]
else:
names += [('var%d(t+%d)' % (j+1, i)) for j in range(n_vars)]
agg = concat(cols, axis=1)
agg.columns = names
if dropnan:
agg.dropna(inplace=True)
return agg
5.单步单变量预测(One-Step Univariate Forecasting)
values = [x for x in range(10)]
data = series_to_supervised(values)
data
var1(t-1) | var1(t) | |
---|---|---|
1 | 0.0 | 1 |
2 | 1.0 | 2 |
3 | 2.0 | 3 |
4 | 3.0 | 4 |
5 | 4.0 | 5 |
6 | 5.0 | 6 |
7 | 6.0 | 7 |
8 | 7.0 | 8 |
9 | 8.0 | 9 |
如上所示是最简单的情况,用t-1的值预测t的值
我们可以指定输入序列的长度,例如3, 即用t-3, t-2, t-1的序列预测t:
values = [x for x in range(10)]
data = series_to_supervised(values, 3)
data
var1(t-3) | var1(t-2) | var1(t-1) | var1(t) | |
---|---|---|---|---|
3 | 0.0 | 1.0 | 2.0 | 3 |
4 | 1.0 | 2.0 | 3.0 | 4 |
5 | 2.0 | 3.0 | 4.0 | 5 |
6 | 3.0 | 4.0 | 5.0 | 6 |
7 | 4.0 | 5.0 | 6.0 | 7 |
8 | 5.0 | 6.0 | 7.0 | 8 |
9 | 6.0 | 7.0 | 8.0 | 9 |
6.多步或序列预测(Multi-Step or Sequence Forecasting)
一类不同的预测问题是用过去的观测值一个序列或未来的观测值,这被称为
序列预测(sequence forecasting)或多步预测multi-step forecasting
这时,就需要用到另一个参数了,指定n_out 可以让我们预测一个序列:
values = [x for x in range(10)]
data = series_to_supervised(values, 2, 2) # 每次用过去的两列值预测未来的两列值
data
var1(t-2) | var1(t-1) | var1(t) | var1(t+1) | |
---|---|---|---|---|
2 | 0.0 | 1.0 | 2 | 3.0 |
3 | 1.0 | 2.0 | 3 | 4.0 |
4 | 2.0 | 3.0 | 4 | 5.0 |
5 | 3.0 | 4.0 | 5 | 6.0 |
6 | 4.0 | 5.0 | 6 | 7.0 |
7 | 5.0 | 6.0 | 7 | 8.0 |
8 | 6.0 | 7.0 | 8 | 9.0 |
7.多变量预测(Multivariate Forecasting)
另一类重要的问题叫做多变量时间序列问题(multivariate time series), 这时我们有多个变量的观测值,并要预测其中的某一个或多个变量
举例,我们有两个时间序列的观测值序列 obs1 和 obs2, 我们要预测其中的一个或两个:
raw = DataFrame()
raw["ob1"] = [x for x in range(10)]
raw["ob2"] = [x for x in range(50, 60)]
values = raw.values
data = series_to_supervised(values)
data
var1(t-1) | var2(t-1) | var1(t) | var2(t) | |
---|---|---|---|---|
1 | 0.0 | 50.0 | 1 | 51 |
2 | 1.0 | 51.0 | 2 | 52 |
3 | 2.0 | 52.0 | 3 | 53 |
4 | 3.0 | 53.0 | 4 | 54 |
5 | 4.0 | 54.0 | 5 | 55 |
6 | 5.0 | 55.0 | 6 | 56 |
7 | 6.0 | 56.0 | 7 | 57 |
8 | 7.0 | 57.0 | 8 | 58 |
9 | 8.0 | 58.0 | 9 | 59 |
如上所示,这是单步多变量的数据格式,X 和 Y可以让我们自由选定。例如如果当前的var1(t)也被提供作为输入,只需预测var2(t), 这当然也是可以的
接下来做多步预测:
raw = DataFrame()
raw["ob1"] = [x for x in range(10)]
raw["ob2"] = [x for x in range(50, 60)]
values = raw.values
data = series_to_supervised(values, 1, 2) # 预测后来的两步
data
var1(t-1) | var2(t-1) | var1(t) | var2(t) | var1(t+1) | var2(t+1) | |
---|---|---|---|---|---|---|
1 | 0.0 | 50.0 | 1 | 51 | 2.0 | 52.0 |
2 | 1.0 | 51.0 | 2 | 52 | 3.0 | 53.0 |
3 | 2.0 | 52.0 | 3 | 53 | 4.0 | 54.0 |
4 | 3.0 | 53.0 | 4 | 54 | 5.0 | 55.0 |
5 | 4.0 | 54.0 | 5 | 55 | 6.0 | 56.0 |
6 | 5.0 | 55.0 | 6 | 56 | 7.0 | 57.0 |
7 | 6.0 | 56.0 | 7 | 57 | 8.0 | 58.0 |
8 | 7.0 | 57.0 | 8 | 58 | 9.0 | 59.0 |
8.总结
有了这个函数,我们可以生成适合监督学习的单步,多步,单变量,多变量的时间序列预测DataFrame
不过n_in 到底取多长合适, n_out到底取多长合适,这些都需要不断地进行实验
本文主要翻译自https://machinelearningmastery.com/convert-time-series-supervised-learning-problem-python/