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


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

原文使用 python 實現模型,這里是用 R

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

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

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

文章的主要內容:

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

問題描述

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

下載鏈接:international-airline-passengers.csv

多層感知機回歸

時間序列預測中最簡單的思路之一便是尋找當前和過去數據(\(X_t, X_{t-1}, \dots\))與未來數據($ X_{t+1}$)之間的關系,這種關系通常會表示成為一個回歸問題。

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

首先,加載相關 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:一方作為另外一方的“特征工程”手段。

擴展閱讀


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM