iT邦幫忙

2026 iThome 鐵人賽

DAY 24
0
自我挑戰組

用數據守護雙眼:生活型態對視力影響的探索性資料分析系列 第 24 篇

五大演算法終極爭霸!全模型性能評測與多類別 ROC-AUC 曲線大對決

  • 分享至 

  • xImage
  •  

系統性彙整 Day 19 至 Day 23 實作的五大機器學習分類演算法——多元邏輯回歸(Logistic Regression)、隨機森林(Random Forest 優化版)、支援向量機(SVM 優化版)、XGBoost 以及 LightGBM。計算一對其餘(One-vs-Rest, OvR)多類別微平均/宏平均 ROC-AUC,繪製全模型綜合指標橫向對比條形圖與多類別 ROC 曲線,完成鐵人賽預測建模階段的冠軍模型決選。

一、實作前情境:如何客觀選出真正能落地的最佳模型?
在過去五天的密集建模實戰中,我們見證了不同演算法在面對用眼疲勞資料時的特性:

  1. 多元邏輯回歸(Day 19):受限於線性邊界,發生了將93筆全判為中度風險的「多數類保守崩塌」。 
  2. 隨機森林優化版(Day 21):透過 ⁠max_depth=3⁠ 與 ⁠class_weight='balanced'⁠,成功將高風險召回提升至 7 筆,繳出 0.337 的 Macro F1-score。 
  3. SVM 優化版(Day 21):高維核空間幾何邊界難以切割交疊嚴重的連續量表,產生了朝向低風險側的單向傾斜。 
  4. XGBoost(Day 22):憑藉對中度多數類的高覆蓋衝出 43.00% 的總準確率,但以全域 Log Loss 最小化為目標時,把低度風險預測歸零(Macro F1 = 0.248)。 
  5. LightGBM(Day 23):以直方圖分箱與葉節點導向生長,在兼顧訓練速度的同時實施類別權重平衡。
    在醫療與亞健康風險評估場景中,不能單看Accuracy(因為投機猜測多數類就能衝高準確率),更要檢視 Macro F1-score 與多類別ROC-AUC,評估模型對於三種風險機率排序的判別力。

二、撰寫五大模型綜合評測與多類別 ROC 曲線腳本
在Colab中新增儲存格,統整各模型的預測結果與預測機率,繪製1x2橫向對比圖表:

# ==========================================
# Day 24:五大機器學習模型終極對決與 ROC-AUC 評測
# ==========================================

import warnings
warnings.filterwarnings('ignore')

import matplotlib.pyplot as plt
import seaborn as sns
import matplotlib.font_manager as fm
import pandas as pd
import numpy as np

from sklearn.preprocessing import label_binarize
from sklearn.metrics import (
    accuracy_score, precision_score, recall_score, f1_score,
    roc_curve, auc, roc_auc_score
)

# 1. 引用中文字型
font_path = 'NotoSansTC-Regular.otf'
my_font = fm.FontProperties(fname=font_path)

# 2. 收集各模型實例與預測結果 (確保先前的模型變數已存在)
# y_test 二值化矩陣 (用於計算多類別 One-vs-Rest ROC 曲線)
y_test_bin = label_binarize(y_test, classes=[0, 1, 2])
n_classes = y_test_bin.shape[1]

models_dict = {
    '多元邏輯回歸': {'pred': clf.predict(X_test), 'prob': clf.predict_proba(X_test)},
    '隨機森林 (優化版)': {'pred': best_rf.predict(X_test), 'prob': best_rf.predict_proba(X_test)},
    'SVM (優化版)': {'pred': best_svm.predict(X_test), 'prob': best_svm.predict_proba(X_test)},
    'XGBoost': {'pred': xgb_clf.predict(X_test), 'prob': xgb_clf.predict_proba(X_test)},
    'LightGBM': {'pred': lgb_clf.predict(X_test), 'prob': lgb_clf.predict_proba(X_test)}
}

# 3. 計算綜合性能評測指標表
benchmarks = []

for name, res in models_dict.items():
    y_pred = res['pred']
    y_prob = res['prob']
    
    acc = accuracy_score(y_test, y_pred)
    macro_prec = precision_score(y_test, y_pred, average='macro', zero_division=0)
    macro_rec = recall_score(y_test, y_pred, average='macro', zero_division=0)
    macro_f1 = f1_score(y_test, y_pred, average='macro', zero_division=0)
    
    # 計算 Macro-average One-vs-Rest ROC-AUC
    try:
        ovr_auc = roc_auc_score(y_test_bin, y_prob, average='macro', multi_class='ovr')
    except:
        ovr_auc = 0.5
        
    # 計算高度風險 (類別 2) 單獨的召回率
    rec_high = recall_score(y_test == 2, y_pred == 2, zero_division=0)
    
    benchmarks.append({
        '模型名稱': name,
        '準確率 (Accuracy)': f"{acc*100:.2f}%",
        'Macro Precision': round(macro_prec, 3),
        'Macro Recall': round(macro_rec, 3),
        'Macro F1-score': round(macro_f1, 3),
        'Macro ROC-AUC': round(ovr_auc, 3),
        '高風險召回率 (High Recall)': f"{rec_high*100:.1f}%"
    })

benchmark_df = pd.DataFrame(benchmarks)
print("=== 五大演算法性能綜合評測總表 ===")
display(benchmark_df)

# 4. 繪製 1x2 畫布:核心指標橫向長條圖 + 宏觀 ROC 曲線對比
fig, axes = plt.subplots(1, 2, figsize=(16, 6))
sns.set_theme(style="whitegrid")

# --- 圖 1:Macro F1-score 與 ROC-AUC 綜合評分長條圖 ---
plot_df = pd.DataFrame({
    '模型名稱': [b['模型名稱'] for b in benchmarks],
    'Macro F1-score': [b['Macro F1-score'] for b in benchmarks],
    'Macro ROC-AUC': [b['Macro ROC-AUC'] for b in benchmarks]
}).set_index('模型名稱')

plot_df.plot(kind='bar', ax=axes[0], colormap='viridis', width=0.6, edgecolor='none')
axes[0].set_title('各模型綜合判別指標對比 (Macro F1 vs. ROC-AUC)', fontproperties=my_font, fontsize=13, fontweight='bold')
axes[0].set_xlabel('機器學習演算法', fontproperties=my_font, fontsize=12)
axes[0].set_ylabel('評估得分 (0.0 ~ 1.0)', fontproperties=my_font, fontsize=12)
axes[0].set_xticklabels(axes[0].get_xticklabels(), fontproperties=my_font, rotation=15, fontsize=10)
axes[0].set_ylim(0, 1.0)
axes[0].legend(loc='lower right')

# --- 圖 2:宏觀平均 ROC 曲線對比 (Macro-average ROC Curves) ---
colors = ['#7f8c8d', '#27ae60', '#8e44ad', '#2980b9', '#16a085']

for (name, res), color in zip(models_dict.items(), colors):
    y_prob = res['prob']
    
    # 計算每一類的 FPR / TPR 並合成宏觀平均曲線
    all_fpr = np.unique(np.concatenate([roc_curve(y_test_bin[:, i], y_prob[:, i])[0] for i in range(n_classes)]))
    mean_tpr = np.zeros_like(all_fpr)
    for i in range(n_classes):
        fpr_i, tpr_i, _ = roc_curve(y_test_bin[:, i], y_prob[:, i])
        mean_tpr += np.interp(all_fpr, fpr_i, tpr_i)
    mean_tpr /= n_classes
    macro_auc = auc(all_fpr, mean_tpr)
    
    axes[1].plot(all_fpr, mean_tpr, label=f'{name} (AUC = {macro_auc:.3f})', color=color, linewidth=2)

axes[1].plot([0, 1], [0, 1], 'k--', linestyle='--', color='gray', label='隨機猜測 (AUC = 0.500)')
axes[1].set_title('五大模型宏觀平均 ROC 曲線對比 (OvR)', fontproperties=my_font, fontsize=13, fontweight='bold')
axes[1].set_xlabel('假陽性率 (False Positive Rate)', fontproperties=my_font, fontsize=12)
axes[1].set_ylabel('真陽性率 (True Positive Rate)', fontproperties=my_font, fontsize=12)
axes[1].legend(loc='lower right')

plt.tight_layout()
plt.show()


上一篇
輕量急速王者!LightGBM 葉節點導向生長與多類別預測實戰
系列文
用數據守護雙眼:生活型態對視力影響的探索性資料分析 共 24 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言