owned this note
owned this note
Published
Linked with GitHub
# 9_隨機森林&XGBoost
## Source
- 大數據分析與資料探勘 W11
- 應⽤機器學習於Python C3-3, 3-4 ==(3-5模型優化還沒加入)==
## 課堂投影片與練習
- [ ] **Python 機器學習課程**
* **單元三:樹的集成學習 - 隨機森林與 XGBoost**
* 各位同學好,在前面的課程中,我們已經初步認識了決策樹模型。今天,我們要將決策樹的概念進一步延伸,學習兩種非常強大且廣泛應用的集成學習模型:**隨機森林 (Random Forest)** 和 **極限梯度提升 (XGBoost)**。這兩種模型在現實世界的資料科學競賽和產業應用中都佔有舉足輕重的地位,理解它們的原理與應用,將能大大提升你們解決問題的能力。
---
- [ ] **隨機森林 (Random Forest) 原理 - 進階版的決策樹**
* **核心概念:**
* 隨機森林可以想像成是「**多棵決策樹加起來變成的一座森林**」。
* 它是一種**樹的集合 (ensemble)**,屬於一種稱為 **Bagging (套袋法)** 的集成學習方法。
* 目標是**避免過度學習 (overfitting)**。
* **「隨機」的玄機:**
* 隨機森林的「隨機」是其效果的關鍵。
* **樣本抽樣設計 (Bagging)**:
* 採用「**抽後放回 (sampling with replacement)**」的方法進行抽樣。
* 這表示**同一個樣本可能被抽到多次,也可能完全沒被抽到**,這確保了每棵樹的獨立性。
* **變數隨機抽樣**:
* 除了樣本隨機抽樣外,也可以對**變數 (features)** 進行隨機抽樣。
* 例如,如果資料集有 100 個變數,第一棵樹可能只抽 50 個變數,第二棵樹可能抽另外不同的 50 個,或者有重複抽到的變數。
* **運作與整合:**
* **多棵樹投票機制**:當有新的樣本進入時,森林中的**每一棵樹會個別進行預測**,最後再透過**投票**來決定最終的類別或預測結果。
* **弱學習器的整合**:單一的決策樹(我們稱之為「弱學習器」)可能會因為分類結果、樹的深度或樣本問題而造成**過度擬合 (overfitting)**。
* 隨機森林透過投票機制來**減少偏差 (bias) 和不好的行為**,有效處理過度擬合的問題。
---
- [ ] **隨機森林 (Random Forest) 的優缺點**
* **優點:**
* 能有效處理**過度擬合**的問題。
* 能夠解決**分類 (Classification) 與迴歸 (Regression) 兩種類型的問題**。
* 可以處理**高維度的資料、特徵遺失的資料以及不平衡的資料**。
* **缺點:**
* **迴歸表現不如分類**:在解決迴歸問題時,其表現不如分類,因為它不能給出連續的輸出,也無法做出超越訓練資料範圍的預測,可能導致對特定噪音資料的過度擬合。
* **黑盒子特性**:對使用者來說,隨機森林模型內部執行像一個黑盒子,可能無法完全控制,許多相似的決策樹也可能掩蓋真實的結果。
* **不適用小資料或低維度資料**:對於小資料或低維度的資料,可能無法產生很好的分類效果。
* **速度較慢**:由於是多棵樹產生,相較於單一決策樹,速度相對較慢。
---
- [ ] **課堂練習:隨機森林核心概念理解**
1. **任務:** 請解釋為什麼隨機森林的每棵決策樹是「獨立」的,以及「抽後放回」的抽樣方式如何幫助達到這個目的?
2. **任務:** 試著用一句話概括「隨機森林」和「單一決策樹」最大的不同是什麼?
3. **討論:** 根據隨機森林的優缺點,你認為在什麼情境下,隨機森林會是一個很好的選擇?在什麼情境下可能需要考慮其他模型?
---
- [ ] **隨機森林 (Random Forest) 實作 - 參數與準備**
* 在 Python 中,我們主要會使用 `scikit-learn` 這個強大的套件來實作隨機森林模型。
* **重要參數 (`RandomForestRegressor` 與 `RandomForestClassifier` 皆有):**
* **`n_estimators` (森林的大小/樹的數量)**:
* 這是隨機森林中**決策樹的數量**。
* 若未設定,預設通常會設定為 100 棵樹。
* 樹越多,模型越複雜,但通常表現會越好,不過訓練時間也會增加。
* **`max_depth` (樹的最大深度)**:
* 控制每棵決策樹的**最大深度**。
* 若未設定,它會將節點展開直到所有葉子都是純淨的 (pure) 或所有葉子包含的樣本數小於 `min_samples_split`。
* 限制深度可以幫助避免單棵樹的過度擬合。
* `criterion`:用於衡量分裂品質的函數,例如 `'mse'` (均方誤差) 用於迴歸,或 `'gini'` (基尼係數) / `'entropy'` (資訊增益) 用於分類。
---
**實作流程概覽:**
1. 實作流程概覽匯入所需套件 : 引入 pandas、numpy 等資料處理套件,以及 RandomForestRegressor、資料集分割與模型評估的工具。
2. 資料讀取與初步處理 : 使用 pandas 讀取紅酒品質資料集(WineQT.csv),檢查資料欄位,確認 quality 為目標變數,並排除識別欄(如 Id)。
3. 特徵與目標變數分離 : 將除 quality 與 Id 外的欄位設為特徵 X,quality 為目標 y。
4. 切分訓練集與測試集 :使用 train_test_split() 將資料分為訓練集與測試集(通常測試集比例設為 0.2)。
5. 建立隨機森林迴歸模型實例:建立 RandomForestRegressor,可調整 n_estimators(樹數量)、random_state 等參數。
6. 模型訓練:使用訓練資料 (X_train, y_train) 來訓練模型(fit())。
7. 模型預測:對測試集 (X_test) 執行預測,取得預測值 y_pred。
8. 模型評估:根據迴歸問題,計算 R2 Score、MAE、MSE、RMSE 等指標來評估模型效能。
---
- [ ] **隨機森林迴歸範例 (紅酒品質)**
* **問題類型**:我們將使用紅酒品質的資料集來示範**迴歸 (Regression)** 問題的解決。
* 下載紅酒品質資料集 : https://www.kaggle.com/datasets/yasserh/wine-quality-dataset
* **Python 程式碼概覽:**
```python=
import pandas as pd
import numpy as np
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split
from sklearn.metrics import r2_score, mean_absolute_error, mean_squared_error
# 1. 讀取資料集
df = pd.read_csv('WineQT.csv')
# 2. 確認欄位,排除 Id 欄位
print("資料欄位:", df.columns.tolist())
# 3. 指定 X 和 y,並排除 'Id' 欄位
X = df.drop(['quality', 'Id'], axis=1)
y = df['quality']
# 4. 分割訓練集/測試集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 5. 建立模型
model_rf_reg = RandomForestRegressor(n_estimators=200, random_state=42)
# 6. 訓練模型
model_rf_reg.fit(X_train, y_train)
# 7. 預測
y_pred_rf_reg = model_rf_reg.predict(X_test)
# 8. 評估 (修正 RMSE 寫法)
R2 = r2_score(y_test, y_pred_rf_reg)
MAE = mean_absolute_error(y_test, y_pred_rf_reg)
MSE = mean_squared_error(y_test, y_pred_rf_reg)
RMSE = np.sqrt(MSE)
print(f"R2 Score: {R2:.2f}")
print(f"MAE: {MAE:.2f}")
print(f"MSE: {MSE:.2f}")
print(f"RMSE: {RMSE:.2f}")
```
* **評估指標**:對於迴歸問題,常用的評估指標包括:
* **R2 (決定係數)**:表示模型能解釋目標變數變異的比例,越接近 1 越好。
* **MAE (Mean Absolute Error, 平均絕對誤差)**:預測值與真實值之間絕對差的平均值。
* **MSE (Mean Squared Error, 均方誤差)**:預測值與真實值之間平方差的平均值,對大誤差更敏感。
* **RMSE (Root Mean Squared Error, 均方根誤差)**:MSE 的平方根,與目標變數單位相同,更直觀。
* 透過這些指標,我們可以瞭解模型在預測時的**最小差值**表現。
---
- [ ] **課中練習二:隨機森林迴歸實作與參數調整**
1. **任務:** 依照前面提供的程式碼框架,完成紅酒品質資料集的載入、資料分割 (train_test_split),並訓練一個 `RandomForestRegressor` 模型。然後,計算並印出 R2、MAE、MSE、RMSE 的值。
2. **任務:** 嘗試修改 n_estimators 參數(例如,50, 100, 200, 500),觀察 R2 值的變化。你觀察到了什麼?請簡單解釋。
```python=
# 嘗試修改 n_estimators 參數(例如,50, 100, 200, 500)
for n in [50, 100, 200, 500]:
model = RandomForestRegressor(n_estimators=n, max_depth=None, random_state=42)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
R2 = r2_score(y_test, y_pred)
MAE = mean_absolute_error(y_test, y_pred)
MSE = mean_squared_error(y_test, y_pred)
RMSE = np.sqrt(MSE)
print(f"n_estimators={n}, max_depth=None -> R2: {R2:.4f}, MAE: {MAE:.4f}, MSE: {MSE:.4f}, RMSE: {RMSE:.4f}")
```
```
簡單觀察與說明
* R2分數最高為 n_estimators=100(0.4628),誤差(MAE/MSE/RMSE)也是最小。
* 當樹數從 50 增加到 100,R2 提升、誤差減少,模型表現改善,但繼續增加到 200 或 500,R2 沒有進一步提升,誤差也差不多,提升有限。
* 結論:
* 在這份資料集,n_estimators=100 已足夠好,再增加並不會有明顯幫助,反而增加計算時間。
```
3. **挑戰題:** 嘗試調整 `max_depth` 參數,觀察模型效能的變化。過深或過淺的深度可能會有什麼影響?
```python=
for d in [3, 8, 20, None]:
model = RandomForestRegressor(n_estimators=100, max_depth=d, random_state=42)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
R2 = r2_score(y_test, y_pred)
MAE = mean_absolute_error(y_test, y_pred)
MSE = mean_squared_error(y_test, y_pred)
RMSE = np.sqrt(MSE)
print(f"n_estimators=100, max_depth={str(d)} -> R2: {R2:.4f}, MAE: {MAE:.4f}, MSE: {MSE:.4f}, RMSE: {RMSE:.4f}")
```
```
分析與簡單說明
max_depth=3(很淺)時,模型表現最差,R2 分數明顯下降(0.34),誤差最高,明顯 underfitting(欠擬合)。
max_depth=8 時,R2 分數提升到 0.45,誤差下降,模型表現變好。
max_depth=20 或 None(不設限),R2 分數約 0.46,誤差進一步下降,模型達到最佳或接近最佳表現。
max_depth=20 跟 None 的結果幾乎一樣,表示此時深度已夠,不再受限。
```
---
- [ ] **隨機森林分類範例 (鐵達尼號生存)**
* **問題類型**:我們將使用鐵達尼號生存的資料集來示範**分類 (Classification)** 問題的解決。
* 在進行分類之前,我們需要進行一些**資料前處理**,例如填補缺失值、合併或丟棄變數以及進行編碼 (如 One-Hot Encoding 或 Label Encoding)。
---
**實作流程步驟**
1. 讀取資料
使用 pandas 的 read_csv() 讀取 train.csv,將資料存入 DataFrame 物件 df。
2. 選特徵與目標
指定要用的特徵欄位(Pclass, Sex, Age, SibSp, Parch, Fare, Embarked),並以 .copy() 方式建立新的 DataFrame。目標變數為 Survived。
3. 補缺值
以中位數填補數值型變數(Age、Fare)的缺失值;以眾數填補類別型變數(Embarked)的缺失值。
4. 類別變數編碼
將 Sex 與 Embarked 兩個類別型欄位進行 One-Hot 編碼,轉換為數值型欄位(以便模型學習),並用 drop_first=True 避免多重共線性。
5. 訓練/驗證集切分
使用 train_test_split() 將資料分為訓練集與驗證集,測試集比例設為 0.2,並設定亂數種子 42。
6. 建模
建立 RandomForestClassifier 分類器,設定樹的數量(n_estimators=100),亂數種子 42。
7. 預測
用訓練好的模型對驗證集進行預測,得到預測結果 y_pred。
8. 評估
計算並印出混淆矩陣(confusion_matrix),以及準確率(accuracy)、精確率(precision)、召回率(recall)、F1 分數(f1 score)等評估指標。
---
**隨機森林分類範例 (鐵達尼號生存)**
* **Python 程式碼概覽:**
```python=
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix, accuracy_score, precision_score, recall_score, f1_score
# 1. 讀取資料
df = pd.read_csv('train.csv')
# 2. 選特徵與目標
cols = ['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked']
X = df[cols].copy() # ← 加上 .copy(),避免 SettingWithCopyWarning
y = df['Survived']
# 3. 補缺值
X['Age'] = X['Age'].fillna(X['Age'].median())
X['Fare'] = X['Fare'].fillna(X['Fare'].median())
X['Embarked'] = X['Embarked'].fillna(X['Embarked'].mode()[0])
# 4. 類別變數編碼
X = pd.get_dummies(X, columns=['Sex', 'Embarked'], drop_first=True)
# 5. 訓練/驗證集切分
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)
# 6. 建模
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)
# 7. 預測
y_pred = model.predict(X_val)
# 8. 評估
conf_matrix = confusion_matrix(y_val, y_pred)
accuracy = accuracy_score(y_val, y_pred)
precision = precision_score(y_val, y_pred)
recall = recall_score(y_val, y_pred)
f1 = f1_score(y_val, y_pred)
print("Confusion Matrix:\n", conf_matrix)
print(f"Accuracy: {accuracy:.4f}")
print(f"Precision: {precision:.4f}")
print(f"Recall: {recall:.4f}")
print(f"F1 Score: {f1:.4f}")
```
* **評估指標**:對於分類問題,我們常用**混淆矩陣 (Confusion Matrix)** 來幫助計算各種評估指標:
* **Accuracy (準確性)**:模型正確預測的比例。
* **Precision (精確度)**:在所有被模型預測為正類的樣本中,真正是正類的比例。
* **Recall (召回率/敏感度/TPR)**:在所有真實正類的樣本中,被模型正確預測為正類的比例。
* **F1-score**:Precision 和 Recall 的調和平均數,綜合考量兩者。
* **FNR (False Negative Rate, 誤報率)**:真實正類中,被模型錯誤預測為負類的比例。
---
```
評估指標結果
Confusion Matrix:
[[91 14]
[18 56]]
Accuracy: 0.8212
Precision: 0.8000
Recall: 0.7568
F1 Score: 0.7778
```
* Confusion Matrix(混淆矩陣)
* 代表91 名未生存者被正確預測(TN),56 名生存者被正確預測(TP)
* 14 名未生存者被錯誤預測為生存(FP),18 名生存者被錯誤預測為未生存(FN)。
* Accuracy(準確率): 預測正確的比例約為 82%。
* Precision(精確率): 模型預測為生存的乘客中,實際真的生存的比例為 80%
* Recall(召回率):所有實際生存者中,有 75.68% 被模型成功找出來
* F1 Score : 精確率與召回率的加權平均,數值愈高代表「同時兼顧精確率與召回率」。
---
- [ ] **極限梯度提升 (XGBoost) 原理介紹**
* **核心概念:**
* XGBoost (Extreme Gradient Boosting) 是一種**梯度提升 (Boosting)** 的集成學習方法。
* 與隨機森林的 Bagging 方法不同,Boosting 演算法是一種**分類器的串聯方法**,它把每個弱模型的輸出作為下一個弱模型(分類器)的輸入。
* **運作原理 - 串聯與誤差減少:**
* **序列式訓練**:每棵決策樹預測的是**前一棵決策樹的誤差**,目標是使總體誤差越來越少。
* **梯度提升 (Gradient Boosting)**:
* 首先,初始化一個預測結果並計算殘差。
* 接著,透過優化方法,沿著**最快降低殘差的方向**建立一個新的弱模型(新的決策樹)。
* 每一次新的決策樹生成都是根據上一步決策樹的**損失函數之負梯度方向**來進行的。
* **最終預測**:將所有決策樹的結果**加總**後,產生樣本最終的預測值。
* **與隨機森林的比較:**
* **隨機森林 (Bagging)**:每棵樹在原始資料集的子集中**並行 (parallel)** 訓練,並用所有樹預測結果的均值作為最終預測。
* **XGBoost (Boosting)**:模型是**串聯 (sequential)** 進行預測,每棵樹都是對前一棵樹的誤差進行修正。
---
- [ ] **極限梯度提升 (XGBoost) 的優點與缺點**
* **優點:**
* **高精準度**:XGBoost 的精準度非常高,是各大機器學習比賽中的**常勝冠軍**。
* **損失函數優化**:加入了 **L2 正則化 (regularization)** 以避免過度擬合。
* **內建缺失值處理**:可自動學習不同節點遇到缺失值時的分類方向。
* **內建交叉驗證功能**:方便獲得最優化的 Boosting 迭代次數。
* **高度靈活性**:支援決策樹、線性模型、自定義目標函數、評估函數等。
* **平行處理能力**:雖然樹的生成是序列的,但在**特徵粒度上可以進行並行處理**。
* **缺點:**
* **參數較多且複雜**:使用者必須對模型參數有所了解才能將其發揮到極致。
* **記憶體耗費較高**:對於空間複雜度高、需要儲存特徵值與索引較高時,耗費的記憶體也較高。
* **資料類型限制**:比較適合處理**結構化資料**,對於圖形化資料的分析相較於其他模型表現較差。
* **黑盒子特性**:與隨機森林類似,XGBoost 模型也具有黑盒子的特性。
---
- [ ] **極限梯度提升 (XGBoost) 實作 - 準備與範例**
* **重要注意事項**:XGBoost **並非 `scikit-learn` 內建的模型**,因此需要額外匯入 `import xgboost as xgb`。
* **`objective` 參數設定**:這是 XGBoost 中非常重要的參數,用於指定模型要解決的問題類型。
* **迴歸問題**:
* `reg:squarederror` (平方誤差迴歸):最常見的迴歸目標。
* **二元分類問題**:
* `binary:logistic` (二元邏輯迴歸):輸出為預測機率,通常用於二分類問題。
* **多元分類問題**:
* `multi:softmax` (多元分類):輸出為類別標籤,用於多分類問題。
* `multi:softprob`:輸出為每個類別的預測機率。
* **迴歸範例 (紅酒品質)**:
```python=
# 匯入 XGBoost 套件
# 匯入必要套件
import pandas as pd
import numpy as np
import xgboost as xgb
from sklearn.model_selection import train_test_split
from sklearn.metrics import r2_score, mean_absolute_error, mean_squared_error
# 1. 讀取資料
df = pd.read_csv('WineQT.csv') # 你的資料集檔案名稱
# 2. 特徵與目標
X = df.drop(['quality', 'Id'], axis=1)
y = df['quality']
# 3. 分割訓練/測試集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 4. 建立 XGBoost Regressor
model_xgb_reg = xgb.XGBRegressor(objective='reg:squarederror', n_estimators=100, random_state=42)
# 5. 訓練模型
model_xgb_reg.fit(X_train, y_train)
# 6. 預測
y_pred_xgb_reg = model_xgb_reg.predict(X_test)
# 7. 評估
R2 = r2_score(y_test, y_pred_xgb_reg)
MAE = mean_absolute_error(y_test, y_pred_xgb_reg)
MSE = mean_squared_error(y_test, y_pred_xgb_reg)
RMSE = np.sqrt(MSE)
print(f"XGBoost\nR2 Score: {R2:.2f}")
print(f"MAE: {MAE:.2f}")
print(f"MSE: {MSE:.2f}")
print(f"RMSE: {RMSE:.2f}")
```
---
**XGBoost vs Random Forest (紅酒品質)**
| 模型 | R2 Score | MAE | MSE | RMSE |
|----------------|----------|-------|-------|-------|
| XGBoost | 0.34 | 0.43 | 0.37 | 0.60 |
| Random Forest <br> <span style="color:red;">(較佳)</span> | 0.46 | 0.41 | 0.30 | 0.55 |
```
Random Forest 整體表現優於 XGBoost(R2、MAE、MSE、RMSE 均較佳)。
紅酒品質資料集本身資料筆數不多、特徵數量也不算高,屬於小型且結構較簡單的資料。在這種結構下,Random Forest 已經可以有效學習特徵與標籤之間的關聯。相較之下,XGBoost 通常在特徵數量較多或資料規模較大的情境下會展現更佳的表現。
```
---
* **分類範例 (鐵達尼號生存)**:
```python=
# 匯入 XGBoost 套件
import xgboost as xgb
# from sklearn.model_selection import train_test_split
# from sklearn.metrics import confusion_matrix, accuracy_score
# 假設 X_train, X_test, y_train, y_test 已準備好
# 建立 XGBoost Classifier 模型實例
# objective 設定為二元邏輯迴歸
model_xgb_clf = xgb.XGBClassifier(objective='binary:logistic', n_estimators=100, random_state=42)
# 訓練模型
# model_xgb_clf.fit(X_train, y_train)
# 進行預測
# y_pred_xgb_clf = model_xgb_clf.predict(X_test)
# 評估模型效能 (同隨機森林分類指標)
# acc = accuracy_score(y_test, y_pred_xgb_clf)
# print(f"XGBoost Accuracy: {acc:.4f}") # 例如:準確性是 79.10%
```
---
**XGBoost vs Random Forest (鐵達尼號生存)**
| 模型 | Accuracy | Precision | Recall | F1 Score |
|--------------------------------------------|----------|-----------|---------|----------|
| XGBoost <br> <span style="color:red;">(較佳)</span> | 0.8324 | 0.8143 | 0.7703 | 0.7917 |
| Random Forest | 0.8268 | 0.8116 | 0.7568 | 0.7832 |
```
XGBoost 四項指標皆優於 Random Forest
Recall 提升較明顯(0.7703 vs 0.7568),代表 XGBoost 在預測「實際存活者」方面更準確。
F1 Score 也有提升,表示模型在 precision 與 recall 取得更好的平衡。
```
---