梯度提升機(Gradient Boosting Machine, GBM),特別是其現代高效實現——XGBoost。這是繼隨機森林后自然進階的方向,也是當前結構化數據競賽和工業界應用中最強大、最受歡迎的算法之一。
為什么推薦XGBoost?
- 與隨機森林互補:同屬集成學習,但Random Forest是Bagging思想,而XGBoost是Boosting思想。學習它可以幫助你全面理解集成學習的兩種主流范式。
- State-of-the-Art性能:在表格型數據上,XGBoost通常比隨機森林表現更好,是Kaggle等數據科學競賽中的"大殺器"。
- 高效且可擴展:專為速度和性能設計,支持并行處理,能處理大規模數據。
- 內置正則化:相比傳統GBM,XGBoost自帶正則化項,更不容易過擬合。
核心概念:Boosting vs Bagging
● Bagging(隨機森林):并行構建多個獨立的弱模型,然后通過投票/平均得到最終結果。
● Boosting(XGBoost):串行構建多個相關的弱模型,每個新模型都專注于糾正前一個模型的錯誤。
完整代碼示例
下面我們使用XGBoost來解決同樣的鳶尾花分類問題,并與隨機森林進行對比。
# xgboost_module.py
# -*- coding: utf-8 -*-"""
XGBoost分類器示例 - 鳶尾花數據集
模塊化實現,包含數據加載、模型訓練、評估、可視化和高級功能
"""# 1. 導入必要的庫
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.metrics import accuracy_score, classification_report
from sklearn.ensemble import RandomForestClassifier
import xgboost as xgb
import warnings
warnings.filterwarnings('ignore')# 設置全局樣式
plt.style.use('seaborn-v0_8')
np.random.seed(42) # 設置隨機種子以確保結果可重現# 2. 數據加載模塊
def load_data():"""加載鳶尾花數據集"""iris = load_iris()X = iris.datay = iris.targetfeature_names = iris.feature_namestarget_names = iris.target_namesreturn X, y, feature_names, target_names# 3. 數據預處理模塊
def prepare_data(X, y, test_size=0.2, random_state=42):"""準備訓練和測試數據集"""X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=test_size, random_state=random_state, stratify=y)print(f"訓練集大小: {X_train.shape[0]}")print(f"測試集大小: {X_test.shape[0]}")return X_train, X_test, y_train, y_test# 4. 隨機森林基準模型模塊
def train_random_forest(X_train, y_train, **params):"""訓練隨機森林模型作為基準"""# 設置默認參數default_params = {'n_estimators': 100,'max_depth': 3,'random_state': 42}# 更新默認參數default_params.update(params)# 初始化并訓練模型model = RandomForestClassifier(**default_params)model.fit(X_train, y_train)print("\n=== 隨機森林模型訓練完成 ===")print(f"使用參數: {default_params}")return model# 5. XGBoost模型訓練模塊
def train_xgboost(X_train, y_train, **params):"""訓練XGBoost模型"""# 設置默認參數default_params = {'n_estimators': 100,'max_depth': 3,'learning_rate': 0.1,'random_state': 42,'use_label_encoder': False,'eval_metric': 'logloss'}# 更新默認參數default_params.update(params)# 初始化并訓練模型model = xgb.XGBClassifier(**default_params)model.fit(X_train, y_train)print("\n=== XGBoost模型訓練完成 ===")print(f"使用參數: {default_params}")return model# 6. 模型評估模塊
def evaluate_model(model, X_test, y_test, model_name="模型"):"""評估模型性能"""# 預測y_pred = model.predict(X_test)# 計算準確率accuracy = accuracy_score(y_test, y_pred)print(f"\n=== {model_name}性能 ===")print(f"測試集準確率: {accuracy:.4f}")return accuracy, y_pred# 7. 交叉驗證比較模塊
def compare_cv_models(models, X, y, cv=5):"""使用交叉驗證比較多個模型"""print("\n=== 交叉驗證比較 ===")results = {}for name, model in models.items():scores = cross_val_score(model, X, y, cv=cv, scoring='accuracy')results[name] = scoresprint(f"{name} 交叉驗證平均分: {scores.mean():.4f} (±{scores.std():.4f})")return results# 8. 特征重要性可視化模塊
def plot_feature_importance(models, feature_names):"""可視化多個模型的特征重要性"""n_models = len(models)plt.figure(figsize=(5 * n_models, 5))for i, (name, model) in enumerate(models.items(), 1):plt.subplot(1, n_models, i)# 獲取特征重要性if hasattr(model, 'feature_importances_'):importances = model.feature_importances_else:# 對于XGBoost模型importances = model.get_booster().get_score(importance_type='weight')# 轉換為數組格式importances_array = np.zeros(len(feature_names))for j, feat in enumerate(feature_names):importances_array[j] = importances.get(f"f{j}", 0)importances = importances_array# 排序并繪制indices = np.argsort(importances)[::-1]plt.bar(range(len(feature_names)), importances[indices])plt.xticks(range(len(feature_names)), [feature_names[i] for i in indices], rotation=45)plt.title(f'{name} - Feature Importance')plt.tight_layout()plt.show()# 9. 高級功能:早停法訓練模塊
def train_xgboost_early_stopping(X_train, y_train, X_test, y_test, **params):"""使用早停法訓練XGBoost模型"""# 設置默認參數default_params = {'max_depth': 3,'learning_rate': 0.1,'objective': 'multi:softmax','num_class': 3,'eval_metric': 'mlogloss'}# 更新默認參數default_params.update(params)# 轉換為XGBoost的DMatrix格式dtrain = xgb.DMatrix(X_train, label=y_train)dtest = xgb.DMatrix(X_test, label=y_test)# 訓練并使用早停法evals = [(dtrain, 'train'), (dtest, 'test')]model = xgb.train(default_params, dtrain, num_boost_round=1000,evals=evals,early_stopping_rounds=10,verbose_eval=False)print("\n=== 早停法訓練完成 ===")print(f"在 {model.best_iteration} 輪停止")print(f"最佳驗證分數: {model.best_score:.4f}")return model# 10. 預測模塊
def make_predictions(model, new_samples, target_names, model_type='sklearn'):"""使用模型進行新樣本預測"""if model_type == 'xgboost_early_stop':# 對于早停法訓練的XGBoost模型dnew = xgb.DMatrix(new_samples)predictions = model.predict(dnew)# 早停法訓練的模型不直接提供概率,需要額外處理print("注意: 早停法訓練的XGBoost模型不直接提供概率輸出")predictions_proba = Noneelse:# 對于標準sklearn接口的模型predictions = model.predict(new_samples)predictions_proba = model.predict_proba(new_samples)print("\n=== 新樣本預測 ===")for i, sample in enumerate(new_samples):predicted_class = target_names[int(predictions[i])]print(f"樣本 {i+1} {sample}:")print(f" 預測類別: {predicted_class}")if predictions_proba is not None:print(f" 類別概率: {dict(zip(target_names, predictions_proba[i].round(4)))}")return predictions, predictions_proba# 11. 主函數 - 整合所有模塊
def main():"""主函數,整合所有模塊"""# 加載數據X, y, feature_names, target_names = load_data()print("=== 鳶尾花數據集 ===")print(f"數據集形狀: {X.shape}")print(f"特征名稱: {feature_names}")print(f"類別名稱: {target_names}")# 準備數據X_train, X_test, y_train, y_test = prepare_data(X, y)# 訓練隨機森林模型rf_model = train_random_forest(X_train, y_train)rf_accuracy, rf_pred = evaluate_model(rf_model, X_test, y_test, "隨機森林")# 訓練XGBoost模型xgb_model = train_xgboost(X_train, y_train)xgb_accuracy, xgb_pred = evaluate_model(xgb_model, X_test, y_test, "XGBoost")# 交叉驗證比較models = {'隨機森林': rf_model,'XGBoost': xgb_model}cv_results = compare_cv_models(models, X, y)# 特征重要性可視化plot_feature_importance(models, feature_names)# 詳細分類報告print("\n=== XGBoost詳細分類報告 ===")print(classification_report(y_test, xgb_pred, target_names=target_names))# 高級功能:早停法訓練xgb_early_model = train_xgboost_early_stopping(X_train, y_train, X_test, y_test)# 進行預測new_samples = [[5.1, 3.5, 1.4, 0.2], # 很可能為setosa[6.7, 3.0, 5.2, 2.3] # 很可能為virginica]predictions, predictions_proba = make_predictions(xgb_model, new_samples, target_names)return {'rf_model': rf_model,'xgb_model': xgb_model,'xgb_early_model': xgb_early_model,'rf_accuracy': rf_accuracy,'xgb_accuracy': xgb_accuracy,'cv_results': cv_results,'predictions': predictions}# 12. 執行主程序
if __name__ == "__main__":results = main()
代碼解析與學習要點
- 參數對比:
○ XGBoost有與隨機森林相似的參數(n_estimators, max_depth)
○ 但也有特有參數如learning_rate(學習率),控制每棵樹的貢獻程度 - 性能比較:
○ 代碼中比較了兩種算法的準確率和交叉驗證結果
○ 通常情況下,XGBoost會略優于隨機森林 - 特征重要性:
○ 可視化對比兩種算法計算的特征重要性
○ 注意:兩種算法計算重要性的方法不同,結果可能有差異 - 高級功能:
○ 演示了早停法(Early Stopping),這是防止過擬合的重要技術
○ 展示了DMatrix數據格式,這是XGBoost的高效數據容器 - 預測概率:
○ XGBoost可以提供每個類別的預測概率,這對于不確定性分析很有用
代碼運行結果
=== 鳶尾花數據集 ===
數據集形狀: (150, 4)
特征名稱: ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
類別名稱: ['setosa' 'versicolor' 'virginica']
訓練集大小: 120
測試集大小: 30=== 隨機森林模型訓練完成 ===
使用參數: {'n_estimators': 100, 'max_depth': 3, 'random_state': 42}=== 隨機森林性能 ===
測試集準確率: 0.9667=== XGBoost模型訓練完成 ===
使用參數: {'n_estimators': 100, 'max_depth': 3, 'learning_rate': 0.1, 'random_state': 42, 'use_label_encoder': False, 'eval_metric': 'logloss'}=== XGBoost性能 ===
測試集準確率: 0.9333=== 交叉驗證比較 ===
隨機森林 交叉驗證平均分: 0.9667 (±0.0211)
XGBoost 交叉驗證平均分: 0.9467 (±0.0267)=== XGBoost詳細分類報告 ===precision recall f1-score supportsetosa 1.00 1.00 1.00 10versicolor 0.90 0.90 0.90 10virginica 0.90 0.90 0.90 10accuracy 0.93 30macro avg 0.93 0.93 0.93 30
weighted avg 0.93 0.93 0.93 30=== 早停法訓練完成 ===
在 33 輪停止
最佳驗證分數: 0.1948=== 新樣本預測 ===
樣本 1 [5.1, 3.5, 1.4, 0.2]:預測類別: setosa類別概率: {'setosa': 0.9911, 'versicolor': 0.0067, 'virginica': 0.0023}
樣本 2 [6.7, 3.0, 5.2, 2.3]:預測類別: virginica類別概率: {'setosa': 0.0019, 'versicolor': 0.0025, 'virginica': 0.9956}