基於 Keras 用深度學習預測時間序列

本文主要參考了 Jason Brownlee 的博文 Time Series Prediction With Deep Learning in Kerasgit

原文使用 python 實現模型,這裏是用 R網絡

基於 Keras 用深度學習預測時間序列

時間序列預測一直以來是機器學習中的一個難題。app

在本篇文章中,將介紹如何在 R 中使用 keras 深度學習包構建神經網絡模型實現時間序列預測。框架

文章的主要內容:機器學習

  • 如何將時間序列預測問題表示成爲一個迴歸問題,並創建對應的神經網絡模型。
  • 如何使用滯後時間的數據實現時間序列預測,並創建對應的神經網絡模型。

問題描述

「航班旅客數據」是一個經常使用的時間序列數據集,該數據包含了 1949 至 1960 年 12 年間的月度旅客數據,共有 144 個觀測值。學習

下載連接:international-airline-passengers.csv測試

多層感知機迴歸

時間序列預測中最簡單的思路之一即是尋找當前和過去數據(\(X_t, X_{t-1}, \dots\))與將來數據($ X_{t+1}$)之間的關係,這種關係一般會表示成爲一個迴歸問題。lua

下面着手將時間序列預測問題表示成一個迴歸問題,並創建神經網絡模型用於預測。spa

首先,加載相關 R 包。

library(keras)
library(dplyr)
library(ggplot2)
library(ggthemes)
library(lubridate)

神經網絡模型在訓練時存在必定的隨機性,因此要爲計算統一隨機數環境

set.seed(7)

畫出總體數據的曲線圖,對問題有一個直觀的認識。

dataframe <- read.csv(
    'international-airline-passengers.csv')

dataframe$Month <- paste0(dataframe$Month,'-01') %>%
    ymd()

ggplot(
    data = dataframe,
    mapping = aes(
        x = Month,
        y = passengers)) +
    geom_line() +
    geom_point() +
    theme_economist() +
    scale_color_economist()

圖1

圖1

很顯然,數據體現出「季節性」,同時存在線性增加和波動水平增大的趨勢。

將數據集分紅兩部分:訓練集和測試集,比例分別佔數據集的 2/3 和 1/3。

dataset <- dataframe$passengers

train_size <- as.integer(length(dataset) * 0.67)
test_size <- length(dataset) - train_size

train <- dataset[1:train_size]
test <- dataset[(train_size + 1):length(dataset)]

cat(length(train), length(test))
96 48

爲訓練神經網絡對數據作預處理,用數據構造出兩個矩陣,分別是「歷史數據」(做爲預測因子)和「將來數據」(做爲預測目標)。這裏用最近一個月的歷史數據作預測。

create_dataset <- function(dataset,
                           look_back = 1)
{
    l <- length(dataset)
    dataX <- matrix(nrow = l - look_back, ncol = look_back)

    for (i in 1:ncol(dataX))
    {
        dataX[, i] <- dataset[i:(l - look_back + i - 1)]
    }

    dataY <- matrix(
        data = dataset[(look_back + 1):l],
        ncol = 1)

    return(
        list(
            dataX = dataX,
            dataY = dataY))
}

look_back <- 1
trainXY <- create_dataset(train, look_back)
testXY <-  create_dataset(test, look_back)

下面構造神經網絡的框架結構並用處理過的訓練數據訓練。

model <- keras_model_sequential()

model %>%
    layer_dense(
        units = 8,
        input_shape = c(look_back),
        activation = 'relu') %>%
    layer_dense(units = 1) %>%
    compile(
        loss = 'mean_squared_error',
        optimizer = 'adam') %>%
    fit(
        trainXY$dataX,
        trainXY$dataY,
        epochs = 200,
        batch_size = 2,
        verbose = 2)

訓練結果以下。

trainScore <- model %>%
    evaluate(
        trainXY$dataX,
        trainXY$dataY,
        verbose = 0)

testScore <- model %>%
    evaluate(
        testXY$dataX,
        testXY$dataY,
        verbose = 0)

sprintf(
    'Train Score: %.2f MSE (%.2f RMSE)',
    trainScore,
    sqrt(trainScore))

sprintf(
    'Test Score: %.2f MSE (%.2f RMSE)',
    testScore,
    sqrt(testScore))
[1] "Train Score: 538.50 MSE (23.21 RMSE)"
[1] "Test Score: 2342.33 MSE (48.40 RMSE)"

把訓練數據的擬合值、測試數據的預測值和原始數據畫在一塊兒。

trainPredict <- model %>%
    predict(trainXY$dataX)
testPredict <- model %>%
    predict(testXY$dataX)

df <- data.frame(
    index = 1:length(dataset),
    value = dataset,
    type = 'raw') %>%
    rbind(
        data.frame(
            index = 1:length(trainPredict) + look_back,
            value = trainPredict,
            type = 'train')) %>%
    rbind(
        data.frame(
            index = 1:length(testPredict) + look_back + length(train),
            value = testPredict,
            type = 'test'))

ggplot(data = df) +
    geom_line(
        mapping = aes(
            x = index,
            y = value,
            color = type)) +
    geom_point(
        mapping = aes(
            x = index,
            y = value,
            color = type)) +
    geom_vline(
        xintercept = length(train) + 0.5) +
    theme_economist() +
    scale_color_economist()

圖2

圖2

黑線左邊是訓練部分,右邊是測試部分。

從圖中能夠看出,神經網絡模型抓住了數據線性增加和波動率逐漸增長的兩大趨勢,在不作數據轉換的前提下,這是經典的時間序列分析模型不容易作到的;可是極可能沒有識別出「季節性」的結構特色,由於訓練和預測結果和原始數據之間存在「平移錯位」。

多層感知機迴歸結合「窗口法」

前面的例子能夠看出,若是僅使用\(X_{t-1}\)來預測\(X_t\),很難讓神經網絡模型識別出「季節性」的結構特徵,所以有必要嘗試增長「窗口」寬度,使用更多的歷史數據(包含一個完整的週期)訓練模型。

下面將數 create_dataset 中的參數 look_back 設置爲 12,用來包含過去 1 年的歷史數據,從新訓練模型。

look_back <- 12
trainXY <- create_dataset(train, look_back)
testXY <-  create_dataset(test, look_back)

model <- keras_model_sequential()

model %>%
    layer_dense(
        units = 8,
        input_shape = c(look_back),
        activation = 'relu') %>%
    layer_dense(units = 1) %>%
    compile(
        loss = 'mean_squared_error',
        optimizer = 'adam') %>%
    fit(
        trainXY$dataX,
        trainXY$dataY,
        epochs = 200,
        batch_size = 2,
        verbose = 2)

trainScore <- model %>%
    evaluate(
        trainXY$dataX,
        trainXY$dataY,
        verbose = 0)

testScore <- model %>%
    evaluate(
        testXY$dataX,
        testXY$dataY,
        verbose = 0)

sprintf(
    'Train Score: %.2f MSE (%.2f RMSE)',
    trainScore,
    sqrt(trainScore))

sprintf(
    'Test Score: %.2f MSE (%.2f RMSE)',
    testScore,
    sqrt(testScore))

trainPredict <- model %>%
    predict(trainXY$dataX)
testPredict <- model %>%
    predict(testXY$dataX)

df <- data.frame(
    index = 1:length(dataset),
    value = dataset,
    type = 'raw') %>%
    rbind(
        data.frame(
            index = 1:length(trainPredict) + look_back,
            value = trainPredict,
            type = 'train')) %>%
    rbind(
        data.frame(
            index = 1:length(testPredict) + look_back + length(train),
            value = testPredict,
            type = 'test'))

ggplot(data = df) +
    geom_line(
        mapping = aes(
            x = index,
            y = value,
            color = type)) +
    geom_point(
        mapping = aes(
            x = index,
            y = value,
            color = type)) +
    geom_vline(
        xintercept = length(train) + 0.5) +
    theme_economist() +
    scale_color_economist()
[1] "Train Score: 157.17 MSE (12.54 RMSE)"
[1] "Test Score: 690.69 MSE (26.28 RMSE)"

圖3

圖3

新的模型基本上克服了「平移錯位」的現象,同時依然可以識別出線性增加和波動率逐漸增長的兩大趨勢。

改進方向

  • 目前對「季節性」的識別是靠增長曆史數據實現的,可否從神經網絡結構的方向入手。
  • 目前的模型中幾乎沒有用到「特徵工程」,如何用特徵工程表示數據中存在的主要趨勢和結構化特徵。
  • DNN + ARIMA:一方做爲另一方的「特徵工程」手段。

擴展閱讀

相關文章
相關標籤/搜索