iT邦幫忙

2026 iThome 鐵人賽

DAY 20
0
自我挑戰組

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

突破線性瓶頸!隨機森林與非線性交互特徵實測

  • 分享至 

  • xImage
  •  

成功訓練100棵決策樹構成的隨機森林模型,完成測試集推論,並透過雙子圖呈現混淆矩陣結構改善與特徵貢獻分佈。

一、實作前情境:為什麼隨機森林能救回邊界預測?
在 Day 19 的實測中,邏輯回歸因為受限於線性超平面,無法捕捉複雜的條件判斷,最終退化為「預測93筆中度風險」的保守策略,使低度風險與高度風險的召回率幾近於0。

隨機森林作為 Bagging 集成學習的代表,具備以下對應優勢:

  • 正交分割與非線性適應:決策樹透過條件分岔劃分特徵空間,天然能夠擬合非線性邊界,不再受限於線性超平面的單一方向限制。
  • 自動捕捉高階交互作用:如 Day 13 發現的「睡眠不足(<=5h)重度暴露(>10h)」複合加乘效應,決策樹能透過深層節點的連續分裂自然捕捉,無須手動枚舉交互項。
  • 對多重共線性免疫:隨機森林在節點分裂時隨機挑選特徵子集,即使 CESI_Score 與其組成特徵(如 Eye_Pain_Level、Daily_Screen_Hours)高度相關,也不會出現邏輯回歸中的負係數抑制現象。

二、撰寫隨機森林訓練、評估與重要度可視化腳本
在Colab中新增儲存格,建立隨機森林分類器,並同步繪製測試集混淆矩陣與特徵重要度長條圖:

# ==========================================
# Day 20:隨機森林分類器與非線性特徵重要度分析
# ==========================================

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.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, confusion_matrix, accuracy_score

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

# 2. 建立並訓練隨機森林分類器
# 設定 n_estimators=100, max_depth=6 避免小樣本過度擬合 (Overfitting)
rf_clf = RandomForestClassifier(
    n_estimators=100,
    max_depth=6,
    min_samples_split=5,
    min_samples_leaf=2,
    random_state=42,
    class_weight='balanced'  # 平衡各類別權重,打破多數類偏差
)
rf_clf.fit(X_train, y_train)

# 3. 測試集預測與性能指標
y_pred_rf = rf_clf.predict(X_test)
y_prob_rf = rf_clf.predict_proba(X_test)

acc_rf = accuracy_score(y_test, y_pred_rf)
print(f"=== 隨機森林測試集整體準確率 (Accuracy): {acc_rf * 100:.2f}% ===\n")

# 4. 輸出分類評估報告 (Precision, Recall, F1-score)
target_names = ['低度風險 (Low)', '中度風險 (Medium)', '高度風險 (High)']
report_dict_rf = classification_report(y_test, y_pred_rf, target_names=target_names, output_dict=True)
report_df_rf = pd.DataFrame(report_dict_rf).transpose()
print("=== 隨機森林分類性能評估報告 (Classification Report) ===")
display(report_df_rf.round(3))

# 5. 繪製 1x2 畫布:混淆矩陣熱力圖 + 特徵重要度排序圖
fig, axes = plt.subplots(1, 2, figsize=(16, 6))
sns.set_theme(style="white")

# --- 圖 1:隨機森林混淆矩陣 (Confusion Matrix) ---
cm_rf = confusion_matrix(y_test, y_pred_rf)
sns.heatmap(
    cm_rf, 
    annot=True, 
    fmt='d', 
    cmap='Greens', 
    xticklabels=target_names, 
    yticklabels=target_names, 
    cbar=False, 
    ax=axes[0]
)
axes[0].set_title('隨機森林測試集混淆矩陣 (Confusion Matrix)', fontproperties=my_font, fontsize=14, fontweight='bold')
axes[0].set_xlabel('模型預測等級 (Predicted Label)', fontproperties=my_font, fontsize=12)
axes[0].set_ylabel('真實風險等級 (True Label)', fontproperties=my_font, fontsize=12)
axes[0].set_xticklabels(target_names, fontproperties=my_font, fontsize=10)
axes[0].set_yticklabels(target_names, fontproperties=my_font, fontsize=10)

# --- 圖 2:隨機森林特徵重要度 (MDI Feature Importance) ---
importances = pd.Series(rf_clf.feature_importances_, index=X_train.columns).sort_values(ascending=True)

importances.plot(
    kind='barh', 
    ax=axes[1], 
    color='#27ae60', 
    edgecolor='none', 
    alpha=0.85
)
axes[1].set_title('隨機森林特徵重要度排序 (Feature Importance)', fontproperties=my_font, fontsize=14, fontweight='bold')
axes[1].set_xlabel('不純度減少貢獻度 (Mean Decrease in Impurity)', fontproperties=my_font, fontsize=12)
axes[1].set_ylabel('輸入特徵項目', fontproperties=my_font, fontsize=12)

plt.tight_layout()
plt.show()

# 6. 輸出詳細特徵重要度數值表
feat_imp_df = pd.DataFrame({
    '特徵項目': importances.index,
    '貢獻佔比 (%)': (importances.values * 100).round(2)
}).sort_values(by='貢獻佔比 (%)', ascending=False).reset_index(drop=True)

print("=== 特徵重要度完整排序表 ===")
display(feat_imp_df)

https://ithelp.ithome.com.tw/upload/images/20261004/20178794rWHnbl09AT.png
https://ithelp.ithome.com.tw/upload/images/20261004/201787940Wps8u1NKB.png

三、圖表解讀與客觀數據分析
本實作以100棵決策樹構成的隨機森林分類器進行預測建模,並加入 class_weight='balanced' 嘗試修復多數類偏差。結合分類報告、測試集混淆矩陣與特徵重要度排序表,可得出以下深度的機器學習實務洞察:
1.混淆矩陣結構改善:成功打破「全判中度」的單一垂直牆
對比Day 19多元邏輯回歸(將93筆全判為中度、低/高風險預測為0的極端崩塌),隨機森林在預測分佈上展現了非線性樹模型的結構修復能力:
a.分類分佈展開:
低度風險(Low,真實24筆):模型預測了25筆,精準命中7筆(召回率從邏輯回歸的0.0%大幅回升至29.2%,F1-score 達 0.286)。
中度風險(Medium,真實47筆):命中26筆,召回率為55.3%,Precision為0.448。
高度風險(High,真實29筆):模型打破了邏輯回歸命中0筆的死局,成功預測出2筆真實高風險樣本。

b.效能瓶頸評估:

  • 測試集整體準確率為 35.00%,Macro Average F1-score 為 0.289。
  • 雖然總準確率因不再「投機全猜中度」而看似微降(35% vs. 41%),但隨機森林真正具備了對三種不同風險等級的辨識能力,在醫療與健康風險評估中,這種能辨識出潛在低/高風險的決策面遠比「多數類保守崩塌」更具實務價值。
  1. 特徵重要度:生活暴露與自覺疲勞的主導地位
    觀察右側不純度減少貢獻長條圖(MDI)與完整排序表,呈現出極具業務說服力的特徵階層:
    a.第一梯隊:作息暴露與綜合指標(核心驅動層,貢獻度各約 15%~17%)
  • Sleep_Hours(16.59%) 高居全場第1名!
  • Daily_Screen_Hours(15.98%) 緊追在後,位列第2名。
  • CESI_Score(15.28%) 穩居第3名。
  • 實質意涵:在隨機森林的多次條件切分中,「睡眠時間」與「螢幕暴露時間」成為決定決策樹分裂的最關鍵分割依據。這呼應了 Day 13 的重要結論——睡眠與螢幕時數的交互組合構成了眼部疲勞的核心主因。同時,Day 15 打造的 CESI_Score 以 15.28% 的高佔比證明其特徵工程的成功整合價值。

b.第二梯隊:生理年齡與自覺症狀(次要調節層,貢獻度約 7%~13%)

  • Age(13.24%)、Eye_Dryness_Level(9.07%)、Headache_Frequency_Per_Week(8.93%)與 Eye_Pain_Level(7.62%)構成了第二層決策依據,說明年齡調節力與自覺症狀在細分風險群體時扮演重要輔助角色。

c.第三梯隊:二元標籤與特定行為(微弱邊際層,貢獻度 < 3%)

  • Break_Frequency_Per_Hour(5.90%)。
  • Blurred_Vision_Yes(2.71%)。
  • Blue_Light_Filter_Used_Yes(2.48%)。
  • Role_Student(2.19%) 位列全場墊底。
  • 統計印證:此排序再度驗證了 Day 16 與 Day 17 的推論統計結果——「抗藍光濾鏡」(2.48%)與「學生身分」(2.19%)在模型眼中幾乎無助於區分風險等級,與先前檢定中 p > 0.05 的「無顯著差異」完全契合!

上一篇
基準模型出戰!多元邏輯回歸與混淆矩陣實測
下一篇
超參數調優大對決!GridSearchCV 實測隨機森林 vs. 支援向量機(SVM
系列文
用數據守護雙眼:生活型態對視力影響的探索性資料分析 共 22 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言