5. XGBoost高级主题


文档摘要

XGBoost高级主题 处理不平衡数据集 (Handling Imbalanced Datasets) 内容详解: 在实际应用中,我们经常会遇到不平衡数据集,即不同类别的样本数量差异很大。 例如,在欺诈检测、疾病诊断等领域,正例(欺诈交易、患病)样本通常远少于负例(正常交易、健康)样本。 不平衡数据集会严重影响模型的性能,因为模型会倾向于预测数量较多的类别,而忽略数量较少的类别。 XGBoost 提供了多种方法来处理不平衡数据集: 参数: 这是最常用的方法。 用于调整正例样本的权重。 其默认值为 1,当数据集不平衡时,可以将其设置为大于 1 的值。 一个常用的启发式方法是将 设置为负例样本数量与正例样本数量的比值。 这样可以使模型更加关注正例样本,从而提高模型在少数类上的性能。

5. XGBoost高级主题

1. 处理不平衡数据集 (Handling Imbalanced Datasets)

内容详解:

在实际应用中,我们经常会遇到不平衡数据集,即不同类别的样本数量差异很大。 例如,在欺诈检测、疾病诊断等领域,正例(欺诈交易、患病)样本通常远少于负例(正常交易、健康)样本。 不平衡数据集会严重影响模型的性能,因为模型会倾向于预测数量较多的类别,而忽略数量较少的类别。

XGBoost 提供了多种方法来处理不平衡数据集:

  • scale_pos_weight 参数: 这是最常用的方法。 scale_pos_weight 用于调整正例样本的权重。 其默认值为 1,当数据集不平衡时,可以将其设置为大于 1 的值。 一个常用的启发式方法是将 scale_pos_weight 设置为负例样本数量与正例样本数量的比值。 这样可以使模型更加关注正例样本,从而提高模型在少数类上的性能。

  • 上采样 (Oversampling) 和下采样 (Undersampling): 可以通过增加少数类样本的数量 (上采样) 或减少多数类样本的数量 (下采样) 来平衡数据集。 常用的上采样方法包括 SMOTE (Synthetic Minority Over-sampling Technique),下采样方法包括随机欠采样和 NearMiss 等。 需要注意的是,上采样可能会导致过拟合,下采样可能会丢失信息。

  • 集成方法 (Ensemble Methods): 可以结合集成方法,例如 EasyEnsemble 和 BalanceCascade 等,来处理不平衡数据集。 这些方法通过多次采样和集成多个模型来提高模型在不平衡数据集上的性能。

  • 调整评估指标: 在不平衡数据集上,准确率 (Accuracy) 通常不是一个好的评估指标,因为它会受到多数类别的支配。 应该使用更合适的评估指标,例如精确率 (Precision)、召回率 (Recall)、F1-score、AUC (Area Under the ROC Curve) 等。

代码实践:

import xgboost as xgb from sklearn.model_selection import train_test_split from sklearn.datasets import make_classification from sklearn.metrics import classification_report, roc_auc_score # 1. 创建不平衡数据集 X, y = make_classification(n_classes=2, class_sep=2, weights=[0.1, 0.9], n_informative=3, n_redundant=1, flip_y=0, n_features=20, n_clusters_per_class=1, n_samples=1000, random_state=10) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 2. 使用 `scale_pos_weight` 参数 # 计算 scale_pos_weight scale_pos_weight = sum(y_train == 0) / sum(y_train == 1) print(f"scale_pos_weight: {scale_pos_weight}") xgb_classifier_weighted = xgb.XGBClassifier( objective='binary:logistic', eval_metric='logloss', use_label_encoder=False, # 避免警告 scale_pos_weight=scale_pos_weight, random_state=42 ) xgb_classifier_weighted.fit(X_train, y_train) y_pred_weighted = xgb_classifier_weighted.predict(X_test) y_prob_weighted = xgb_classifier_weighted.predict_proba(X_test)[:, 1] print("\n使用 scale_pos_weight 的 XGBoost 分类器:") print(classification_report(y_test, y_pred_weighted)) print(f"AUC: {roc_auc_score(y_test, y_prob_weighted)}") # 3. 不使用 `scale_pos_weight` 参数作为对比 xgb_classifier_unweighted = xgb.XGBClassifier( objective='binary:logistic', eval_metric='logloss', use_label_encoder=False, # 避免警告 random_state=42 ) xgb_classifier_unweighted.fit(X_train, y_train) y_pred_unweighted = xgb_classifier_unweighted.predict(X_test) y_prob_unweighted = xgb_classifier_unweighted.predict_proba(X_test)[:, 1] print("\n未使用 scale_pos_weight 的 XGBoost 分类器:") print(classification_report(y_test, y_pred_unweighted)) print(f"AUC: {roc_auc_score(y_test, y_prob_unweighted)}")

代码详解:

  • 代码首先使用 make_classification 函数创建了一个不平衡的二分类数据集,其中正例样本 (class 1) 占 10%,负例样本 (class 0) 占 90%。

  • 然后,计算了 scale_pos_weight 的值,并将其传递给 XGBClassifier 的构造函数。

  • 分别训练了使用和未使用 scale_pos_weight 参数的两个 XGBoost 分类器。

  • 最后,使用 classification_reportroc_auc_score 评估了两个模型的性能。 可以看到,使用 scale_pos_weight 参数的模型在精确率、召回率和 F1-score 等指标上都有所提升,尤其是在正例 (class 1) 上的召回率显著提高,AUC 也略有提升,表明 scale_pos_weight 参数有效地提升了模型在不平衡数据集上的性能。

Graph TD 图:

图表解释:

该图表展示了处理不平衡数据集的流程。 首先,针对不平衡数据集,可以进行数据预处理,包括计算 scale_pos_weight 或进行上采样/下采样。 然后,使用 XGBoost 模型进行训练,训练时可以设置 scale_pos_weight 参数。 最后,使用合适的评估指标(例如关注少数类指标)评估模型性能,并与不处理不平衡数据集的模型进行比较。

2. 自定义损失函数和评估指标 (Custom Loss Functions and Evaluation Metrics)

内容详解:

XGBoost 允许用户自定义损失函数 (Objective Function) 和评估指标 (Evaluation Metric),这使其能够灵活地适应各种复杂的机器学习任务。

  • 自定义损失函数: 损失函数用于衡量模型预测值与真实值之间的差异,XGBoost 通过优化损失函数来训练模型。 对于不同的任务,可能需要使用不同的损失函数。 例如,对于回归任务,可以使用均方误差 (Mean Squared Error, MSE) 或平均绝对误差 (Mean Absolute Error, MAE);对于二分类任务,可以使用对数损失 (Log Loss) 或交叉熵损失 (Cross-Entropy Loss)。 XGBoost 允许用户自定义损失函数,只需要提供一阶梯度 (gradient) 和二阶梯度 (hessian) 的计算方法即可。

  • 自定义评估指标: 评估指标用于衡量模型在验证集或测试集上的性能。 XGBoost 内置了多种常用的评估指标,例如 rmse (均方根误差)、mae (平均绝对误差)、logloss (对数损失)、error (错误率)、auc (AUC) 等。 用户也可以自定义评估指标,只需要提供评估指标的计算方法即可。 自定义评估指标可以帮助用户更全面地了解模型的性能,并根据实际需求选择最佳模型。

代码实践:

import xgboost as xgb from sklearn.model_selection import train_test_split from sklearn.datasets import make_regression import numpy as np # 1. 创建回归数据集 X, y = make_regression(n_samples=1000, n_features=10, noise=0.1, random_state=42) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 2. 自定义 MAE 损失函数 def mae_obj(y_pred, dtrain): '''MAE objective function.''' y_true = dtrain.get_label() grad = np.sign(y_pred - y_true) hess = np.zeros_like(grad) # MAE 的二阶导数为 0 return grad, hess # 3. 自定义 MAPE 评估指标 def mape_eval(y_pred, dtrain): '''MAPE evaluation metric.''' y_true = dtrain.get_label() y_true = np.abs(y_true) # 避免除以 0 错误,实际应用中需要更严谨的处理 y_pred = np.abs(y_pred) # 避免除以 0 错误,实际应用中需要更严谨的处理 mape = np.mean(np.abs((y_true - y_pred) / y_true)) * 100 return 'mape', mape # 4. 使用自定义损失函数和评估指标训练 XGBoost 模型 dtrain = xgb.DMatrix(X_train, label=y_train) dtest = xgb.DMatrix(X_test, label=y_test) params = { 'objective': mae_obj, # 使用自定义损失函数 'eval_metric': mape_eval, # 使用自定义评估指标 'seed': 42, } watchlist = [(dtrain, 'train'), (dtest, 'eval')] bst = xgb.train(params, dtrain, num_boost_round=100, evals=watchlist) y_pred_custom = bst.predict(dtest) # 5. 使用默认 RMSE 评估指标作为对比 params_default_eval = { 'objective': 'reg:squarederror', # 使用默认 MSE 损失函数 'eval_metric': 'rmse', # 使用默认 RMSE 评估指标 'seed': 42, } bst_default_eval = xgb.train(params_default_eval, dtrain, num_boost_round=100, evals=watchlist) y_pred_default = bst_default_eval.predict(dtest) # 6. 评估模型性能 (这里只打印 MAPE,RMSE 可以自行计算) print("\n使用自定义 MAE 损失函数和 MAPE 评估指标的模型:") print(f"MAPE: {mape_eval(y_pred_custom, dtest)[1]}%") print("\n使用默认 RMSE 评估指标的模型:") print(f"MAPE: {mape_eval(y_pred_default, dtest)[1]}%") # 仍然使用 MAPE 评估,方便对比

代码详解:

  • 代码首先创建了一个回归数据集。

  • 然后,定义了两个自定义函数:mae_objmape_eval

    • mae_obj 函数实现了 MAE 损失函数的一阶梯度和二阶梯度计算。 对于 MAE 损失函数,一阶梯度为 sign(y_pred - y_true),二阶梯度为 0。

    • mape_eval 函数实现了 MAPE (Mean Absolute Percentage Error) 评估指标的计算。

  • xgb.train 函数中,通过 objective 参数指定自定义损失函数 mae_obj,通过 eval_metric 参数指定自定义评估指标 mape_eval

  • 为了对比,还训练了一个使用默认 RMSE 评估指标的模型。

  • 最后,评估并打印了两个模型的 MAPE 值。 可以看到,使用自定义 MAE 损失函数训练的模型在 MAPE 指标上可能表现更好,这取决于具体的数据集和任务需求。

Graph TD 图:

图表解释:

该图表展示了自定义损失函数和评估指标的流程。 首先,需要定义自定义的损失函数(计算梯度和二阶梯度)和评估指标(计算指标值)。 然后,准备 XGBoost 的 DMatrix 数据,并设置 XGBoost 参数,包括指定自定义的损失函数和评估指标。 最后,使用 XGBoost 进行模型训练,并使用自定义的评估指标评估模型性能。

3. 单调约束 (Monotonic Constraints)

内容详解:

单调约束是指强制模型学习到的特征与目标变量之间存在单调关系。 单调递增约束意味着随着特征值的增加,目标变量的值也应该增加或保持不变;单调递减约束则相反。 在某些领域,例如金融、医学等,单调约束非常重要,因为我们通常期望某些特征与目标变量之间存在明确的单调关系。 例如,在信用评分模型中,我们期望收入越高,信用评分越高,这是一个单调递增关系。

XGBoost 允许用户通过 monotone_constraints 参数来设置单调约束。 monotone_constraints 参数接受一个字典,键为特征索引(或特征名,如果 DMatrix 包含特征名),值为约束类型,可以是 1 (单调递增)、-1 (单调递减) 或 0 (无约束)。

代码实践:

import xgboost as xgb from sklearn.model_selection import train_test_split from sklearn.datasets import make_regression import pandas as pd # 1. 创建模拟数据集 (假设特征 0 和目标变量存在单调递增关系) np.random.seed(42) n_samples = 1000 X = pd.DataFrame({ 'feature_0': np.sort(np.random.rand(n_samples)), # 特征 0 单调递增 'feature_1': np.random.rand(n_samples), 'feature_2': np.random.rand(n_samples) }) y = 2 * X['feature_0'] + 0.5 * X['feature_1'] - 0.8 * X['feature_2'] + np.random.randn(n_samples) * 0.1 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 2. 使用单调约束训练 XGBoost 模型 (特征 0 单调递增) dtrain = xgb.DMatrix(X_train, label=y_train, feature_names=X_train.columns) # 包含特征名 dtest = xgb.DMatrix(X_test, label=y_test, feature_names=X_test.columns) params_monotonic = { 'objective': 'reg:squarederror', 'eval_metric': 'rmse', 'seed': 42, 'monotone_constraints': {'feature_0': 1} # 设置特征 0 为单调递增 } watchlist = [(dtrain, 'train'), (dtest, 'eval')] bst_monotonic = xgb.train(params_monotonic, dtrain, num_boost_round=100, evals=watchlist) y_pred_monotonic = bst_monotonic.predict(dtest) # 3. 不使用单调约束作为对比 params_no_monotonic = { 'objective': 'reg:squarederror', 'eval_metric': 'rmse', 'seed': 42, } bst_no_monotonic = xgb.train(params_no_monotonic, dtrain, num_boost_round=100, evals=watchlist) y_pred_no_monotonic = bst_no_monotonic.predict(dtest) # 4. 可视化单调约束的影响 (仅特征 0) import matplotlib.pyplot as plt feature_0_test = X_test['feature_0'].sort_values() y_pred_monotonic_sorted = bst_monotonic.predict(dtest.slice(feature_0_test.index)) # 保持特征 0 排序顺序 y_pred_no_monotonic_sorted = bst_no_monotonic.predict(dtest.slice(feature_0_test.index)) plt.figure(figsize=(10, 6)) plt.plot(feature_0_test, y_pred_monotonic_sorted, label='Monotonic Constraint') plt.plot(feature_0_test, y_pred_no_monotonic_sorted, label='No Constraint') plt.xlabel('Feature 0 (Sorted)') plt.ylabel('Predicted Value') plt.title('Impact of Monotonic Constraint on Feature 0') plt.legend() plt.grid(True) plt.show()

代码详解:

  • 代码首先创建了一个模拟回归数据集,其中特征 0 被设计为与目标变量存在单调递增关系。

  • 然后,在训练 XGBoost 模型时,通过 monotone_constraints 参数设置了特征 0 的单调递增约束 ({'feature_0': 1}). 注意,这里 DMatrix 包含了特征名 feature_names=X_train.columns, 这样 monotone_constraints 才能使用特征名作为键。

  • 为了对比,还训练了一个没有单调约束的模型。

  • 最后,可视化了两个模型在特征 0 上的预测结果。 可以看到,使用单调约束的模型学习到的特征 0 与预测值之间呈现单调递增关系,而没有单调约束的模型则可能不满足单调性。

Graph TD 图:

图表解释:

该图表展示了应用单调约束的流程。 首先,需要理解业务场景和特征与目标变量之间的关系,确定哪些特征应该施加单调约束。 然后,在 XGBoost 模型训练时,设置 monotone_constraints 参数,指定需要单调约束的特征和约束类型。 训练完成后,进行模型预测和评估,评估时需要检查模型是否满足单调性约束,并评估模型性能。

4. Tree SHAP (Tree SHAP for Explainability)

内容详解:

Tree SHAP (SHapley Additive exPlanations for Tree models) 是一种用于解释树模型预测结果的强大工具。 它基于博弈论中的 Shapley 值,将每个特征对预测结果的贡献分解为一个个数值,称为 SHAP 值。 SHAP 值可以帮助我们理解:

  • 全局特征重要性: 通过汇总所有样本的 SHAP 值,可以得到每个特征的全局重要性,了解哪些特征对模型预测结果影响最大。 这与传统的特征重要性 (例如 XGBoost 的 feature_importance_) 不同,SHAP 值提供了更一致和可靠的特征重要性度量。

  • 个体预测解释: 对于单个样本的预测结果,SHAP 值可以解释每个特征是如何影响该样本的预测值的,是正向影响还是负向影响,影响程度是多少。 这有助于理解模型的决策过程,并进行模型调试和改进。

XGBoost 集成了 Tree SHAP 算法,可以通过 shap 包方便地使用。

代码实践:

import xgboost as xgb from sklearn.model_selection import train_test_split from sklearn.datasets import make_classification import shap # 1. 创建分类数据集 X, y = make_classification(n_samples=100, n_features=20, random_state=42) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 2. 训练 XGBoost 分类器 xgb_classifier = xgb.XGBClassifier( objective='binary:logistic', eval_metric='logloss', use_label_encoder=False, # 避免警告 random_state=42 ) xgb_classifier.fit(X_train, y_train) # 3. 使用 Tree SHAP 解释模型 explainer = shap.TreeExplainer(xgb_classifier) shap_values = explainer.shap_values(X_test) # 计算测试集样本的 SHAP 值 (二分类问题返回 list,取 class 1 的 SHAP 值) # 4. 可视化 SHAP 值 # 4.1 全局特征重要性 (summary plot) shap.summary_plot(shap_values, X_test, feature_names=[f'feature_{i}' for i in range(X_test.shape[1])]) # 4.2 个体预测解释 (force plot - 第一个样本) shap.force_plot(explainer.expected_value, shap_values[0,:], X_test[0,:], feature_names=[f'feature_{i}' for i in range(X_test.shape[1])]) # 4.3 个体预测解释 (decision plot - 第一个样本) shap.decision_plot(explainer.expected_value, shap_values[0,:], feature_names=[f'feature_{i}' for i in range(X_test.shape[1])]) # 4.4 特征依赖图 (dependence plot - 第一个特征) shap.dependence_plot(0, shap_values, X_test, feature_names=[f'feature_{i}' for i in range(X_test.shape[1])])

代码详解:

  • 代码首先创建了一个分类数据集并训练了一个 XGBoost 分类器。

  • 然后,使用 shap.TreeExplainer(xgb_classifier) 创建了一个 Tree SHAP 解释器。

  • 使用 explainer.shap_values(X_test) 计算了测试集样本的 SHAP 值。 对于二分类问题,shap_values 返回一个 list,我们需要取 class 1 的 SHAP 值进行解释。

  • 代码展示了四种常用的 SHAP 值可视化方法:

    • shap.summary_plot: 汇总所有样本的 SHAP 值,展示全局特征重要性。

    • shap.force_plot: 使用力导向图解释单个样本的预测结果,直观展示每个特征的贡献方向和大小。

    • shap.decision_plot: 使用决策图解释单个样本的预测路径,展示特征值如何逐步影响最终预测结果。

    • shap.dependence_plot: 展示单个特征的 SHAP 值与特征值本身之间的依赖关系,帮助理解特征效应。

Graph TD 图:

图表解释:

该图表展示了使用 Tree SHAP 解释 XGBoost 模型的流程。 首先,训练一个 XGBoost 模型。 然后,创建一个 Tree SHAP Explainer,并输入样本数据计算 SHAP 值。 最后,可以使用不同的可视化方法 (summary plot, force plot, decision plot, dependence plot) 分析 SHAP 值,从而进行全局特征重要性分析、个体预测解释和特征效应分析。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U