XGBoost参数调优

在机器学习中,参数调优是一门玄学,因为模型的最优参数可能依赖于许多场景。因此,不可能为参数调优创建一个全面的指南。本文尝试为XGBoost中的参数提供一些指导。

一. 思路概述

1.1 理解偏差-方差权衡(Bias-Variance Tradeoff)

如果你参加过机器学习或统计学课程,这可能是最重要的概念之一。当我们允许模型变得更加复杂(例如,增加深度)时,模型具有更好的拟合训练数据的能力,从而获得偏差较小的模型。然而,这种复杂的模型需要更多的数据来进行拟合。

XGBoost中的大多数参数都涉及偏差和方差的权衡。最好的模型应该在模型复杂度和预测能力之间进行仔细权衡。参数文档会告诉你每个参数是否会使模型更保守。这可以帮助你在复杂模型和简单模型之间进行调整。

1.2 控制过拟合

当你观察到训练准确率高但测试准确率低时,很可能遇到了过拟合问题。

在XGBoost中,一般有两种方法可以控制过拟合:

  • 第一种方法是直接控制模型复杂度。

    这包括max_depth、min_child_weight和gamma。

  • 第二种方法是增加随机性,使训练对噪声具有鲁棒性。

这包括subsample和colsample_bytree。

你还可以减少步长eta。记住在这样做时增加num_round。

1.3 处理数据集不平衡

对于诸如广告点击日志等常见情况,数据集极度不平衡。这会影响XGBoost模型的训练,有两种方法可以改进。

如果你只关心预测的整体性能指标(AUC)

  • 通过scale_pos_weight平衡正负样本的权重

  • 使用AUC作为评估标准

如果你关心预测的正确概率

  • 在这种情况下,你不能重新平衡数据集

  • 将参数max_delta_step设置为一个有限的数值(例如1)以帮助收敛

1.4 减少内存使用

如果你使用类似sklearn.model_selection.GridSearchCV的HPO库,请控制它可以使用的线程数。最好让XGBoost并行运行,而不是让GridSearchCV同时运行多个实验。例如,为交叉验证创建一个数据折叠可以消耗大量内存:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 这会创建数据集的副本。X和X_train同时存在于内存中。
# 如果你在n_jobs大于1的情况下运行`GridSearchCV`,每个线程都会同时发生这种情况。
X_train, X_test, y_train, y_test = train_test_split(X, y)

df = pd.DataFrame()
# 这会创建数据框的新副本,即使你指定了inplace参数
new_df = df.drop(...)

array = np.array(...)
# 这可能会也可能不会复制数据,具体取决于数据类型
array.astype(np.float32)

# np默认使用双精度,你真的需要吗?
array = np.array(...)

你可以在文档中找到一些更具体的减少内存使用的实践。例如:与Dask的分布式XGBoost、XGBoost GPU支持。然而,在深入研究这些之前,要意识到数据副本的创建是一个好的起点。它通常消耗的内存比人们预期的要多得多

二. XGB参数详解

在运行 XGBoost 之前, 我们必须设置三种类型的参数: 常规参数, 提升器参数和任务参数.

  • 常规参数与我们用于提升的提升器有关,通常是树模型或线性模型
  • 提升器参数取决于你所选择的提升器
  • 学习任务的参数决定了学习场景, 例如回归任务可以使用不同的参数进行排序相关的任务
  • 命令行参数的行为与 xgboost 的 CLI 版本相关

2.1 常规参数

booster [默认=gbtree]

选择使用哪种booster,可以是gbtree、gblinear或dart。gbtree和dart使用基于树的模型,而gblinear使用线性函数。

silent [默认=0]

0表示打印运行信息,1表示静默模式。

nthread [默认值为可用的最大线程数,如果未设置]

用于运行xgboost的并行线程数。

num_pbuffer [由xgboost自动设置,无需用户设置]

预测缓冲区的大小,通常设置为训练实例的数量。缓冲区用于保存上一次boosting步骤的预测结果。

num_feature [由xgboost自动设置,无需用户设置]

boosting过程中使用的特征维度,设置为特征的最大维度。

2.2 用于 Tree 提升的参数

⭐eta [默认=0.3]

用于更新的步长缩减,以防止过拟合。在每个提升步骤之后,我们可以直接获得新特征的权重。eta 实际上是缩小了特征权重,使提升过程更加保守。 范围: [0,1]

⭐gamma [默认=0]

在树的叶节点上进行进一步分区所需的最小损失减少量。值越大,算法越保守。 范围: [0,∞]

⭐max_depth [默认=6]

树的最大深度,增加此值将使模型更加复杂/更容易过拟合。 范围: [1,∞]

⭐min_child_weight [默认=1]

子节点所需的实例权重(赫西安矩阵)的最小和。如果树分区步骤导致叶节点的实例权重和小于 min_child_weight,那么构建过程将放弃进一步分区。在线性回归模式下,这仅对应于每个节点所需的最小实例数。值越大,算法越保守。 范围: [0,∞]

max_delta_step [默认=0]

每棵树的权重估计允许的最大步长。如果设置为0,则表示没有约束。如果设置为正值,可以帮助使更新步骤更加保守。通常不需要此参数,但在类极不平衡的逻辑回归中可能会有所帮助。设置为1-10的值可能有助于控制更新。 范围: [0,∞]

subsample [默认=1]

训练实例的子采样比例。设置为0.5表示XGBoost随机收集一半的数据实例来生长树,这将防止过拟合。 范围: (0,1]

colsample_bytree [默认=1]

构建每棵树时的列的子采样比例。 范围: (0,1]

colsample_bylevel [默认=1]

在每个层次上分割时的列的子采样比例。 范围: (0,1]

⭐lambda [默认=1]

权重上的L2正则化项,增加此值将使模型更加保守。

alpha [默认=0]

权重上的L1正则化项,增加此值将使模型更加保守。

tree_method, string [默认=‘auto’]

XGBoost中使用的树构建算法(参见参考文献中的描述)。 分布式和外部存储版本仅支持近似算法。 选择:{‘auto’, ‘exact’, ‘approx’}

‘auto’: 使用启发式方法选择更快的算法。 对于中小型数据集,将使用精确贪婪算法。 对于非常大的数据集,将选择近似算法。 由于旧行为始终在单机上使用精确贪婪算法,因此在选择近似算法时用户将收到通知。 ‘exact’: 精确贪婪算法。 ‘approx’: 使用素描和直方图的近似贪婪算法。

sketch_eps, [默认=0.03]

仅用于近似贪婪算法。 这大致转换为 O(1 / sketch_eps) 个箱子的数量。相比于直接选择箱子的数量,这种方法带有理论上的素描准确性保证。 通常用户不需要调整此参数,但可以考虑设置为较低的值以获得更准确的枚举。 范围: (0, 1)

⭐scale_pos_weight, [默认=0]

控制正负权重的平衡,对不平衡类别有用。一个典型的考虑值是:sum(负例) / sum(正例)。详见参数调优中的更多讨论。参见 Higgs Kaggle 比赛的示例:R, py1, py2, py3

2.3 学习任务的参数

指定学习任务及相应的学习目标。可选的目标如下:

objective [默认值=reg:linear]

  • “reg:linear” – 线性回归

  • “reg:logistic” – 逻辑回归

  • “binary:logistic” – 用于二分类的逻辑回归,输出概率

  • “binary:logitraw” – 用于二分类的逻辑回归,输出逻辑变换前的得分

  • “count:poisson” – 计数数据的泊松回归,输出泊松分布的均值 泊松回归中max_delta_step默认设为0.7(用于保障优化过程)

  • “multi:softmax” – 使用softmax目标设置XGBoost进行多类分类,还需要设置num_class(类别数)

  • “multi:softprob” – 与softmax相同,但输出一个ndata * nclass的向量,可以进一步重塑为ndata, nclass矩阵。结果包含每个数据点属于每个类别的预测概率。

  • “rank:pairwise” – 设置XGBoost通过最小化成对损失来执行排序任务

  • “reg:gamma” – 用于严重度数据的伽玛回归,输出伽玛分布的均值

base_score [默认值=0.5]

所有实例的初始预测得分,全局偏差 对于足够多的迭代次数,改变这个值不会有太大影响。

⭐eval_metric [默认值根据objective确定]

验证数据的评估指标,将根据objective分配一个默认指标(回归任务为rmse,分类任务为error,排序任务为平均精度) 用户可以添加多个评估指标,对于Python用户,请记住将指标作为参数对的列表传递,而不是映射,这样后面的‘eval_metric’不会覆盖前面的。

可选的评估指标如下:

  • “rmse”:均方根误差

  • “mae”:平均绝对误差

  • “logloss”:负对数似然

  • “error”:二分类错误率。计算方法为 #(错误案例)/#(所有案例)。对于预测,评估会将预测值大于0.5的实例视为正例,其余视为负例。

  • “merror”:多类分类错误率。计算方法为 #(错误案例)/#(所有案例)。

  • “mlogloss”:多类对数损失

  • “auc”:用于排序评估的曲线下面积

  • “ndcg”:归一化折扣累积增益

  • “map”:平均精度

  • “ndcg@n”,“map@n”:n可以设为一个整数,用于截断评估列表中的前n个位置。

  • “ndcg-”,“map-”,“ndcg@n-”,“map@n-”:在XGBoost中,NDCG和MAP将评估没有任何正样本的列表的得分为1。通过在评估指标中添加“-”,XGBoost将在某些条件下将这些得分评估为0。

  • “gamma-deviance”: [伽玛回归的残差偏差]

seed [默认值=0]

随机数种子。

2.4 用于 Dart Booster 的其它参数

sample_type [默认值=”uniform”]

采样算法的类型。
“uniform”:均匀选择丢弃的树。
“weighted”:按权重比例选择丢弃的树。

normalize_type [默认值=”tree”]

归一化算法的类型。
“tree”:新树的权重与每棵丢弃的树相同。
新树的权重为 1 / (k + 学习率)
丢弃的树按 k / (k + 学习率) 进行缩放。
“forest”:新树的权重与丢弃树(森林)的权重总和相同。
新树的权重为 1 / (1 + 学习率)
丢弃的树按 1 / (1 + 学习率) 进行缩放。

rate_drop [默认值=0.0]

丢弃率。
范围:[0.0, 1.0]

2.5 用于 Linear Booster 的参数

skip_drop [默认值=0.0]

跳过丢弃的概率。
如果跳过丢弃,新树将以与 gbtree 相同的方式添加。
范围:[0.0, 1.0]

lambda [默认值=0]

权重的L2正则化项,增加这个值会使模型更加保守。

alpha [默认值=0] 权重的L1正则化项,增加这个值会使模型更加保守。

lambda_bias

偏置的L2正则化项,默认值为0(没有偏置的L1正则化,因为它不重要)。

三. XGB代码示例

此代码用于二分类问题,使用XGB建模,并输出评估报告,绘制AUC曲线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import xgboost as xgb
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import roc_auc_score,roc_curve
from sklearn.metrics import classification_report

# 参数设置
params={
'booster':'gblinear',
'objective':'binary:logistic',
'metric':'auc',
'eval_metric':'auc',
'eta':0.0425,
'max_depth':15,
'min_child_weight':20,
'gamma':0,
'subsample':1,
'colsample_bytree':1,
'scale_pos_weight':1
}

dtrain = xgb.DMatrix(x, y)

lr_class_weight = xgb.train(params=params,dtrain=dtrain,num_boost_round=165)
# 加载测试数据
data_test = test_slct3

data_test_encoding = pd.get_dummies(data_test)
y_test = data_test_encoding['Attrition']
x_test = transfer.transform(data_test_encoding.drop('Attrition', axis=1))

# 使用xgb.DMatrix进行预测
y_pre_prob = lr_class_weight.predict(xgb.DMatrix(x_test))
y_pre = (y_pre_prob >= 0.70).astype(int) # 将概率转换为0或1

train_y_pre_prob = lr_class_weight.predict(xgb.DMatrix(x))
train_y_pre = (train_y_pre_prob >= 0.70).astype(int) # 将概率转换为0或1

# 计算并打印ROC AUC得分
roc_auc = roc_auc_score(y_test, y_pre_prob)
print(f"ROC AUC Score: {roc_auc}")

# 计算并打印ROC AUC得分
roc_auc = roc_auc_score(y_test, y_pre_prob)
print(f"ROC AUC Score: {roc_auc}")

# 生成并打印classification_report
report = classification_report(y_test, y_pre)
print(report)
# 绘制ROC曲线
fpr, tpr, _ = roc_curve(y_test, y_pre_prob)
fpr_train, tpr_train,_=roc_curve(y, train_y_pre_prob)
plt.plot(fpr, tpr, label='evl ROC')
plt.plot(fpr_train, tpr_train, label='Train ROC')
plt.plot([0, 1], [0, 1], 'k--')
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC Curve')
plt.legend(loc='best')
plt.show()

XGBoost参数调优
https://linxkon.github.io/XGB参数调优.html
作者
linxkon
发布于
2020年10月1日
许可协议