Python中使用LSTM網絡進行時間序列預測

長短記憶型遞歸神經網絡擁有學習長觀察值序列的潛力。

它似乎是實現時間序列預測的完美方法,事實上,它可能就是。

在此教程中,你將學習如何構建解決單步單變量時間序列預測問題的LSTM預測模型。

在學習完此教程後,您將學會:

  • 如何為預測問題制定性能基準。

  • 如何為單步時間序列預測問題設計性能強勁的測試工具。

  • 如何準備數據以及創建並評測用於預測時間序列的LSTM 遞歸神經網絡。

讓我們開始吧。

Python中使用LSTM網絡進行時間序列預測

Python中使用長短期記憶網絡進行時間序列預測

Matt MacGillivray 拍攝,保留部分權利

教程概覽

這是一個大課題,我們將深入討論很多問題。請做好準備。

該教程分為 9 節;它們分別為:

  1. 洗髮水銷量數據集

  2. 測試設置

  3. 持續性模型預測

  4. LSTM數據準備

  5. LSTM 模型開發

  6. LSTM預測

  7. 完成LSTM 樣本

  8. 得出穩定的結果

  9. 教程延伸

Python 環境

本教程假設您已安裝 Python SciPy 環境。您在學習本教程時可使用 Python 2 或 3。

您必須使用 TensorFlow 或 Theano 後端安裝 Keras(2.0或更高版本)。

本教程還假設您已安裝 scikit-learn、Pandas、 NumPy 和 Matplotlib。

如果您在安裝環境時需要幫助,請查看這篇文章:

  • 如何使用 Anaconda安裝機器學習和深度學習所需的 Python 環境

    http://machinelearningmastery.com/setup-python-environment-machine-learning-deep-learning-anaconda/

洗髮水銷量數據集

該數據集描述某洗髮水在3年內的月度銷量。

數據單位為銷售量,共有36個觀察值。原始數據集由Makridakis、Wheelwright 和 Hyndman(1998)提供。

您可通過此鏈接下載和進一步瞭解該數據集:https://datamarket.com/data/set/22r0/sales-of-shampoo-over-a-three-year-period。

將該數據集下載至您當前的工作目錄,並保存為“shampoo-sales.csv”。注意您可能需要刪除 DataMarket 添加的腳註信息。

下方例子加載並生成已加載數據集的視圖。

Python中使用LSTM網絡進行時間序列預測

運行該示例,以 Pandas 序列的形式加載數據集,並打印出頭5行。

Python中使用LSTM網絡進行時間序列預測

然後生成顯示增長持續性的序列線圖。

Python中使用LSTM網絡進行時間序列預測

洗髮水月度銷量數據集線圖

試驗測試設置

我們將把洗髮水銷量數據集分為兩組:訓練組和測試組。

前兩年的銷售數據將作為訓練數據集,最後一年的數據將作為測試組。

例如:

Python中使用LSTM網絡進行時間序列預測

使用訓練數據集構建模型,然後對測試數據集進行預測。

我們將使用滾動預測的方式,也稱為步進式模型驗證。

以每次一個的形式運行測試數據集的每個時間步。使用模型對時間步作出預測,然後收集測試組生成的實際預期值,模型將利用這些預期值預測下一時間步。

例如:

Python中使用LSTM網絡進行時間序列預測

這模擬了現實生活中的場景,新的洗髮水銷量觀察值會在月底公佈,然後被用於預測下月的銷量。

最後,收集所有測試數據集的預測,計算誤差值總結該模型的預測能力。採用均方根誤差(RMSE)的原因是這種計算方式能夠降低粗大誤差對結果的影響,所得分數的單位和預測數據的單位相同,即洗髮水月度銷量。

例如:

Python中使用LSTM網絡進行時間序列預測

持續性模型預測

對呈線性增長趨勢的時間序列作出的準確的基線預測就是持續性化預測。

在持續性模型中,上一時間步(t-1)得到的觀察值用於預測當前時間步(t)的觀察值。

為了實現這一方法,我們可以從訓練數據和步進驗證積累的歷史數據中收集上一次觀察,然後用它來預測當前時間步。

例如:

Python中使用LSTM網絡進行時間序列預測

我們將把所有預測累積在一個數組中,這樣便可將它們與測試數據集進行直接比較。

洗髮水銷量數據集持續性預測模型的完整示例如下所示。

Python中使用LSTM網絡進行時間序列預測

運行示例,約打印136個洗髮水月度銷量的均方根誤差,對測試數據集進行預測。

Python中使用LSTM網絡進行時間序列預測

同時生成測試數據集(藍色)對比預測值(橙色)的線圖,在背景中顯示持續性模型預測。

Python中使用LSTM網絡進行時間序列預測

洗髮水銷量數據集觀察值對比預測值的持續性預測

想要了解更多關於時間序列預測的持續性模型的內容,請查看這篇文章:

  • 如何使用Python完成時間序列預測的基線預測

    http://machinelearningmastery.com/persistence-time-series-forecasting-with-python/

現在我們制定了數據集的性能基線,接下來就可以開始構建數據的LSTM模型了。

LSTM數據準備

在將LSTM模型放入數據集前,我們必須轉化數據。

本節分外三步:

  1. 將時間序列轉化為監督學習問題。

  2. 轉化時間序列數據使其呈靜態。

  3. 轉化觀察值使其處於特定區間。

將時間序列轉化為監督學習

Keras中的LSTM模型假設您的數據分為兩部分:輸入(X)和輸出(y)。

對於時間序列問題,我們可以將上一時間步(t-1)的觀測值作為輸入,將當前時間步(t)的觀測值作為輸出。

為了實現這一轉化,我們可以調用Pandas庫中的shift()函數將某一序列中的所有數值向下錯位特定的位數。我們需要向下錯一位,這位上的數值將成為輸入變量。該時間序列則將成為輸入變量。

然後我們將這兩個序列串在一起創建一個DataFrame進行監督學習。向下錯位後的序列移到了頂部,沒有任何數值。此位置將使用一個NaN(非數)值。我們將用0值代替這些NaN值,LSTM 模型將不得不學習“序列的開頭”或“此處無數據”,因為此數據集中未觀察到銷量為零的月份。

下方的代碼定義了一個完成此步的輔助函數,名稱為 timeseries_to_supervised()。這個函數由原始時間序列數據的NumPy數組和一個滯後觀察值或錯位的序列數生成,並作為輸入使用。

Python中使用LSTM網絡進行時間序列預測

我們可以用載入的洗髮水銷量數據集測試該函數,並將它轉化為監督學習問題。

Python中使用LSTM網絡進行時間序列預測

運行該示例,打印新的監督學習問題的前5行。

Python中使用LSTM網絡進行時間序列預測

想要了解更多關於將時間序列問題轉化為監督學習問題的內容,請查看這篇文章:

  • 時間序列預測問題轉為監督學習問題

    http://machinelearningmastery.com/time-series-forecasting-supervised-learning/

將時間序列轉化為靜態

洗髮水銷量數據集不是靜止的。

這意味著數據中的某個結構與時間有關。更確切地說,數據中存在增加的趨勢。

靜態數據更容易建模,並且很可能得出更加準確的預測。

可以從觀察中移除該趨勢,然後再添加至預測中,將預測恢復至原始區間並計算出相當的誤差值。

移除趨勢的標準方法是差分數據。也就是從當前觀察值(t)中減去從上一時間步(t-1)得到的觀察值。這樣我們就移除了該趨勢,得到一個差分序列,或者一個時間步及其下一時間步得出的觀察值發生改變。

我們可以通過調用pandas庫中的diff() function函數自動完成此步。另外,我們還可以獲得更好的控制,用我們自己編寫的函數完成此步,在該例中我們將採用這種方法,因為它具有靈活性。

下方是一個名稱為difference()的函數,用來計算差分序列。注意,由於不存在用於計算差分值的先前觀察值,因此須略過該序列中的第一個觀察值。

Python中使用LSTM網絡進行時間序列預測

為了使差分序列的預測恢復至原始的區間內,我們還需要逆轉這個流程。

下方的這個名為inverse_difference()的函數用來逆轉這個操作。

Python中使用LSTM網絡進行時間序列預測

我們可以通過差分整個序列來測試這些函數,然後再將它恢復至原始區間內,具體代碼如下所示:

Python中使用LSTM網絡進行時間序列預測

運行示例,打印載入數據的前5行,然後再打印差分序列的前5行,最後再打印序列逆轉差分操作後的前5行。

注意,原始數據集中的第一個觀察值已從逆轉差分操作後的數據中移除。另外最後一個數據集按照預期與第一個數據集相對應。

Python中使用LSTM網絡進行時間序列預測

想要了解更多關於時間序列靜態化和差分的內容,請查看以下文章:

  • 如何用Python檢查時間序列數據是否呈靜態

    http://machinelearningmastery.com/time-series-data-stationary-python/

  • 如何用Python差分時間序列數據集

    http://machinelearningmastery.com/difference-time-series-dataset-python/

轉化時間序列使其處於特定區間

和其他神經網絡一樣,LSTM要求數據須處在該網絡使用的激活函數的區間內。

LSTM的默認激活函數為雙曲正切函數(tanh),這種函數的輸出值處在-1和1之間,這也是時間序列函數的區間。

為了保證該試驗的公平,縮放係數(最小和最大)值必須根據訓練數據集計算,並且用來縮放測試數據集和任何預測。這是為了避免該實驗的公平性受到測試數據集信息影響,而可能使模型在預測時處於劣勢。

我們可以使用MinMaxScaler class轉化數據集使其處在 [-1, 1] 區間內。和其他scikit-learn轉換模塊一樣,它需要提供行列矩陣形式的數據。因此,我們必須在轉換數據集之前變換NumPy數組。

例如:

Python中使用LSTM網絡進行時間序列預測

同樣,我們必須將逆轉對預測的縮放,將數值恢復至原始的區間內,這樣就可以解釋結果並且算出相當的誤差值。

Python中使用LSTM網絡進行時間序列預測

全部綜合起來,下例所示的代碼可轉化洗髮水銷量數據所處的區間。

Python中使用LSTM網絡進行時間序列預測

運行示例,打印載入數據的前5行,再打印經縮放數據的前5行,然後打印逆轉縮放後數據的前5行,匹配原始數據。

Python中使用LSTM網絡進行時間序列預測

現在我們學會了如何為LSTM網絡準備數據,我們就可以構建模型了。

LSTM 模型開發

長短期記憶網絡(LSTM)是一種遞歸神經網絡(RNN)。

這類網絡的的優點是它能學習並記住較長序列,並不依賴預先指定的窗口滯後觀察值作為輸入。

在Keras中,這被稱為stateful,在定義LSTM網絡層時將“stateful”語句設定為“True”。

在默認下,Keras中的LSTM 網絡層在一批數據之間維持狀態。一批數據是訓練數據集中的固定行數,該數據集定義在更新網絡權值之前運行多少模式。

各批數據之間的LSTM層的狀態在默認下是清空的,因此我們必須使LSTM有狀態。通過調用reset_states()函數,我們可以精確掌控LSTM層的狀態何時被清空。

LSTM層要求輸入值須位於有維度的矩陣中;【例子、時間步、特徵】。

  • 例子:是指定義域中的獨立觀察值,通常是幾列數據。

  • 時間步:是指特定觀察值的給定變量的單獨時間步。

  • 特徵:是指的觀察時得到的單獨指標。

我們在該網絡的洗髮水銷量數據集的構造上有些靈活性。我們將簡化構造,並且將問題限制在原始序列的每個時間步,僅保留一個單獨的樣本、一個時間步和一個特徵。

鑑於訓練數據集的形式定義為X輸入和y輸出,必須將其轉化為樣本/時間步/特徵的形式,例如:

Python中使用LSTM網絡進行時間序列預測

LSTM層必須使用 “batch_input_shape” 語句作為元組定義輸入數據的形態,該語句詳細規定讀取沒批數據的預期觀察值數,時間步數和特徵數。

batch大小通常要比樣本總數小很多。它和epoch的數目共同決定網絡學習數據的速度(權值更新的頻率)。

最後一個定義LSTM層的輸入參數是神經元的數目,也稱為記憶單元或模塊的數目。這是一個相當簡單的問題,在1至5之間選取數字應該就足夠了。

下列的這行語句生成一個簡單的LSTM層,並且通過“batch_input_shape”語句規定輸入層的預期參數。

Python中使用LSTM網絡進行時間序列預測

該網絡需要在帶線性激活函數的輸出層上插入一個簡單的神經元,以預測下一時間步的洗髮水銷量。

一旦明確規定好網絡後,必須使用後端數學庫將該網絡編譯成高效的符號表示,例如TensorFlow 或 Theano。

在編譯網絡時,我們必須規定一個損失函數和優化算法。我們將使用“mean_squared_error”作為損失函數,因為它與我們要計算的平方根誤差十分接近,使用高效的ADAM優化算法。

使用連續的KerasAPI 定義該網絡,下方的語句創建並編譯該網絡。

Python中使用LSTM網絡進行時間序列預測

在編譯後,該網絡能夠擬合訓練數據。因為該網絡有狀態,我們必須在內部狀態重啟時實施控制。因此,我們必須一次一個epoch地手動管理訓練流程,直至完成預期的epoch數。

在默認下,epoch內的樣本在輸入網絡之前已經混合。同樣,這對LSTM而言很不理想,因為我們希望該網絡通過學習觀察值序列形成狀態。我們無法通過設置“shuffle”為“False”來禁止樣本的混合。

而且在默認下,該網絡在每個epoch結束時報告大量關於學習進展和模型技能的調試信息。我們可以將“verbose”語句設置為“0”級別以禁止該報告。

然後我們可以在每個訓練epoch結束時重置內部狀態,準備進行下一次訓練迭代。

下方的循環語句可手動調整網絡,使其與訓練數據擬合。

Python中使用LSTM網絡進行時間序列預測

綜合起來,我們可以定義一個名為fit_lstm()的函數,它用於訓練和返回LSTM模型。作為語句,它將訓練數據集轉化為監督學習的形式,一個批量大小,一些epoch和一些神經元。

Python中使用LSTM網絡進行時間序列預測

批量大小必須設置為1.這是因為它必須是訓練和測試數據集大小的一個因子。

模型的predict() 函數也受到批量大小的限制;批量大小必須設置為1,因為我們希望對測試數據進行單步預測。

我們將不會在此教程中調整網絡參數;相反,我們將使用以下結構進行,該結構經過少量測試並且帶有誤差。

  • 批量大小:1

  • Epoch:3000

  • 神經元: 4

作為本教程的延伸,你可能喜歡探索不同的模型參數並嘗試改善性能。

  • 更新:不妨試設置為1500 epoch和1 神經元,性能可能會更好!

下面,我們將探討如何使用合格的LSTM模型作單步預測。

LSTM 預測

一旦LSTM模型與訓練數據相擬合,這個模型就可用來作預測。

同樣,我們有些靈活性。我們可以決定將模型一次性擬合所有訓練數據,讓一次一個地預測測試數據中的每個新時間步(我們將這種方法稱為固定方法)。或者我們可以重新擬合模型或者在測試數據的每個時間步內更新模型,因為我們已知測試數據中的新觀察值(我們將這種方法稱為動態方法)。

在本教程中,我們為了方便採用固定方法,但是我們估計動態方法會得到更好的模型技能。

為了作出預測,我們能調用模型上的predict() 函數。這要求將一個三維NumPy數組作為語句。在這種情況下,它將是一個單值數組,前一時間步的觀察值。

predict() 函數返回一列預測,提供的每個輸入行對於一個預測。因為我們提供的是一個單一輸入,輸出將是單值的二維NumPy數組。

我們可以在下列這個名為forecast()的函數中發現這種行為。給定一個合適的模型,擬合模型(例1)時的一批數據和一行測試數據,該函數將從測試數據行中分離出輸入數據,對其進行改造,然後以單一浮點值的形式返回預測。

Python中使用LSTM網絡進行時間序列預測

在訓練期間,每個epoch結束後都對內部狀態進行重置。在進行預測時,我們將不會在預測中間重置內部狀態。事實上,誒嗎希望模型形成狀態,因為我們預測測試數據集的每個時間步。

這引發了這樣一個問題,在對測試數據集進行預測之前,對網絡而言怎樣才算作好的初始狀態。

在本教程中,我們將通過對訓練數據集的所有樣本進行預測來確定初始狀態。理論上,應設置好初始狀態來預測下一步。

我們現在已經完成所有步驟,可以為洗髮水銷量數據集擬合LSTM網絡模型並評測它的性能。

下一部分,我們將把所有這些步驟結合起來。

完成LSTM樣本

本節,我們將為洗髮水銷量數據集擬合一個LSTM模型並評測它的性能。

這將涉及結合前幾節中的所有內容,內容很多,所有讓我們回顧一下:

1. 從CSV文件中載入數據集。

2. 轉化數據集使其擬合LSTM模型,包括:

1. 將數據轉化為監督學習問題。

2. 將數據轉化為靜態。

3. 轉化數據使其處於-1至1的區間內。

3. 將有狀態的LSTM網絡模型與訓練數據進行擬合。

4. 根據測試數據評測靜態的LSTM模型。

5. 報告預測的性能。

一些關於樣本的注意事項:

  • 為了簡便起見,縮放和逆轉縮放行為已被移至函數scale()和invert_scale()中。

  • 為了確保測試數據的最小/最大值不影響模型,使用根據訓練數據擬合的縮放器對測試數據進行縮放。

  • 為了方便起見,數據轉化的順序調整為現將數據轉化為靜態,再轉化為監督學習問題,再進行縮放。

  • 為了方便起見,在將數據集分為訓練組和測試組之前對整個數據集進行差分。我們可以在步進驗證期間輕鬆收集觀察值並在之後步驟中對它們進行差分。為了獲得更好的可讀性,我決定不採用這種做法。

完整的例子如下所示:

Python中使用LSTM網絡進行時間序列預測

Python中使用LSTM網絡進行時間序列預測

Python中使用LSTM網絡進行時間序列預測

Python中使用LSTM網絡進行時間序列預測

運行示例,打印測試數據集12個月份中每一月份的預期和預測銷量。

示例還打印了所有預測值得均方根誤差。該模型顯示洗髮水月度銷量的均方根誤差為71.721,好於持續性模型得出的對應結果136.761。

在構建LSTM模型中使用了隨機數字,因此,你在運行該模型時可能得到不同的結果。我們在下一節中將對此進行進一步討論。

Python中使用LSTM網絡進行時間序列預測

同時生成了測試數據(藍色)對比預測數據(橙色)的線圖,為模型技能提供了背景。

Python中使用LSTM網絡進行時間序列預測

LSTM預測對比預期值的線圖

作為後注,你可以通過一個簡單的試驗幫助建立對測試工具和所有轉化和逆向轉化的信任。

標註出在步進驗證中擬合LSTM模型的線條:

Python中使用LSTM網絡進行時間序列預測

用下列語句代替它:

Python中使用LSTM網絡進行時間序列預測

這會構建出一個擁有完美預測技能的模型(例如預測出的預期結果和模型輸出一致)。

結果應如下所示,顯示LSTM模型是否能夠完美預測序列,逆向轉換和錯誤計算能正確顯示。

Python中使用LSTM網絡進行時間序列預測

得出穩定的結果

神經網絡的一個難題是初始條件不同,它們給出結果就不同。

一種解決辦法是修改Keras使用的隨機數種子值以確保結果可複製。另一種辦法是使用不同的實驗設置控制隨機初始條件。

想要了解更多關於機器學習隨機性的內容,請查看這篇文章:

  • 概括機器學習中的隨機性

  • http://machinelearningmastery.com/randomness-in-machine-learning/

我們可以多次重複上節中的實驗,然後取均方根誤差的平均值作為評估該結構預測未知數據的平均水平的一個指標。

這通常被稱為多次重複或多次重啟。

我們可以將模型擬合和步進驗證包含在固定重複次數的循環語句中。運行每次迭代得到的均方根誤差都能記錄下來。然後我們可以總結均方根誤差的分佈。

Python中使用LSTM網絡進行時間序列預測

數據準備步驟仍和之前一樣。

我們將使用30次重複,因為這足以提供一個良好的均方根誤差分值分佈。

完整的例子如下所示:

Python中使用LSTM網絡進行時間序列預測

Python中使用LSTM網絡進行時間序列預測

Python中使用LSTM網絡進行時間序列預測

Python中使用LSTM網絡進行時間序列預測

運行示例,打印每次重複的均方根誤差分值。運行到最後將給出收集的均方根誤差分值的總結統計數據。

我們能看到,洗髮水閱讀銷量的均值和標準層均方根誤差分值分別為138.491905和46.313783。

這是一個非常有用的結果,因為他表明,上文報告的結果可能是統計意義上的偶然時間。該實驗表明,此模型的平均性能可能大概和持續性模型一樣,都為136.761甚至還與後者相差少許。

這至少表明進一步的模型調試是必須的。

Python中使用LSTM網絡進行時間序列預測

下方所示的分佈生成了塊狀圖和須狀圖。這得出了數據的中值以及範圍和異常結果。

Python中使用LSTM網絡進行時間序列預測

LSTM重複實驗塊狀圖和須狀圖

這是一個可用來比較LSTM模型結構或者構建另一結構的實驗設置。

教程擴展

我們可考慮的教程擴展有很多。

  • 多步預測。該實驗設置可以在修改後預測下n個時間步,而不僅僅是下一時間步。而且還能實現更大的批量和更快的訓練。注意,由於模型未更新,儘管已知新的觀察值並且這些值都用作輸入變量,我們在本教程中執行的僅僅是一類12單步預測。

  • 調試LSTM模型。該模型未經調試;相反,模型結果結構只經過一些簡單的測試並且存在誤差。我認為,僅僅通過調試神經元數和訓練epoch就能獲得更好的結果,我還認為在測試中通過回調函數來提前終止運行可能有用。

  • 初始狀態實驗。通過預測所有訓練數據在進行預測之前初建系統是否有用還不得而知。理論上似乎是一種好辦法,但是需要進行驗證。而且,其他在預測前初建模型的方法也可能有用。

  • 更新模型。可以在步進驗證的每個時間步中更新模型。需要進行實驗來確定從新開始重擬合該模型或者通過另外幾個訓練epoch(包括新樣本)更新權值是否能獲得更好的結果。

  • 輸入時間步。LSTM 輸入支持單樣本採用多個時間步。需要進行實驗來確認將滯後觀察作為時間步是否能獲得更好結果。

  • 輸入滯後特徵。滯後觀察可作為輸入特徵。需要實驗確定包括滯後觀察是否能像AR(k)線性模型那樣帶來任何好處。

  • 輸入誤差序列。和MA(k)一樣,誤差序列經過構建(預測持續性模型的誤差)可作為附加的輸入特徵。需要進行實驗以觀察這是否能帶來任何好處。

  • 學習非靜態。LSTM網絡也許能學習數據中的趨勢並作出合理的預測。需要進行實驗以觀察LSTM是否能學習和有效預測留在數據中的暫時性獨立結構,如趨勢和季節性。

  • 對比無狀態。本教程使用的是有狀態LSTM。應將結果與無狀態LSTM結構作對比。

  • 統計學意義。多次重複實驗方案可以進一步延伸,加入統計學意義測試,證明均方根誤差結果的樣本群和不同結構間的差異是否具有統計學意義。

總 結

在本教程中,你學會了如何構建LSTM模型解決時間序列預測問題。

具體地說,你學會了:

  • 如何為構建LSTM模型準備時間序列數據。

  • 如何構建LSTM模型解決時間序列預測問題。

  • 如何使用性能良好的測試工具評測LSTM模型。

本文作者 Jason Brownlee 博士是一位學術研究員、作家、專業開發者和機器學習從業人員。他致力於幫助開發者開始學習並掌握機器學習應用。

本文由 AI100 編譯,轉載需得到本公眾號同意。


編譯:AI100

原文鏈接:http://machinelearningmastery.com/time-series-forecasting-long-short-term-memory-network-python/


關於AI100

AI100致力於打造人工智能技術和產業社區。為人工智能開發者提供信息和技術交流的平臺;為人工智能創業者提供行業數據及智能應用的商業場景;為行業提供人工智能化的技術商業應用。請快快關注AI100公眾號吧!

相關推薦

推薦中...