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 features và rolling 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:
pip install sktimeLoad dữ liệu:
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)
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:
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/1949lag_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:
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.
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ển | Cá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, SARIMA | Decision 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.


