[转]将时间序列预测问题转换为python中的监督学习问题

原文:《How to Convert a Time Series to a Supervised Learning Problem in Python》---Jason Brownlee

一、前言

像深度学习这样的机器学习方法可以用于时间序列预测。

在机器学习方法可以被使用前,时间序列预测问题必须重新构建成监督学习问题,从一个单纯的序列变成一对序列输入和输出。

在这个教程中,你将了解如何将单变量和多变量时间序列预测问题转换为与机器学习算法一起使用的监督学习问题。

在你完成本教程后,你将知道:

  • 如何开发一个功能,将时间序列数据集转换为监督学习数据集
  • 如何变换单变量时间序列数据进行机器学习。
  • 如何变换多元时间序列数据进行机器学习。

让我们开始吧。

二、时间序列与监督学习

在我们开始之前,让我们花点时间来更好地理解时间序列和监督学习数据的形式。
时间序列是由时间索引排序的一系列数字, 这可以被认为是有序值列表或列

例如:

0
1
2
3
4
5
6
7
8
9

监督学习问题由输入模式(X)和输出模式(y)组成,使得算法可以学习如何从输入模式预测输出模式
例如:


X,  y
1   2
2,  3
3,  4
4,  5
5,  6
6,  7
7,  8
8,  9

有关这个主题更多的信息,请参考如下文章:

三、Pandas shift()方法介绍

帮助将时间序列数据转化为监督学习问题的关键方法是Pandas shift()函数。
给定一个DataFrame,可以使用shift()函数来创建向前推送的列的副本(NaN值的行添加到前面)或拉回(添加到最后的NaN值的行)。
这是创建滞后观察列以及监督学习格式的时间序列数据集的预测观测列所需的行为。
我们来看一些shift()函数的实际使用案例。
我们可以定义一个由10个数字组成的序列来模拟时间序列数据集,在这种情况下,DataFrame中的单个列如下所示:

from pandas import DataFrame
df = DataFrame()
df['t'] = [x for x in range(10)]
print(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['t'].shift(1)
print(df)

运行示例,我们发现数据集中有了两列的值,第一个是原来的列和一个新的shift()函数产生的列。
我们可以看到,将序列向前移动一步,我们构造出了一个原始的监督学习问题,尽管X和y的顺序是错误的。 忽略行标签的那一列,由于NaN值,第一行需要被丢弃。 第二行显示第二列(输入或X)中的输入值0.0和第一列(输出或y)中的值1。

  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

我们可以看到,如果我们可以重复上述过程,通过移动2步,3步和更多的移位,我们如何创建长的输入序列(X),用来预测输出值(y)。
移位运算符也可以接受一个负整数值。 这样做的结果是通过在最后插入新行来提取结果。 下面是一个例子:

from pandas import DataFrame
df = DataFrame()
df['t'] = [x for x in range(10)]
df['t+1'] = df['t'].shift(-1)
print(df)

运行该示例,显示了一个最后一行值为NaN的新列。
我们可以看到,原始列可以作为输入(X),第二个新列作为输出值(y)。 那就是输入值0可以用来预测1的输出值。

 t  t+1
0  0  1.0
1  1  2.0
2  2  3.0
3  3  4.0
4  4  5.0
5  5  6.0
6  6  7.0
7  7  8.0
8  8  9.0
9  9  NaN

在技术上,在时间序列预测术语中,当前时间(t)和未来时间(t + 1,t + n)是预测时间,过去的观测值(t-1,t-n)被用于预测。
我们可以看到正向和负向的移动可以用来创建一个新的数据帧,从而转变成监督学习问题的时间序列的输入和输出模式。
这不仅允许经典的X - > y预测,而且允许X - > Y,其中输入和输出都可以是序列。

此外,移位函数也适用于所谓的多元时间序列问题。 我们有多个(例如温度和压力),而不是有一组时间序列的观测值。 时间序列中的所有变量可以向前或向后移动以创建多元输入和输出序列。 我们将在本教程稍后讨论这个问题。

四、series_to_supervised()函数介绍

我们可以通过给定的输入和输出序列的长度,使用Pandas中的shift()函数自动创建新的时间序列问题的框架。
这将是一个有用的工具,因为它可以让我们使用机器学习算法探索不同框架的时间序列问题,来找到更好的模型。
在本节中,我们将定义一个名为series_to_supervised()的新Python函数,它采用单变量或多变量时间序列,并将其作为监督学习数据集。

该函数有四个参数:

  • 数据:序列,列表或二维的NumPy数组。 必需的参数。
  • n_in:作为输入的滞后步数(X)。 值可能介于[1..len(data)],可选参数。 默认为1。
  • n_out:作为输出的移动步数(y)。 值可以在[0..len(data)-1]之间, 可选参数。 默认为1。
  • dropnan:Boolean是否删除具有NaN值的行。 可选参数。 默认为True。

该函数返回一个单一的值:

  • 返回:作为监督学习序列的Pandas DataFrame类型值。

新的数据集被构造为一个DataFrame,每一列都适当地以可变数量和时间步长命名。 这允许您从给定的单变量或多变量时间序列中设计各种不同的时间步长序列类型预测问题。
一旦DataFrame返回,您可以决定如何将返回的DataFrame的行分割为X和Y两部分,以便以任何您希望的方式监督学习。
这个函数是用默认参数定义的,所以如果你只用你的数据调用它,它将构造一个DataFrame,其中t-1为X,t为y
该函数可以在Python 2和Python 3中运行,下面列出了完整的功能,包括功能注释:

from pandas import DataFrame
from pandas import concat
 
def series_to_supervised(data, n_in=1, n_out=1, dropnan=True):
    """
    Frame a time series as a supervised learning dataset.
    Arguments:
        data: Sequence of observations as a list or NumPy array.
        n_in: Number of lag observations as input (X).
        n_out: Number of observations as output (y).
        dropnan: Boolean whether or not to drop rows with NaN values.
    Returns:
        Pandas DataFrame of series framed for supervised learning.
    """
    n_vars = 1 if type(data) is list else data.shape[1]
    df = DataFrame(data)
    cols, names = list(), list()
    # input sequence (t-n, ... 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)]
    # forecast sequence (t, t+1, ... t+n)
    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)]
    # put it all together
    agg = concat(cols, axis=1)
    agg.columns = names
    # drop rows with NaN values
    if dropnan:
        agg.dropna(inplace=True)
    return agg

如果你发现什么好的方法,可以使上面的函数更强大或更可读,请在下面的评论中告诉我。
现在我们有了全部的函数,我们可以探索如何使用它。

五、移动一步的单变量预测

在时间序列预测中的标准做法是使用过去的观察值(例如t-1)作为输入变量来预测当前的时间步长(t),这被称为一步预测
下面的例子演示了使用过去的时间步(t-1)来预测当前时间步长(t)的一个例子。

from pandas import DataFrame
from pandas import concat
 
def series_to_supervised(data, n_in=1, n_out=1, dropnan=True):
    """
    Frame a time series as a supervised learning dataset.
    Arguments:
        data: Sequence of observations as a list or NumPy array.
        n_in: Number of lag observations as input (X).
        n_out: Number of observations as output (y).
        dropnan: Boolean whether or not to drop rows with NaN values.
    Returns:
        Pandas DataFrame of series framed for supervised learning.
    """
    n_vars = 1 if type(data) is list else data.shape[1]
    df = DataFrame(data)
    cols, names = list(), list()
    # input sequence (t-n, ... 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)]
    # forecast sequence (t, t+1, ... t+n)
    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)]
    # put it all together
    agg = concat(cols, axis=1)
    agg.columns = names
    # drop rows with NaN values
    if dropnan:
        agg.dropna(inplace=True)
    return agg
 
 
values = [x for x in range(10)]
data = series_to_supervised(values)
print(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

我们可以看到,列值被命名为“var1”,输入列值被命名为(t-1),输出时间步长命名为(t)。
我们还可以看到,具有NaN值的行已经从DataFrame中自动删除。
我们可以用任意数量的长度输入序列(如3)来重复这个例子,这可以通过指定输入序列的长度作为参数来完成; 例如:
data = series_to_supervised(values, 3)

完整的例子如下所示:

from pandas import DataFrame
from pandas import concat
 
def series_to_supervised(data, n_in=1, n_out=1, dropnan=True):
    """
    Frame a time series as a supervised learning dataset.
    Arguments:
        data: Sequence of observations as a list or NumPy array.
        n_in: Number of lag observations as input (X).
        n_out: Number of observations as output (y).
        dropnan: Boolean whether or not to drop rows with NaN values.
    Returns:
        Pandas DataFrame of series framed for supervised learning.
    """
    n_vars = 1 if type(data) is list else data.shape[1]
    df = DataFrame(data)
    cols, names = list(), list()
    # input sequence (t-n, ... 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)]
    # forecast sequence (t, t+1, ... t+n)
    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)]
    # put it all together
    agg = concat(cols, axis=1)
    agg.columns = names
    # drop rows with NaN values
    if dropnan:
        agg.dropna(inplace=True)
    return agg
 
 
values = [x for x in range(10)]
data = series_to_supervised(values, 3)
print(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

六、多步或者序列预测

另一种类型的预测问题是使用过去的值来预测未来的序列值,这可以被称为序列预测或多步预测。
我们可以通过指定另一个参数来构建序列预测的时间序列。 例如,我们可以用2个过去的观测值的输入序列来构造一个预测问题,以便预测2个未来的观测值如下:
data = series_to_supervised(values, 2, 2)

完整的代码如下:

from pandas import DataFrame
from pandas import concat
 
def series_to_supervised(data, n_in=1, n_out=1, dropnan=True):
    """
    Frame a time series as a supervised learning dataset.
    Arguments:
        data: Sequence of observations as a list or NumPy array.
        n_in: Number of lag observations as input (X).
        n_out: Number of observations as output (y).
        dropnan: Boolean whether or not to drop rows with NaN values.
    Returns:
        Pandas DataFrame of series framed for supervised learning.
    """
    n_vars = 1 if type(data) is list else data.shape[1]
    df = DataFrame(data)
    cols, names = list(), list()
    # input sequence (t-n, ... 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)]
    # forecast sequence (t, t+1, ... t+n)
    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)]
    # put it all together
    agg = concat(cols, axis=1)
    agg.columns = names
    # drop rows with NaN values
    if dropnan:
        agg.dropna(inplace=True)
    return agg
 
 
values = [x for x in range(10)]
data = series_to_supervised(values, 2, 2)
print(data)

运行上面的代码,输出结果如下,t-2和t-1作为输入序列,t和t+1作为输出序列

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

七、多变量预测

另一个重要的时间序列称为多元时间序列
这是我们可以观察到多种不同的方式,并有兴趣预测其中的一个或多个。

例如,我们可能有两组时间序列观测obs1和obs2,我们希望预测其中的一个或两个。
我们可以以完全相同的方式调用series_to_supervised(),如下:

from pandas import DataFrame
from pandas import concat
 
def series_to_supervised(data, n_in=1, n_out=1, dropnan=True):
    """
    Frame a time series as a supervised learning dataset.
    Arguments:
        data: Sequence of observations as a list or NumPy array.
        n_in: Number of lag observations as input (X).
        n_out: Number of observations as output (y).
        dropnan: Boolean whether or not to drop rows with NaN values.
    Returns:
        Pandas DataFrame of series framed for supervised learning.
    """
    n_vars = 1 if type(data) is list else data.shape[1]
    df = DataFrame(data)
    cols, names = list(), list()
    # input sequence (t-n, ... 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)]
    # forecast sequence (t, t+1, ... t+n)
    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)]
    # put it all together
    agg = concat(cols, axis=1)
    agg.columns = names
    # drop rows with NaN values
    if dropnan:
        agg.dropna(inplace=True)
    return agg
 
 
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)
print(data)

运行示例将打印数据,为显示一个时间步长但是包含两个变量的输入模式,以及一个时间步长两个变量的输出模式。
同样,根据问题的具体情况,可以任意选择将列分成X和Y,例如,如果当前观察到的var1也作为输入提供,并且只有var2被预测。

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

通过指定输入和输出序列的长度,您可以看到如何使用多元时间序列轻松地进行序列预测。
例如,下面是以1个时间步骤作为输入和2个时间步骤作为预测序列的重新构造的示例。

from pandas import DataFrame
from pandas import concat
 
def series_to_supervised(data, n_in=1, n_out=1, dropnan=True):
    """
    Frame a time series as a supervised learning dataset.
    Arguments:
        data: Sequence of observations as a list or NumPy array.
        n_in: Number of lag observations as input (X).
        n_out: Number of observations as output (y).
        dropnan: Boolean whether or not to drop rows with NaN values.
    Returns:
        Pandas DataFrame of series framed for supervised learning.
    """
    n_vars = 1 if type(data) is list else data.shape[1]
    df = DataFrame(data)
    cols, names = list(), list()
    # input sequence (t-n, ... 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)]
    # forecast sequence (t, t+1, ... t+n)
    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)]
    # put it all together
    agg = concat(cols, axis=1)
    agg.columns = names
    # drop rows with NaN values
    if dropnan:
        agg.dropna(inplace=True)
    return agg
 
 
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)
print(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

尝试使用自己的数据集,并尝试使用多个不同的框架,以查看最佳效果。

八、总结

在本教程中,您发现了如何将时间序列数据集重新组织为有监督的Python学习问题。

具体来说,你了解到:

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

推荐阅读更多精彩内容