§4.4 生成模型分類法

LDA QDA Naive Bayes 貝氏定理 分類 · 難度 ★★★★ · 課本 p153–160
「與其直接畫一條線把兩類分開,不如先理解每一類『長什麼樣子』,再問新來的比較像誰。」

核心概念:生成 vs 判別

前面學的 logistic regression 是「判別模型」——直接學 \( \Pr(Y=k|X=x) \)(看到 x 時,它是哪一類?)。而 generative model 走另一條路:先學每一類的「樣子」\( f_k(x) \),再用貝氏定理反推分類機率。

生活化比喻:判別模型像你去餐廳,看一眼菜就判斷「這是川菜還是日料」。生成模型則是你先學「川菜的辣椒+花椒是長這樣」、「日料的擺盤+醬油是長這樣」,再問新菜比較像誰。

📚 理論基礎
貝氏定理:\( \Pr(Y=k|X=x) = \frac{\pi_k \cdot f_k(x)}{\sum_{l=1}^K \pi_l \cdot f_l(x)} \),其中 \( \pi_k \) 是先驗機率(該類在母體中的比例),\( f_k(x) \) 是該類的密度函數。

LDA:線性判別分析

LDA 假設所有類別共享同一個共變異數矩陣 \( \mathbf{\Sigma} \),但每個類有自己的平均 \( \boldsymbol{\mu}_k \)。這導致決策邊界是線性的。

\[ \delta_k(x) = x^T \mathbf{\Sigma}^{-1} \boldsymbol{\mu}_k - \frac{1}{2} \boldsymbol{\mu}_k^T \mathbf{\Sigma}^{-1} \boldsymbol{\mu}_k + \log \pi_k \]

分類時選 \( \delta_k(x) \) 最大的 k。當 \( p \)(變數數量)很大時,LDA 需要估計 \( p(p+1)/2 \) 個共變異數參數。

✅ 優點

參數少、不易 overfit;n 小時比 QDA 穩定;線性邊界可解釋

❌ 缺點

真實資料各類變異程度常不同;邊界只能是線性的;對 outliers 敏感

QDA:二次判別分析

QDA 放寬假設:每個類有自己的共變異數矩陣 \( \mathbf{\Sigma}_k \)。這讓決策邊界變成二次曲線,可以捕捉更複雜的分類邊界。

\[ \delta_k(x) = -\frac{1}{2}(x-\boldsymbol{\mu}_k)^T \mathbf{\Sigma}_k^{-1}(x-\boldsymbol{\mu}_k) - \frac{1}{2}\log|\mathbf{\Sigma}_k| + \log \pi_k \]

但代價是參數量暴增:QDA 要估 \( K \times p(p+1)/2 \) 個參數,樣本不夠時會 overfit。

Bias-Variance 取捨
LDA 假設 \( \mathbf{\Sigma}_1 = \mathbf{\Sigma}_2 = \cdots = \mathbf{\Sigma}_K \) → 高 bias(彈性低)但低 variance(參數少)。QDA 各類分別估 \( \mathbf{\Sigma}_k \) → 低 bias(彈性高)但高 variance(參數多)。
經驗法則:K 類多或 n 小 → LDA;各類明顯不同形狀 → QDA。

Naive Bayes

Naive Bayes 做一個大膽假設:給定類別後,所有 predictor 互相獨立。也就是 \( f_k(x) = \prod_{j=1}^p f_{kj}(x_j) \)。這個假設幾乎在所有真實資料中都是「錯的」,但實戰上效果出奇地好。

為什麼?因為即使它對 \( f_k(x) \) 的估計有偏差,分類時只在乎誰的 \( \delta_k(x) \) 最大,不求精確機率。bias-variance trade-off 再次發揮威力:引入偏差,換取極低 variance。

✅ 優點

極少參數(p≫n 時唯一可行的生成模型);可處理混合型態(連續+類別);訓練/預測超快

❌ 缺點

獨立性假設在真實世界幾乎不成立;機率估計不準確(分類仍可);高度相關 predictor 會放大偏差

三種方法比較

LDAQDANaive Bayes
假設各類共用 Σ各類獨立 Σkpredictors 獨立
邊界形狀線性二次曲線非線性
參數量\( \frac{p(p+1)}{2} + Kp \)\( K\cdot\frac{p(p+1)}{2} + Kp \)最低
適合情境K 多、n 中等各類形狀差異大p 很大、n 很小
預測速度中等最快

Python 實戰

# Google Colab / 本機通用
try:
    from google.colab import drive
    drive.mount('/content/drive')
    DATA_PATH = '/content/drive/MyDrive/ISLP_data/'
except ImportError:
    DATA_PATH = '/tmp/'

import numpy as np
import pandas as pd
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis, QuadraticDiscriminantAnalysis
from sklearn.naive_bayes import GaussianNB
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix, classification_report, roc_curve, auc

# ── 載入 Default 資料 ──
from ISLP import load_data
Default = load_data('Default')
X = pd.get_dummies(Default[['student', 'balance', 'income']], drop_first=True)
y = (Default['default'] == 'Yes').astype(int)

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1)

# ── LDA ──
lda = LinearDiscriminantAnalysis()
lda.fit(X_train, y_train)
lda_pred = lda.predict(X_test)
print("=== LDA 混淆矩陣 ===")
print(confusion_matrix(y_test, lda_pred))

# ── QDA ──
qda = QuadraticDiscriminantAnalysis()
qda.fit(X_train, y_train)
qda_pred = qda.predict(X_test)
print("\n=== QDA 混淆矩陣 ===")
print(confusion_matrix(y_test, qda_pred))

# ── Naive Bayes ──
nb = GaussianNB()
nb.fit(X_train, y_train)
nb_pred = nb.predict(X_test)
print("\n=== Naive Bayes 混淆矩陣 ===")
print(confusion_matrix(y_test, nb_pred))

# ── ROC 曲線比較 ──
lda_prob = lda.predict_proba(X_test)[:,1]
qda_prob = qda.predict_proba(X_test)[:,1]
nb_prob = nb.predict_proba(X_test)[:,1]

plt.figure(figsize=(8,6))
for probs, label, color in [(lda_prob,'LDA','#1a73e8'),(qda_prob,'QDA','#0d904f'),(nb_prob,'Naive Bayes','#e37400')]:
    fpr, tpr, _ = roc_curve(y_test, probs)
    plt.plot(fpr, tpr, label=f'{label} (AUC={auc(fpr,tpr):.3f})', color=color, linewidth=2)
plt.plot([0,1],[0,1],'k--',alpha=0.3)
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC Curve: LDA vs QDA vs Naive Bayes')
plt.legend()
plt.savefig('/tmp/roc_comparison.png', dpi=120, bbox_inches='tight')
plt.close()
print("\n✅ ROC 圖已存為 /tmp/roc_comparison.png")

應用場景

🏦 信用風險(Default 資料)
課本例:用 LDA 預測信用卡違約。預設閾值 50% 時,違約者的召回率只有 24.3%(75.7% 的違約者被漏掉)。調低閾值到 20%,召回率提升到 58.6%,但誤報也增加——這是 sensitivity-specificity 取捨的經典案例。
🧬 基因分類(p ≫ n)
基因表現資料常有數千個 gene(predictor)但只有幾十個樣本(n)。LDA 無法處理(Σ 不可逆),QDA 更不用說。Naive Bayes 是唯一可行的生成模型選擇。

關鍵公式回顧

方法判別函數核心假設
LDA\( \delta_k(x) = x^T \Sigma^{-1} \mu_k - \frac{1}{2}\mu_k^T \Sigma^{-1}\mu_k + \log\pi_k \)\( \Sigma_k = \Sigma \; \forall k \)
QDA\( \delta_k(x) = -\frac{1}{2}\log|\Sigma_k| - \frac{1}{2}(x-\mu_k)^T\Sigma_k^{-1}(x-\mu_k) + \log\pi_k \)各類 \( \Sigma_k \) 不同
Naive Bayes\( \delta_k(x) = \log\pi_k + \sum_{j=1}^p \log f_{kj}(x_j) \)predictors 獨立

對 Hermes 的啟發

Naive Bayes 的 bias-variance trade-off 與 agent skill 設計
Naive Bayes 的成功說明一個道理:簡化假設(bias ↑)換取穩定性(variance ↓)在資源不足時是正確策略。這與 Hermes skill 設計的「免費 LLM 只用於短摘要、分類、子任務」策略一致——不追求完美,只求在限制下做到最好。當 p≫n(任務多、資源少),簡化假設就是生存法則。

📚 James, Witten, Hastie, Tibshirani (2023) An Introduction to Statistical Learning with Python, §4.4, p153–160.
📚 Hastie, Tibshirani, Friedman (2009) The Elements of Statistical Learning, §4.3.