時間序列預測在各個領域都有廣泛應用,從金融市場預測到天氣預報,準確的時序資料預測至關重要。深度學習模型,特別是 BiTCN 和 RNN,為處理時序資料提供了強大的工具。BiTCN 透過雙向卷積操作捕捉時間依賴關係,而 RNN 則利用隱藏狀態的迭代計算來處理序列資訊。兩種模型各有優劣,BiTCN 更擅長捕捉區域性時間模式,而 RNN 則更適合處理長期依賴關係。選擇合適的模型取決於資料的特性和預測目標。例如,對於具有明顯週期性規律的資料,BiTCN 可能更有效;而對於需要考慮長期趨勢的資料,RNN 則更為合適。在實際應用中,需要根據具體問題選擇合適的模型和引數,並進行充分的實驗和驗證,才能獲得最佳的預測效果。模型的效能評估也至關重要,常用的指標包括均方誤差、均方根誤差、平均絕對百分比誤差等。透過這些指標,可以客觀地衡量模型的預測精確度,並為模型的改進提供依據。此外,視覺化結果分析可以更直觀地展現模型的預測效果,並幫助我們理解模型的行為。

時序資料的神經網路

時序資料的預測問題一直是機器學習與人工智慧領域中的重要課題。透過神經網路來處理時序資料,能夠有效地捕捉資料中的時間依賴關係,從而提升預測的準確性。在這一章節中,玄貓將探討如何利用雙向時間卷積網路(BiTCN)來進行時序資料的預測,並透過具體的案例來說明其實際應用。

雙向時間卷積網路(BiTCN)

BiTCN 是時間卷積網路(TCN)的延伸,主要透過在正向和反向兩個方向上應用卷積操作來處理時序資料。這樣的設計使得 BiTCN 能夠同時考慮到過去和未來的資訊,從而提升模型的預測能力。

技術概述

正向和反向處理

BiTCN 的核心思想是將 TCN 模型擴充套件為雙向處理。具體來說,BiTCN 在正向和反向兩個方向上都進行卷積操作。正向處理從資料序列的起點開始,逐步計算到終點;而反向處理則從終點開始,逐步計算到起點。

正向處理的輸出如下: [ y_t = \sum_{k=0}^{K-1} w_{k} x_{t-k} + b ]

反向處理的輸出如下: [ y_t = \sum_{k=0}^{K-1} w_{k} x_{t+(k)} + b ]

合併正向和反向輸出

正向和反向處理的輸出結果會被合併,通常透過逐元素相加的方式來獲得最終輸出。這樣的設計能夠充分利用過去和未來的資訊,從而提升模型的預測能力。

此圖示展示了使用三層堆積疊的 TCN 層來實作對預測點 ( t_0+1 ) 的條件預測。這些層使用正向和反向稀疏卷積,核大小為 3,稀疏係數為 ( 2^i - 1 ):

  graph LR
    A[Input Sequence] --> B[Forward Convolution]
    A --> C[Backward Convolution]
    B --> D[Output Sequence]
    C --> D

BiTCN 的實際應用

接下來,玄貓將介紹如何將這些抽象概念轉化為實際的程式碼實作。首先,我們需要匯入必要的函式庫:

import pandas as pd
import numpy as np
from sklearn.metrics import mean_squared_error, mean_absolute_percentage_error, r2_score
from IPython.display import display, Markdown
import matplotlib.pyplot as plt
from neuralforecast import NeuralForecast
from neuralforecast.models import BiTCN
from ray import tune
from neuralforecast.losses.pytorch import GMM, DistributionLoss
from neuralforecast.tsdataset import TimeSeriesDataset

接著,我們載入包含 12 年月度航空乘客資料的資料集:

from neuralforecast.utils import AirPassengersDF as Y_df

# 分割訓練集與測試集
Y_train_df = Y_df[Y_df.ds <= '1959-12-31']
Y_test_df = Y_df[Y_df.ds > '1959-12-31']

# 建立 TimeSeriesDataset 物件
dataset, *_ = TimeSeriesDataset.from_df(Y_train_df)

接下來初始化並訓練 BiTCN 模型:

horizon = 12

fcst = NeuralForecast(
    models=[
        BiTCN(
            h=horizon,
            input_size=12,
            loss=GMM(n_components=7, return_params=True, level=[80, 90]),
            max_steps=100,
            scaler_type='standard',
            hist_exog_list=None,
        ),
    ],
    freq='M'
)

fcst.fit(df=Y_train_df)

預測與評估

完成模型訓練後,我們可以進行預測並評估模型的效能:

# 預測未來一個預測週期(horizon)內的值
y_hat = fcst.predict()
y_hat.set_index('ds', inplace=True)

# 輸出預測結果
y_hat.head()

評估模型效能:

# 評估模型效能指標
def calculate_error_metrics(y_true, y_pred):
    mse = mean_squared_error(y_true, y_pred)
    rmse = np.sqrt(mse)
    mape = mean_absolute_percentage_error(y_true, y_pred)
    r2 = r2_score(y_true, y_pred)
    adjusted_r2 = 1 - (1 - r2) * (len(y_true) - 1) / (len(y_true) - y_true.shape[1] - 1)
    return mse, rmse, mape, r2, adjusted_r2

error_metrics = calculate_error_metrics(Y_test_df[['y']], y_hat[['BiTCN']])
print(f"MSE: {error_metrics[0]}")
print(f"RMSE: {error_metrics[1]}")
print(f"MAPE: {error_metrics[2]}")
print(f"R²: {error_metrics[3]}")
print(f"Adjusted R²: {error_metrics[4]}")

最後,我們視覺化預測結果:

# 設定索引為日期欄位
Y_train_df.set_index('ds', inplace=True)
Y_test_df.set_index('ds', inplace=True)

plt.figure(figsize=(20, 3))
plt.plot(Y_train_df["y"], label="過去時序值")
plt.plot(y_hat["BiTCN"], label="預測值")
plt.plot(Y_test_df["y"], label="真實時序值")
plt.title('航空乘客資料預測', fontsize=10)
plt.ylabel('月度乘客數', fontsize=10)
plt.xlabel('時間戳 [t]', fontsize=10)
plt.legend()
plt.show()

BiTCN 模型分析

從上述視覺化結果可以看出,BiTCN 模型預測出來的航空乘客數並不接近真實數值。這表明在某些情況下,BiTCN 模型可能不如單向 TCN 模型表現得好。這可能是由於過擬合、模型複雜度或資料集特性等因素所導致。

迴歸神經網路(RNN)與時間序列預測

在時間序列預測中,迴歸神經網路(Recurrent Neural Network, RNN)是一種常見且強大的工具。RNN 的架構與其他深度神經網路相似,但它們在資訊傳遞方式上有所不同。以下將探討 RNN 的工作原理及其應用。

資訊傳遞的差異

RNN 的核心理念在於其隱藏狀態(hidden state)的迭代計算過程。對於輸入時間序列 ( x = {x_1, x_2, \ldots, x_n} ),RNN 會計算隱藏狀態序列 ( h = {h_1, h_2, \ldots, h_n} ) 以及輸出序列 ( y = {y_1, y_2, \ldots, y_n} )。

RNN 的核心公式如下:

[ h_t = f(W_{hx} x_t + W_{hh} h_{t-1} + b_h) ] [ y_t = g(W_{yh} h_t + b_y) ]

其中:

  • ( W_{hx} ) 是輸入到隱藏層的權重矩陣。
  • ( W_{hh} ) 是隱藏層到隱藏層的權重矩陣。
  • ( W_{yh} ) 是隱藏層到輸出層的權重矩陣。

圖示解釋

此圖示展示了 RNN 的展開結構,顯示瞭如何透過迭代處理時間序列資料。

  graph TD;
    A[Input x1] --> B[Hidden h1];
    B --> C[Output y1];
    D[Input x2] --> E[Hidden h2];
    E --> F[Output y2];
    B --> E;

內容解密:

上述圖示展示了 RNN 在不同時間步驟中的結構。每個時間步驟都會接收一個輸入並生成一個隱藏狀態和一個輸出。隱藏狀態會傳遞給下一個時間步驟,這使得 RNN 能夠記住之前的資訊並用於當前的計算。

RNN 的挑戰

儘管 RNN 在處理時間序列資料時表現出色,但它仍面臨一些挑戰:

  • 梯度爆炸與消失:這些現象發生在權重值過大或過小時,導致學習過程中斷。
  • 長距離依賴問題:RNN 在處理長時間步驟之間的依賴關係時表現不佳。

為了克服這些問題,研究者們提出了長短期記憶網路(Long Short-Term Memory, LSTM),這將在後續章節中詳細討論。

RNN 的實際應用

接下來,玄貓將展示如何使用 Python 實作一個簡單的 RNN 模型來進行時間序列預測。

import pandas as pd
import numpy as np
from sklearn.metrics import mean_squared_error, mean_absolute_percentage_error, r2_score
import matplotlib.pyplot as plt
from neuralforecast import NeuralForecast
from neuralforecast.models import RNN
from neuralforecast.tsdataset import TimeSeriesDataset

# 載入資料集
from neuralforecast.utils import AirPassengersDF as Y_df
Y_train_df = Y_df[Y_df.ds <= '1959-12-31']
Y_test_df = Y_df[Y_df.ds > '1959-12-31']

# 建立資料集
dataset, *_ = TimeSeriesDataset.from_df(Y_train_df)

# 初始化並訓練模型
horizon = 12
fcst = NeuralForecast(
    models=[RNN(
        h=horizon,
        input_size=-1,
        inference_input_size=24,
        loss=MQLoss(level=[80, 90]),
        scaler_type='robust',
        encoder_n_layers=2,
        encoder_hidden_size=128,
        context_size=10,
        decoder_hidden_size=128,
        decoder_layers=2,
        max_steps=300,
    )],
    freq='M'
)
fcst.fit(df=Y_train_df, val_size=12)

# 預測未來值
y_hat = fcst.predict()
y_hat.set_index('ds', inplace=True)
print(y_hat.head())

內容解密:

上述程式碼展示瞭如何使用 NeuralForecast 函式庫來載入資料、初始化並訓練一個 RNN 模型。首先,從 AirPassengersDF 中載入資料並分割為訓練集和測試集。接著,建立一個 RNN 模型並進行訓練。最後,使用訓練好的模型進行預測,並顯示預測結果。

評估模型效能

評估模型效能是確保模型有效性的重要步驟。以下是一些常見的評估指標:

# 評估模型效能
def calculate_error_metrics(y_true, y_pred):
    mse = mean_squared_error(y_true, y_pred)
    rmse = np.sqrt(mse)
    mape = mean_absolute_percentage_error(y_true, y_pred)
    r2 = r2_score(y_true, y_pred)
    adjusted_r2 = 1 - (1 - r2) * (len(y_true) - 1) / (len(y_true) - len(y_pred.columns) - 1)
    return mse, rmse, mape, r2, adjusted_r2

error_metrics = calculate_error_metrics(Y_test_df[['y']], y_hat[['RNN-median']])
print(error_metrics)

內容解密:

上述程式碼定義了一個函式 calculate_error_metrics 用於計算模型的各種評估指標,包括均方誤差(MSE)、均方根誤差(RMSE)、平均絕對百分比誤差(MAPE)以及決定係數(r²)。這些指標有助於量化模型的預測效能。

視覺化結果

最後,我們可以透過視覺化來直觀地觀察模型的預測結果與真實值之間的差異。

# 視覺化結果
Y_train_df.set_index('ds', inplace=True)
Y_test_df.set_index('ds', inplace=True)

plt.figure(figsize=(20, 3))
plt.plot(Y_train_df["y"], label="過去時間序列值")
plt.plot(y_hat[['RNN-median']], label="預測")
plt.plot(Y_test_df["y"], label="真實時間序列值")
plt.title('AirPassengers 預測', fontsize=10)
plt.ylabel('每月乘客數', fontsize=10)
plt.xlabel('時刻 [t]', fontsize=10)
plt.legend()
plt.show()

內容解密:

上述程式碼展示瞭如何使用 Matplotlib 函式庫來視覺化模型的預測結果。透過繪製過去的真實值、預測值和測試集中的真實值,我們可以直觀地觀察到模型預測的準確性。

總結來說,RNN 是一種強大的工具用於時間序列預測,但它也面臨一些挑戰。透過適當的技術選擇和評估,我們可以提升模型的效能並應用於實際問題中。