ISLP §2.2 · pp. 37–49 · ★★★☆☆ · Bias-Variance · Bayes Classifier · KNN
Ý tưởng cốt lõi: Khi đánh giá mô hình, sai số trên dữ liệu đã huấn luyện (MSEtrain) thường thấp một cách đánh lừa. Điều thực sự quan trọng là sai số trên dữ liệu chưa từng thấy (MSEtest).
Công thức MSE huấn luyện (2.5):
Đo lường sai số trên chính dữ liệu đã dùng để huấn luyện. Dễ tính nhưng không phản ánh được khả năng tổng quát hóa.
Công thức MSE kiểm tra (2.6):
Đo sai số trên dữ liệu chưa từng thấy — đây mới là chỉ số thực sự quan trọng.
🎯 Ứng dụng thực tế: Trong giao dịch định lượng, nếu chỉ nhìn Sharpe ratio trong mẫu (tương đương MSEtrain thấp), mô hình sẽ overfit vào nhiễu lịch sử. Gerard & Mi (2019) phát hiện Sharpe ratio ngoài mẫu giảm trung bình >50%. Giải pháp: luôn dùng walk-forward validation.
核心概念:用訓練資料算出的誤差(MSEtrain)通常低得很騙人。真正要關心的是模型在沒見過的資料上的誤差(MSEtest)。公式:MSEtrain = (1/n) Σ (yᵢ − ŷ(xᵢ))²,只是計算已見過資料的誤差。MSEtest = E[(y₀ − ŷ(x₀))²] 才是真正衡量泛化能力的指標。量化交易的教訓:只看樣本內 Sharpe ratio 的基金,實戰表現平均衰退超過 50%。
Ba hàm thực khác nhau được mô phỏng, rồi so sánh hai mô hình: bậc 1 (tuyến tính, linh hoạt thấp) và bậc 10 (đa thức, linh hoạt cao). Code dưới đây tái hiện chính xác Hình 2.9–2.11 trong sách — chạy được trên Colab:
三種真實函數,用兩種模型(一次線性 vs 十次多項式)擬合。以下程式碼完整重現課本 Figure 2.9–2.11,可直接在 Colab 執行:
# === Google Drive + Colab 相容資料讀取 ===
import numpy as np
import pandas as pd
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.metrics import mean_squared_error
try:
from google.colab import drive
drive.mount('/content/drive')
DATA_PATH = '/content/drive/MyDrive/ISLP_data/'
except ImportError:
DATA_PATH = '/tmp/'
np.random.seed(42)
def simulate_data(n, f_true, sigma=1.0):
X = np.sort(np.random.uniform(0, 10, n))
eps = np.random.normal(0, sigma, n)
y = f_true(X) + eps
return X, y, f_true
# Ba hàm thực sự
f_nonlinear = lambda x: 0.5*x + 3*np.sin(x) + 0.2*x**2 - 5
f_near_linear = lambda x: 2 + 1.5*x + 0.1*np.sin(2*x)
f_highly_nonlinear = lambda x: 0.3*x**2 - x + 10*np.sin(x)
fig, axes = plt.subplots(1, 3, figsize=(18, 5))
titles = ['Hình 2.9: f phi tuyến vừa phải',
'Hình 2.10: f gần tuyến tính',
'Hình 2.11: f phi tuyến cao']
for ax, title, f_true in zip(axes, titles,
[f_nonlinear, f_near_linear, f_highly_nonlinear]):
X_train, y_train, _ = simulate_data(30, f_true, sigma=1.5)
X_test, y_test, _ = simulate_data(100, f_true, sigma=0)
x_range = np.linspace(0, 10, 200)
ax.plot(x_range, f_true(x_range), 'k-',
label='Đường thực sự', linewidth=2)
# Bậc 1
reg1 = LinearRegression()
reg1.fit(X_train.reshape(-1,1), y_train)
ax.plot(x_range, reg1.predict(x_range.reshape(-1,1)),
'b--', label='Bậc 1', linewidth=2)
# Bậc 10
poly10 = PolynomialFeatures(degree=10, include_bias=False)
Xp = poly10.fit_transform(X_train.reshape(-1,1))
reg10 = LinearRegression().fit(Xp, y_train)
xp = poly10.transform(x_range.reshape(-1,1))
ax.plot(x_range, reg10.predict(xp), 'g-',
label='Bậc 10', linewidth=2)
ax.scatter(X_train, y_train, s=30, c='red',
alpha=0.5, label='Dữ liệu huấn luyện')
ax.set_xlim(0, 10); ax.set_ylim(-5, 10)
ax.set_title(title); ax.legend()
plt.tight_layout(); plt.show()
Kỳ vọng của MSE kiểm tra có thể phân rã thành ba thành phần:
Đánh đổi: Mô hình càng linh hoạt → bias ↓ nhưng variance ↑. Mô hình càng đơn giản → variance ↓ nhưng bias ↑. Mục tiêu là tìm điểm cân bằng tối ưu.
測試 MSE 的期望值可分解為三項:E[(y₀−ŷ(x₀))²] = 方差 + 偏差² + 不可約誤差。偏差是模型太簡單造成的系統性錯誤(欠擬合);方差是模型對訓練資料微小變化過度敏感(過擬合);不可約誤差是資料本身的噪音。模型越靈活→偏差降但方差升,反之亦然,關鍵是找到最優平衡點。
Định nghĩa: Bộ phân loại Bayes gán mỗi quan sát vào lớp có xác suất hậu nghiệm cao nhất:
Đây là bộ phân loại tối ưu về mặt lý thuyết — không mô hình nào có thể đạt tỷ lệ lỗi thấp hơn tỷ lệ lỗi Bayes (Bayes error rate):
Trong thực tế: Ta không bao giờ biết phân phối thực của dữ liệu, nên không thể tính được bộ phân loại Bayes chính xác. Các mô hình thực tế (KNN, Logistic, LDA...) đều là những xấp xỉ của nó. Tỷ lệ lỗi Bayes là giới hạn dưới không thể vượt qua — giống như Var(ε) trong hồi quy.
貝氏分類器是理論上的最優分類器:將每個觀測值分配給後驗機率最高的類別,ŷ = argmaxⱼ P(Y=j|X=x₀)。其錯誤率(貝氏錯誤率)1−E[maxⱼ P(Y=j|X)] 是任何模型都無法突破的下限。實務上我們永遠不知道真實資料分布,所以 KNN、Logistic 等模型都是對貝氏分類器的近似。貝氏錯誤率就像是迴歸中的 Var(ε) —— 不可約的理論下限。
Cơ chế: Để dự đoán cho điểm x₀, KNN tìm K điểm gần nhất trong tập huấn luyện, rồi:
Ảnh hưởng của K:
Bài học quan trọng từ Hình 2.14–2.16: Khi K=1, lỗi huấn luyện = 0 (mỗi điểm tự dự đoán chính nó) nhưng lỗi kiểm tra cao. Khi K tăng, lỗi kiểm tra giảm đến điểm tối ưu rồi tăng trở lại — minh họa hoàn hảo cho đánh đổi bias-variance.
KNN 機制:對新點 x₀,找出訓練集中最近的 K 個鄰居。回歸取平均值,分類取多數決。K=1 極度靈活→低偏差高方差,決策邊界崎嶇;K 很大 平滑→高偏差低方差,邊界趨近線性。課本 Figure 2.14–2.16 的核心教訓:K=1 時訓練誤差=0(每個點自己預測自己)但測試誤差很高;隨著 K 增加測試誤差降到最佳點後回升——這是偏差-方差權衡的完美示範。
Code minh họa KNN phân loại — tái hiện Hình 2.14:
KNN 分類示範程式碼(重現 Figure 2.14):
# === KNN Phân loại: Hình 2.14 ===
from sklearn.neighbors import KNeighborsClassifier
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(1)
# Dữ liệu hai lớp giả lập
n = 100
X = np.random.randn(n, 2)
y = (X[:,0] + X[:,1] > 0).astype(int)
# Lưới quyết định
xx, yy = np.meshgrid(np.linspace(-3,3,200), np.linspace(-3,3,200))
fig, axes = plt.subplots(1, 2, figsize=(12,5))
for ax, K in zip(axes, [1, 15]):
knn = KNeighborsClassifier(n_neighbors=K).fit(X, y)
Z = knn.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
ax.contourf(xx, yy, Z, alpha=0.3, cmap='coolwarm')
ax.scatter(X[y==0,0], X[y==0,1], c='blue', label='Lớp 0', alpha=0.7)
ax.scatter(X[y==1,0], X[y==1,1], c='red', label='Lớp 1', alpha=0.7)
ax.set_title(f'KNN với K={K}')
ax.legend()
plt.tight_layout(); plt.show()
Bài tiếp theo: → §3.1 Hồi quy tuyến tính đơn
下一課:→ §3.1 簡單線性迴歸