目錄python
本文主要參考了 Jason Brownlee 的博文 Time Series Prediction With Deep Learning in Kerasgit
原文使用 python 實現模型,這裏是用 R網絡
時間序列預測一直以來是機器學習中的一個難題。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
很顯然,數據體現出「季節性」,同時存在線性增加和波動水平增大的趨勢。
將數據集分紅兩部分:訓練集和測試集,比例分別佔數據集的 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
黑線左邊是訓練部分,右邊是測試部分。
從圖中能夠看出,神經網絡模型抓住了數據線性增加和波動率逐漸增長的兩大趨勢,在不作數據轉換的前提下,這是經典的時間序列分析模型不容易作到的;可是極可能沒有識別出「季節性」的結構特色,由於訓練和預測結果和原始數據之間存在「平移錯位」。
前面的例子能夠看出,若是僅使用\(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
新的模型基本上克服了「平移錯位」的現象,同時依然可以識別出線性增加和波動率逐漸增長的兩大趨勢。