TimesFM 作為一個根據解碼器架構的基礎模型,能有效處理單變數和多變數時序預測問題。在單變數案例中,以航班乘客資料為例,我們首先匯入必要的 Python 模組,接著載入和準備資料,並將資料集分割成訓練集和測試集。然後,組態 TimesFM 模型,設定關鍵引數如上下文長度、預測範圍、輸入和輸出片段長度、模型層數和維度等。載入預訓練模型後,使用訓練資料生成預測結果,並計算均方誤差、均方根誤差、平均絕對百分比誤差和決定係數等指標評估模型效能。最後,將預測結果視覺化,以便直觀比較真實值與預測值。多變數案例則以電價預測為例,同樣需要資料準備和模型組態。建立資料管道,以批次方式處理資料,並考慮多個相關變數,如發電預測、系統負載和星期幾等。在模型組態方面,同樣需要設定上下文長度和預測範圍等引數。值得注意的是,多變數案例中需要處理更複雜的資料關係,模型的訓練和評估也更具挑戰性。
時序預測的創新方法:TimesFM的應用
時序預測的基本概念
時序預測(Time Series Forecasting)是一項將歷史資料作為依據,預測未來資料趨勢的技術。這在各種領域中都有廣泛應用,例如金融市場分析、供應鏈管理、能源需求預測等。TimesFM 是一種根據解碼器架構的基礎模型,能夠在單變數和多變數情境下進行高效的時序預測。以下是 TimesFM 在單變數和多變數情境下的實作和分析。
匯入所需模組
首先,我們需要匯入一些必要的 Python 模組來進行資料處理和建模。
import numpy as np
import pandas as pd
import timesfm
import matplotlib.pyplot as plt
from sklearn.metrics import mean_squared_error, mean_absolute_percentage_error, r2_score
import os
# 設定環境變數以避免使用特定硬體加速
os.environ['XLA_PYTHON_CLIENT_PREALLOCATE'] = 'false'
os.environ['JAX_PMAP_USE_TENSORSTORE'] = 'false'
單變數時序預測
接下來我們考慮一個單變數的時間序列案例——航班乘客資料。這個資料集包含了 12 年的月度航班乘客資料。
資料準備與載入
# 使用 pandas 讀取 CSV 資料並轉換日期格式
Y_df = pd.read_csv('AirPassengersDataset.csv')
Y_df['ds'] = pd.to_datetime(Y_df['ds'])
Y_df = Y_df.reset_index(drop=True)
Y_df.head()
uniqueId ds y
0 1 1949-01-31 112
1 1 1949-02-28 118
2 1 1949-03-31 132
3 1 1949-04-30 129
4 1 1949-05-31 121
資料集分割
將資料集分割為訓練集和測試集。
# 分割資料集為訓練和測試集
Y_train_df = Y_df[Y_df.ds <= '1959-12-31']
Y_test_df = Y_df[Y_df.ds > '1959-12-31']
建立與組態 TimesFM 模型
組態模型使用 CPU。
# 組態使用 CPU 作為後端計算資源
timesfm_backend = "cpu"
from jax._src import config
config.update("jax_platforms", {"cpu": "cpu", "gpu": "cuda", "tpu": ""}[timesfm_backend])
初始化 TimesFM 模型並定義引數。
# 初始化 TimesFM 模型並定義引數
tfm = timesfm.TimesFm(
context_len=128,
horizon_len=12,
input_patch_len=32,
output_patch_len=128,
num_layers=20,
model_dims=1280,
backend=timesfm_backend,
)
模型引數解釋
這裡我們需要理解一些關鍵引數:
context_len: 模型使用的歷史資料視窗長度。horizon_len: 預測的未來時間長度。input_patch_len: 輸入資料片段長度。output_patch_len: 輸出資料片段長度。num_layers: 模型中的層數。model_dims: 每層的維度。
載入預訓練模型
從檢查點載入預訓練模型。
# 載入預訓練模型
tfm.load_from_checkpoint(repo_id="google/timesfm-1.0-200m")
生成預測結果
使用 TimesFM 模型在訓練資料上進行預測。
# 生成預測結果
timesfm_forecast = tfm.forecast_on_df(
inputs=Y_train_df,
freq="MS",
value_name="y",
num_jobs=-1,
)
timesfm_forecast = timesfm_forecast[["ds","timesfm"]]
timesfm_forecast.head()
ds timesfm
0 1960-01-01 410.117157
1 1960-02-01 381.569823
2 1960-03-01 445.656927
3 1960-04-01 432.986388
4 1960-05-01 455.837586
評估模型效能
計算錯誤評估指標,以瞭解模型在測試資料上的表現。
# 評估模型效能並計算錯誤指標
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 = r2 - ( (len(y_true) - len(y_pred)) / (len(y_true) - len(y_pred) - len(tfm.params)) ) * (r2 - r)
return {
"MSE": mse,
"RMSE": rmse,
"MAPE": mape,
"R^2": r2,
"Adjusted R^2": adjusted_r2,
}
error_metrics = calculate_error_metrics(Y_test_df[['y']], timesfm_forecast['timesfm'])
print(error_metrics)
{'MSE': 777.6665687573778, 'RMSE': 27.8876, 'MAPE': 0.456, 'R^2': 0.86, 'Adjusted R^2': -}
預測結果視覺化
最後,我們將預測結果進行視覺化,以便更直觀地比較真實值與預測值。
# 改變索引並繪製圖表以比較真實值與預測值
Y_train_df.set_index('ds', inplace=True)
timesfm_forecast.set_index('ds', inplace=True)
Y_test_df.set_index('ds', inplace=True)
plt.figure(figsize=(20,5))
y_past = Y_train_df["y"][-50:]
y_pred = timesfm_forecast['timesfm']
y_test = Y_test_df["y"]
plt.plot(y_past, label="過去的時間序列值")
plt.plot(timesfm_forecast, label="預測")
plt.plot(y_test, label="實際時間序列值")
plt.title('航班乘客數預測', fontsize=15)
plt.ylabel('月度乘客人數', fontsize=15)
plt.xlabel('時間戳 [t]', fontsize=15)
plt.tight_layout()
plt.xticks(rotation=90)
plt.legend()
plt.show()
內容解密:
這段程式碼首先將訓練集、預測結果和真實值設定為索引,並繪製出比較圖表。這裡我們可以看到過去的真實值、模型生成的預測值以及未來的真實值。這樣可以直觀地看出模型的表現如何,是否能夠準確地捕捉到未來趨勢。圖表中的標籤和轉動角度使得視覺化更加清晰且易於理解。這些步驟有助於我們評估模型在單變數情境下的有效性,並為後續的多變數情境提供參考。
與多變數情境相似地區別於單變數情境
多變數時序預測(Multivariate Time Series Forecasting)則是同時考慮多個相關變數之間的關係進行預測。這在現實中的應用場景更為複雜但也更接近真實世界中的問題。以下是一個關於電價預測的案例:
資料準備與載入
這裡我們使用的是電價預測相關資料。
df = pd.read_csv('EPF_FR_BE.csv')
df[df['unique_id'] == 'FR'].head()
unique_id ds y gen_forecast systemload week_day \
FR FR FR ...
FR FR ...
建立資料管道
接著我們要建立資料管道以處理批次資料。
from collections import defaultdict
def get_batched_data_fn(batch_size: int = 64, context_len: int = 64, horizon_len: int = 3):
examples = defaultdict(list)
for country in ("FR", "BE"):
sub_df = df[df["unique_id"] == country]
for start in range(horizon_len + context_len):
examples["country"].append(country)
examples["inputs"].append(sub_df["y"][start:(start + context_len)].tolist())
examples["gen_forecast"].append(sub_df["gen_forecast"][start:(start + context_len + horizon_len)].tolist())
examples["week_day"].append(sub_df["week_day"][start:(start + context_len + horizon_len)].tolist())
examples["outputs"].append(sub_df["y"][start + context_len:(start + context_len + horizon_len)].tolist())
def data_fn():
for i in range(len(examples[list(examples.keys())[0]])):
yield {k: v[i:i + batch_size] for k, v in examples.items()}
return data_fn
batched_data_fn = get_batched_data_fn()
內容解密:
在這段程式碼中,我們首先建立了一個預設字典 examples 用來儲存每個國家(例如法國和比利時)不同批次中需要用到的資料。接著透過迴圈處理每個國家及其對應的時間序列資料。對於每個國家,我們會取出一定長度(context_len) 的歷史資料作為輸入,並且取出較長的一段資料作為生成器與其他相關特徵(例如天氣或其他經濟指標)。最後透過建立一個 data_fn 函式來生成資料批次,方便後續用於訓練或評估模型。這樣可以確保每次取得的是固定長度且具有一致性的一批資料,避免了每次隨機取得不同長度資料可能帶來的一致性問題。
組態 TimesFM 模型
再次組態使用 CPU 作為計算資源。
timesfm_backend = "cpu"
from jax._src import config
config.update("jax_platforms", {"cpu": "cpu", "gpu": "cuda", "tpu": ""}[timesfm_backend])
初始化 TimesFM 模型並定義引數:
model = timesfm.TimesFm(
context_len=context_length,
horizon_len=horizon_length,
)
內容解密:
在這段程式碼中,首先更新了 Jax 的組態以確保它使用正確的後端計算資源(CPU),這樣可以避免不必要地消耗 GPU 或 TPU 資源。然後我們初始化了 TimesFM 模型並定義了其引數,其中包括了歷史資料視窗長度 (context_length) 和未來要預測的時間視窗長度 (horizon_length)。這些引數決定了模型如何處理和學習時間序列資料。
構建檢查點檔案以儲存或還原模型狀態:
由於進行深層學習相關工作需花費大量時間及資源,建議進行檢查點檔案功能能夠節省大量時間與成本。 因篇幅所限將此部分省略。