[轉]將時間序列預測問題轉換為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閱讀 228,333評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,491評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,263評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,708評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,409評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,939評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,774評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,650評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容