Dự báo chuỗi thời gian với mô hình cây quyết định

Dự báo chuỗi thời gian với mô hình cây quyết định

Dự báo chuỗi thời gian với mô hình cây quyết định

Khi nhắc đến dự báo chuỗi thời gian (time series forecasting), nhiều người sẽ nghĩ ngay đến ARIMA, SARIMA hay Prophet. Tuy nhiên, các mô hình machine learning truyền thống như Decision Tree, Random Forest, Gradient Boosting cũng có thể dự báo rất tốt — nếu chúng ta biết cách “biến hình” dữ liệu chuỗi thời gian thành dạng bảng (tabular data).

Trong bài viết này, bạn sẽ học cách:

  • Biến chuỗi thời gian thành bài toán supervised learning
  • Tạo lag featuresrolling statistics
  • Chia tập train/test theo thời gian đúng cách
  • Huấn luyện mô hình cây quyết định
  • Đánh giá sai số bằng MAE
  • Tránh data leakage

Chúng ta bắt đầu ngay.

Ý tưởng chính: Biến time series thành dữ liệu có cấu trúc

Mô hình cây quyết định không hiểu khái niệm “thời gian”. Nó chỉ hiểu các cột đặc trưng (features).

Vì vậy, ta cần:

  • Tạo các đặc trưng từ giá trị quá khứ (lag features)
  • Tạo thống kê trượt (rolling mean, rolling std)
  • Biến mọi thứ thành DataFrame dạng bảng

Sau đó, bài toán dự báo trở thành một bài toán regression thông thường.

Dataset sử dụng

Chúng ta dùng bộ dữ liệu số lượng hành khách hàng tháng, có sẵn trong thư viện sktime.

Dữ liệu này gồm:

  • Số hành khách mỗi tháng
  • Từ năm 1949 đến 1960
  • Chuỗi thời gian đơn biến (univariate)

Cài đặt và load dữ liệu

Nếu chưa cài đặt:

PowerShell
pip install sktime

Load dữ liệu:

Python
import pandas as pd
from sktime.datasets import load_airline

# Tải dữ liệu
chuoi_hanh_khach = load_airline()

print(chuoi_hanh_khach.head())

Biến chuoi_hanh_khach là một pandas.Series có index dạng thời gian.

Tạo đặc trưng từ chuỗi thời gian

Ta sẽ tạo một hàm:

  • Sinh các lag features (ví dụ: 12 tháng trước)
  • Sinh rolling mean và rolling std
  • Tránh data leakage bằng cách .shift(1)
Python
def tao_dataframe_lag_rolling(series, so_lag=12, cua_so_rolling=3):
    """
    series: chuỗi thời gian (pandas Series)
    so_lag: số tháng quá khứ sử dụng làm đặc trưng
    cua_so_rolling: kích thước cửa sổ rolling
    """
    
    df = pd.DataFrame({"y": series})
    
    # Tạo lag features
    for lag in range(1, so_lag + 1):
        df[f"lag_{lag}"] = df["y"].shift(lag)
    
    # Rolling mean và std (không dùng giá trị hiện tại)
    df[f"rolling_mean_{cua_so_rolling}"] = (
        df["y"].shift(1).rolling(cua_so_rolling).mean()
    )
    
    df[f"rolling_std_{cua_so_rolling}"] = (
        df["y"].shift(1).rolling(cua_so_rolling).std()
    )
    
    return df.dropna()

Tạo dataset đặc trưng:

Python
df_features = tao_dataframe_lag_rolling(
    chuoi_hanh_khach,
    so_lag=12,
    cua_so_rolling=3
)

print(df_features.head())

Hiểu rõ những gì chúng ta vừa làm

Giả sử đang ở tháng 1/1950:

  • lag_1 = giá trị tháng 12/1949
  • lag_2 = tháng 11/1949
  • lag_12 = tháng 1/1949

Rolling mean 3 tháng:

  • Trung bình của 3 tháng gần nhất
  • Không bao gồm tháng hiện tại (nhờ .shift(1))

⚠ Đây là bước cực kỳ quan trọng để tránh look-ahead bias (data leakage).

Chia tập train/test đúng cách

Với chuỗi thời gian, KHÔNG được shuffle.

Ta chia theo thứ tự thời gian:

Python
ti_le_train = 0.8
kich_thuoc_train = int(len(df_features) * ti_le_train)

tap_train = df_features.iloc[:kich_thuoc_train]
tap_test = df_features.iloc[kich_thuoc_train:]

X_train = tap_train.drop("y", axis=1)
y_train = tap_train["y"]

X_test = tap_test.drop("y", axis=1)
y_test = tap_test["y"]

Huấn luyện Decision Tree Regressor

Chúng ta sử dụng DecisionTreeRegressor từ scikit-learn.

Python
from sklearn.tree import DecisionTreeRegressor
from sklearn.metrics import mean_absolute_error

# Khởi tạo mô hình
mo_hinh_cay = DecisionTreeRegressor(
    max_depth=5,
    random_state=42
)

# Huấn luyện
mo_hinh_cay.fit(X_train, y_train)

# Dự báo
du_bao = mo_hinh_cay.predict(X_test)

# Đánh giá
mae = mean_absolute_error(y_test, du_bao)

print("Sai số MAE:", mae)

Trong một lần chạy, MAE khoảng ~45 hành khách.

Với dữ liệu có quy mô vài trăm hành khách mỗi tháng, mức sai số này là tương đối ổn cho một mô hình cơ bản.

Làm sao để cải thiện?

Bạn có thể:

  • Dùng Random Forest
  • Dùng Gradient Boosting / XGBoost
  • Tăng số lag
  • Thêm feature mùa vụ (tháng trong năm)
  • Thêm feature xu hướng (trend)
  • Dùng cross-validation dạng TimeSeriesSplit

Khác biệt so với phương pháp truyền thống

Phương pháp cổ điểnCách tiếp cận ML
Dựa hoàn toàn vào quá khứ của biến đóDựa vào các feature được tạo
ARIMA, SARIMADecision Tree, Random Forest
Cấu trúc thống kêHọc quan hệ phi tuyến

Trong thực tế, cách tốt nhất là:

👉 Kết hợp cả mô hình thống kê và mô hình ML
👉 Hoặc dùng ensemble để tăng độ ổn định

Khi nào nên dùng tree-based models cho time series?

Phù hợp khi:

  • Dữ liệu có nhiều feature bổ sung
  • Dữ liệu có yếu tố phi tuyến
  • Muốn kết hợp nhiều biến ngoại sinh (exogenous variables)
  • Muốn pipeline ML thống nhất

Không phù hợp khi:

  • Chuỗi quá ngắn
  • Không có đủ dữ liệu quá khứ
  • Cần dự báo dài hạn nhiều bước mà không có chiến lược recursive phù hợp

Tổng kết

Trong bài viết này, bạn đã học được cách:

  • Biến chuỗi thời gian thành bài toán supervised learning
  • Tạo lag features và rolling statistics
  • Tránh data leakage
  • Huấn luyện Decision Tree cho bài toán dự báo
  • Đánh giá bằng MAE

Điểm mấu chốt:

Mô hình cây không hiểu “thời gian”.
Nhưng nếu bạn biến thời gian thành feature, nó sẽ học được quy luật.

Leave a Reply