在上一篇文章中我们已经了解到GBDT 是一种强大的集成学习方法,具有高准确性、良好的泛化能力和处理非线性关系的优势。
但是其仍存在训练时间长、难以并行化和超参数调优复杂等缺点。而XGBT(Extreme Gradient Boosting) 是一种改进的 GBDT,旨在解决上述问题。

1. XGBT相对GBDT的优化

  • 正则化
    XGBoost 在目标函数中引入了正则化项,以控制模型的复杂度,防止过拟合。

  • 二阶导数信息
    XGBoost 利用损失函数的一阶和二阶导数信息来构建树,优化效率更高。

  • Shrinkage(缩减)
    在每一轮迭代后,缩减新树的贡献,防止过拟合。

  • 列抽样
    类似于随机森林的思想,XGBoost 在构建每棵树时,随机抽样一部分特征,从而增加了模型的多样性,减少了过拟合。

  • 并行化
    XGBoost 通过并行化实现了更高效的训练过程。这里的并行化体现在两大部分:

    • 特征分裂点搜索的并行化
      在每次选择最佳分裂点时,XGBoost会对所有特征进行遍历,计算每个特征的最佳分裂点增益。这一过程是可以并行化的,即在不同的线程或进程中同时计算不同特征的分裂增益。最终,选择所有计算结果中增益最大的分裂点。
    • 数据块结构(Block Structure)
      XGBoost引入了特定的数据块结构,称为“块化并行”(Block-wise Parallelism)。数据被分成多个块,每个块包含一部分样本和所有特征。块与块之间是独立的,可以并行处理。这种结构使得在分布式系统中,每个节点可以独立处理自己的数据块,然后在全局上合并结果。
    • 并行化的梯度计算
      在每次迭代中,XGBoost需要计算所有样本的梯度和Hessian。这一过程可以在多个处理单元上并行计算,然后将结果汇总。梯度和Hessian的计算是独立的,不同样本之间没有依赖关系,因此可以高效并行化。
  • 分布式计算
    对于特别大的数据集,单机内存可能不足以容纳所有数据。XGBoost支持分布式训练,将数据分布在多个计算节点上,每个节点独立训练局部模型,然后在全局上合并结果。这种方法利用了集群计算的强大处理能力,显著提高了训练效率。

将这些概念代入数学,我们可以得到对应推理公式。

2. 推理公式

  1. 初始化模型
    对于回归问题,初始模型是一个常数预测,即所有样本的均值。

    \hat{y}_i^{(0)} = \frac{1}{N} \sum_{i=1}^{N} y_i
  2. 定义目标函数
    XGBoost的目标是最小化一个带有正则化项的目标函数。

    L(\phi) = \sum_{i=1}^{N} l(y_i, \hat{y}_i^{(t)}) + \sum_{k=1}^{t} \Omega(f_k)
    • \sum_{i=1}^{N} l(y_i, \hat{y}_i) 是损失函数项,评估所有样本的预测误差。(在回归中为均方MSE,在分类中为交叉熵Log Loss)
    • \sum_{k=1}^{t} \Omega(f_k) 是正则化项,评估模型复杂度。
    \Omega(f) = \gamma T + \frac{1}{2} \lambda \sum_{j=1}^{T} w_j^2
    • \gamma T 是树的叶节点数量的惩罚项,T表示一棵树叶子的数量。
    • \frac{1}{2} \lambda \sum_{j=1}^{T} w_j^2 是叶节点权重的L2正则化,控制叶节点权重的大小,\lambda是调节系数,w是向量的模。
  3. 梯度提升
    每一步中,添加一个新的决策树来拟合当前模型的残差。

    \hat{y}_i^{(t)} = \hat{y}_i^{(t-1)} + f_t(x_i)

    其中,f_t 是在第t步添加的决策树。

  4. 优化目标函数
    经过多次迭代后,目标函数愈发复杂,直接求解比较困难,且基于避免过拟合,我们可以使用二阶泰勒展开,将损失函数近似为:

    L^{(t)} \approx \sum_{i=1}^{N} \left[ l(y_i, \hat{y}_i^{(t-1)}) + g_i f_t(x_i) + \frac{1}{2} h_i f_t^2(x_i) \right] + \Omega(f_t)

    其中,g_i = \frac{\partial l(y_i, \hat{y}_i)}{\partial \hat{y}_i} 是一阶导数,h_i = \frac{\partial^2 l(y_i, \hat{y}_i)}{\partial \hat{y}_i^2} 是二阶导数。

  5. 树的结构得分
    对于每个候选分裂点,计算增益(Gain),选择增益最大的分裂。

    Gain = \frac{1}{2} \left[ \frac{G_L^2}{H_L + \lambda} + \frac{G_R^2}{H_R + \lambda} - \frac{(G_L + G_R)^2}{H_L + H_R + \lambda} \right] - \gamma

    其中,G_LG_R 是左子节点和右子节点的梯度和,H_LH_R 是左子节点和右子节点的Hessian和,\lambda 是正则化参数,\gamma 是分裂的惩罚项。

    • 增益可以用于迭代时优化,选择增益最大的分裂点。
    • 增益还可以用于剪枝,选择增益最大的分裂点
      • 如果设定了阈值,增益小于阈值,则停止迭代。
      • 计算分裂前后分数,如果分裂前分数更好或者相同,停止分裂。

3. 构建过程

我们仍然以上文提到的回归问题且相同为例,构建XGBT的构建过程。

3.1 目标函数和初始预测

初始数据如下:

X y
1 2
2 3
3 6
4 8

我们使用均方误差(MSE)作为损失函数:

L = \frac{1}{N} \sum_{i=1}^{N} (y_i - \hat{y}_i)

初始模型预测值为所有目标值的均值:

\hat{y}_i^{(0)} = \frac{1}{4} (2 + 3 + 6 + 8) = 4.75

3.2 计算残差和梯度

一阶导数(梯度):

g_i = \hat{y}_i - y_i

二阶导数(Hessian):

h_i = 1

计算每个样本的梯度和 Hessian:

X y \hat{y}_i^{(0)} g_i h_i
1 2 4.75 2.75 1
2 3 4.75 1.75 1
3 6 4.75 -1.25 1
4 8 4.75 -3.25 1

3.3 选择最佳分裂点

计算在每个分裂点的增益,选择增益最大的分裂点。设 \lambda = 1\gamma = 0(假设值)。

分裂点 X=1.5:

左节点:

G_L = 2.75, H_L = 1

右节点:

G_R = 1.75 - 1.25 - 3.25 = -2.75, H_R = 3

增益:

Gain = \frac{1}{2} \left( \frac{G_L^2}{H_L + \lambda} + \frac{G_R^2}{H_R + \lambda} - \frac{(G_L + G_R)^2}{H_L + H_R + \lambda} \right) - \gamma \\= \frac{1}{2} \left( \frac{2.75^2}{1 + 1} + \frac{(-2.75)^2}{3 + 1} - \frac{0^2}{4 + 1} \right) = 2.8359375

分裂点 X=2.5:

左节点:

G_L = 2.75 + 1.75 = 4.5, H_L = 2

右节点:

G_R = -1.25 - 3.25 = -4.5, H_R = 2

增益:

Gain = \frac{1}{2} \left( \frac{4.5^2}{2 + 1} + \frac{(-4.5)^2}{2 + 1} - \frac{0^2}{4 + 1} \right) = 6.75

分裂点 X=3.5:

左节点:

G_L = 2.75 + 1.75 - 1.25 = 3.25, H_L = 3

右节点:

G_R = -3.25, H_R = 1

增益:

Gain = \frac{1}{2} \left( \frac{3.25^2}{3 + 1} + \frac{(-3.25)^2}{1 + 1} - \frac{0^2}{4 + 1} \right) = 3.9609375

最佳分裂点是 X=2.5。

更新叶节点值

更新左子节点和右子节点的预测值:

左子节点:

w_L = -\frac{G_L}{H_L + \lambda} = -\frac{4.5}{2 + 1} = -1.5

右子节点:

w_R = -\frac{G_R}{H_R + \lambda} = -\frac{-4.5}{2 + 1} = 1.5

3.4 更新模型

\hat{y}_i^{(1)} = \hat{y}_i^{(0)} + \eta f_1(x_i)

假设学习率 \eta = 1,则:

X \hat{y}_i^{(0)} f_1(x_i) \hat{y}_i^{(1)}
1 4.75 -1.5 4.75 - 1.5*1 = 3.75
2 4.75 -1.5 4.75 - 1.5*1 = 3.75
3 4.75 1.5 4.75 + 1.5*1 = 6.25
4 4.75 1.5 4.75 + 1.5*1 = 6.5

3.5 反复迭代

这里和其它boosting一样,我们需要根据上一学习器的残差来计算新的残差和梯度。为了简化流程,这里仅举例一次迭代。

使用第一轮迭代更新后的预测值:

X y \hat{y}_i^{(1)} 残差g_i 二阶导数h_i
1 2 3.25 1.25 1
2 3 3.25 0.25 1
3 6 6.25 0.25 1
4 8 6.25 -1.75 1

选择最佳分裂点

计算在每个分裂点的增益,选择增益最大的分裂点。设 \lambda = 1\gamma = 0

  • 分裂点 X=1.5:

左节点:

G_L = 1.25, H_L = 1

右节点:

G_R = 0.25 + 0.25 - 1.75 = -1.25, H_R = 3

增益:

Gain = \frac{1}{2} \left( \frac{G_L^2}{H_L + \lambda} + \frac{G_R^2}{H_R + \lambda} - \frac{(G_L + G_R)^2}{H_L + H_R + \lambda} \right) - \gamma
Gain = \frac{1}{2} \left( \frac{1.25^2}{1 + 1} + \frac{(-1.25)^2}{3 + 1} - \frac{0^2}{4 + 1} \right)
Gain = \frac{1}{2} \left( \frac{1.5625}{2} + \frac{1.5625}{4} \right) = \frac{1}{2} \left( 0.78125 + 0.390625 \right) = 0.5859375
  • 分裂点 X=2.5:

左节点:

G_L = 1.25 + 0.25 = 1.5, H_L = 2

右节点:

G_R = 0.25 - 1.75 = -1.5, H_R = 2

增益:

Gain = \frac{1}{2} \left( \frac{1.5^2}{2 + 1} + \frac{(-1.5)^2}{2 + 1} - \frac{0^2}{4 + 1} \right)
Gain = \frac{1}{2} \left( \frac{2.25}{3} + \frac{2.25}{3} \right) = \frac{1}{2} \left( 0.75 + 0.75 \right) = 0.75
  • 分裂点 X=3.5:

左节点:

G_L = 1.25 + 0.25 + 0.25 = 1.75, H_L = 3

右节点:

G_R = -1.75, H_R = 1

增益:

Gain = \frac{1}{2} \left( \frac{1.75^2}{3 + 1} + \frac{(-1.75)^2}{1 + 1} - \frac{0^2}{4 + 1} \right)
Gain = \frac{1}{2} \left( \frac{3.0625}{4} + \frac{3.0625}{2} \right) = \frac{1}{2} \left( 0.765625 + 1.53125 \right) = 1.1484375

最佳分裂点是 X=3.5。

更新叶节点值

更新左子节点和右子节点的预测值:

左子节点:

w_L = -\frac{G_L}{H_L + \lambda} = -\frac{1.75}{3 + 1} = -0.4375

右子节点:

w_R = -\frac{G_R}{H_R + \lambda} = -\frac{-1.75}{1 + 1} = 0.875

更新模型

假设学习率 \eta = 1,则:

\hat{y}_i^{(2)} = \hat{y}_i^{(1)} + \eta f_2(x_i)
X \hat{y}_i^{(1)} f_2(x_i) \hat{y}_i^{(2)}
1 3.25 -0.4375 3.25 - 0.4375 = 2.8125
2 3.25 -0.4375 3.25 - 0.4375 = 2.8125
3 6.25 0.875 6.25 + 0.875 = 7.125
4 6.25 0.875 6.25 + 0.875 = 7.125

3.6 模型验证

我们继续使用上一篇文章中的数据,进行模型验证。

X y
1 2
2 3
3 6
4 8
详细预测步骤
  1. x = 1.5:

    • 初始预测值:4.75
    • 第一轮调整值:-1.5
    • 第一轮后预测值:4.75 - 1.5 = 3.25
    • 第二轮调整值:-0.4375
    • 最终预测值:3.25 - 0.4375 = 2.8125
  2. x = 2.5:

    • 初始预测值:4.75
    • 第一轮调整值:-1.5
    • 第一轮后预测值:4.75 - 1.5 = 3.25
    • 第二轮调整值:-0.4375
    • 最终预测值:3.25 - 0.4375 = 2.8125
  3. x = 3.5:

    • 初始预测值:4.75
    • 第一轮调整值:1.5
    • 第一轮后预测值:4.75 + 1.5 = 6.25
    • 第二轮调整值:0.875
    • 最终预测值:6.25 + 0.875 = 7.125
  4. x = 4.5:

    • 初始预测值:4.75
    • 第一轮调整值:1.5
    • 第一轮后预测值:4.75 + 1.5 = 6.25
    • 第二轮调整值:0.875
    • 最终预测值:6.25 + 0.875 = 7.125

汇总可得下表:

X 初始预测值\hat{y}_i^{(0)} 第一轮调整值f_1(x_i) 第二轮调整值f_2(x_i) 最终预测值\hat{y}_i^{(final)}
1.5 4.75 -1.5 -0.4375 4.75 - 1.5 - 0.4375 = 2.8125
2.5 4.75 -1.5 -0.4375 4.75 - 1.5 - 0.4375 = 2.8125
3.5 4.75 1.5 0.875 4.75 + 1.5 + 0.875 = 7.125
4.5 4.75 1.5 0.875 4.75 + 1.5 + 0.875 = 7.125

可以看到,随着迭代次数的增加,模型预测值逐渐接近真实值。当然,由于我们的迭代次数极少且模型参数设置极简单,所以模型效果并不是很好。

4. 代码实现

4.1 常用python函数

需要注意的是,xgboost不再是sklearn的模型,而是单独的一个包。

import xgboost
import sklearn.model_selection

""" xgboost 类 """
clf = xgboost.XGBClassifier(
    # 树的数量,即迭代次数。
    # 默认值100。调整范围(50-500)。常用值100-300。
    # 增加提高模型拟合能力,但也会增加训练时间和过拟合风险。
    # 一般与 learning_rate 结合调整。
    n_estimators=100,

    # 学习率,控制每棵树对最终模型的贡献。
    # 默认值0.3。调整范围(0.01-0.3)。常用值0.1。
    # 较小的学习率可以让模型更加稳健,但需要更多的树。
    learning_rate=0.1,

    # 树的最大深度。
    # 默认值6。调整范围(3-10)。常用值3-8。
    # 较深的树可以拟合更加复杂的关系,但也容易过拟合。
    max_depth=6,

    # L2正则化项的权重。
    # 默认值1。调整范围(0-10)。常用值0-3。
    # 增加此参数可以减少过拟合。
    reg_lambda=1,

    # L1正则化项的权重。
    # 默认值0。调整范围(0-10)。常用值0-1。
    # 增加此参数可以减少过拟合。
    reg_alpha=0,

    # 树的子样本比例。
    # 默认值1。调整范围(0.5-1)。常用值0.7-1。
    # 设置为小于1时,算法会随机抽样部分数据来训练树,增加模型的随机性。
    subsample=1,

    # 特征的子样本比例。
    # 默认值1。调整范围(0.5-1)。常用值0.7-1。
    # 设置为小于1时,算法会随机抽样部分特征来训练树,增加模型的随机性。
    colsample_bytree=1,

    # 最小的叶子节点样本权重和。
    # 默认值1。调整范围(1-10)。常用值1-5。
    # 增加此参数可以减少过拟合。
    min_child_weight=1,

    # 每次树分裂的最小损失减少。
    # 默认值0。调整范围(0-1)。常用值0-0.1。
    # 增加此参数可以减少过拟合。
    gamma=0,

    # 树的生长策略。
    # 可选值为 'auto', 'exact', 'approx', 'hist', 'gpu_hist'。默认值为 'auto'。
    #'exact' 贪心算法,找到最优分裂点(小数据集,高精度要求),
    #'approx' 近似搜索,提高速度,保持较高精度(中数据集)
    #'hist' 直方图搜索,大幅提高速度,降低内存使用(大规模数据)
    #'gpu_hist' GPU直方图搜索。(gpu加速)
    # 商业应用中一般选择 'hist' 或 'gpu_hist' 以提高训练速度。
    tree_method='auto',

    # 随机种子。
    # 默认值0。调整范围(0-1000)。常用值0-42。
    # 设置随机种子以便结果可重现。
    random_state=0
)


""" 将数据转换为 DMatrix 
DMatrix 是 XGBoost 的内部数据结构,专门用于高效存储和处理数据。它在内存利用率和计算效率上进行了优化,
尤其适合于大规模数据集。创建 DMatrix 的过程包括将数据和标签传递给 DMatrix 类,然后可以使用这个结构进行训练和预测。
"""

X_train = [[1, 2], [3, 4], [5, 6], [7, 8]]
y_train = [0, 1, 0, 1]
X_test = [[2, 3], [4, 5], [6, 7]]
y_test = [0, 1, 0]

dtrain = xgb.DMatrix(X_train, label=y_train)
dtest = xgb.DMatrix(X_test, label=y_test)


""" xgboost 训练器,提供细粒度控制,并支持 DMatrix"""
params = {
    # 树的最大深度。
    # 默认值6。调整范围(3-10)。常用值3-8。
    # 较大值增加模型的复杂度和训练时间,但可能提高准确性。
    'max_depth': 6,
  
    # 学习率,控制每棵树对最终模型的贡献。
    # 默认值0.3。调整范围(0.01-0.3)。常用值0.1。
    # 较小的学习率需要更多的树,较大的学习率可能导致过拟合。
    'eta': 0.1,
  
    # 树的生长策略。
    # 默认值 'auto'。可选值包括 'exact', 'approx', 'hist', 'gpu_hist'。
    # 商业应用中常用 'hist' 或 'gpu_hist' 以提高训练速度。
    'tree_method': 'hist',
  
    # 目标函数。
    # 根据任务选择,回归任务一般为 'reg:squarederror',分类任务为 'binary:logistic'。
    # 其他目标函数根据具体需求调整。
    'objective': 'binary:logistic',
  
    # 评估指标。
    # 默认值无。可以设置为 'auc', 'logloss' 等。
    # 商业应用中常用 'auc' 评估分类任务的性能。
    'eval_metric': 'auc',
  
    # L2正则化项权重。
    # 默认值1。调整范围(0-10)。常用值0-3。
    # 增加此参数可以减少过拟合。
    'lambda': 1,
  
    # L1正则化项权重。
    # 默认值0。调整范围(0-10)。常用值0-1。
    # 增加此参数可以减少过拟合。
    'alpha': 0,
  
    # 样本子集采样率。
    # 默认值1。调整范围(0.5-1)。常用值0.7-1。
    # 设置为小于1时,可以防止过拟合。
    'subsample': 1,
  
    # 特征子集采样率。
    # 默认值1。调整范围(0.5-1)。常用值0.7-1。
    # 设置为小于1时,可以防止过拟合。
    'colsample_bytree': 1,
}

bst = xgb.train(
    params, 
    dtrain, 
    num_boost_round=100,  # 树的数量,即迭代次数。默认值10。调整范围(50-500)。常用值100-300。
    evals=[(dtrain, 'train'), (dtest, 'eval')],  # 评估数据,用于监控模型性能。
    early_stopping_rounds=10,  # 提前停止的轮数。如果在指定轮数内评估指标没有提升,则停止训练。
    evals_result={},  # 用于存储评估结果的字典。
    verbose_eval=True  # 是否输出训练过程中的评估结果。
)

""" 展示单颗树结构 """
xgboost.plot_tree(clf, num_trees=0)


""" xgboost长伴随网格搜索适用,用于超参调优 """
sklearn.model_selection.GridSearchCV.param_grid = {
    'n_estimators': [100, 200, 300],
    'learning_rate': [0.01, 0.1, 0.2],
    'max_depth': [3, 5, 7],
    'subsample': [0.7, 0.8, 0.9],
    'colsample_bytree': [0.7, 0.8, 0.9]
}
grid_search = sklearn.model_selection.GridSearchCV(clf, param_grid, scoring='roc_auc', cv=3)

4.2 代码应用

我们将使用Kaggle的一个客户流失数据集,该数据集包含客户的基本信息以及他们是否流失的标记。

数据集

我们将使用Kaggle的Telco Customer Churn数据集,下载链接:Telco Customer Churn

1. 数据预处理

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
import time

# 读取数据
data = pd.read_csv('WA_Fn-UseC_-Telco-Customer-Churn.csv')

# 数据预处理
data = data.drop(columns=['customerID'])
data['TotalCharges'] = pd.to_numeric(data['TotalCharges'], errors='coerce')
data = data.dropna()

# 编码分类变量
label_encoders = {}
for column in data.select_dtypes(include=['object']).columns:
    le = LabelEncoder()
    data[column] = le.fit_transform(data[column])
    label_encoders[column] = le

# 特征和标签
X = data.drop(columns=['Churn'])
y = data['Churn']

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

2. 使用XGBoost进行训练和预测

import xgboost as xgb
from sklearn.metrics import classification_report, confusion_matrix

# 创建DMatrix
dtrain = xgb.DMatrix(X_train, label=y_train)
dtest = xgb.DMatrix(X_test, label=y_test)

# 设置参数
params = {
    'max_depth': 3,
    'eta': 0.1,
    'objective': 'binary:logistic',
    'eval_metric': 'auc',
    'tree_method': 'gpu_hist'  # 使用并行处理的树构建方法
}

# 训练模型
start_time = time.time()
bst = xgb.train(params, dtrain, num_boost_round=100, evals=[(dtest, 'test')], early_stopping_rounds=10)
xgb_train_time = time.time() - start_time

# 预测
start_time = time.time()
y_pred_prob = bst.predict(dtest)
xgb_predict_time = time.time() - start_time
y_pred = np.round(y_pred_prob).astype(int)

# 评估模型
print("XGBoost Classification Report:\n", classification_report(y_test, y_pred))
print("XGBoost Confusion Matrix:\n", confusion_matrix(y_test, y_pred))
print("XGBoost Training Time:", xgb_train_time)
print("XGBoost Prediction Time:", xgb_predict_time)

3. 使用GBDT进行训练和预测

from sklearn.ensemble import GradientBoostingClassifier

# 创建GBDT模型
gbdt = GradientBoostingClassifier(
    n_estimators=100,
    learning_rate=0.1,
    max_depth=3,
    random_state=42
)

# 训练模型
start_time = time.time()
gbdt.fit(X_train, y_train)
gbdt_train_time = time.time() - start_time

# 预测
start_time = time.time()
y_pred_gbdt = gbdt.predict(X_test)
gbdt_predict_time = time.time() - start_time

# 评估模型
print("GBDT Classification Report:\n", classification_report(y_test, y_pred_gbdt))
print("GBDT Confusion Matrix:\n", confusion_matrix(y_test, y_pred_gbdt))
print("GBDT Training Time:", gbdt_train_time)
print("GBDT Prediction Time:", gbdt_predict_time)

评估和对比结果

我们将在控制台输出中包括训练时间和预测时间的指标。

综合示例

完整的代码如下:

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import classification_report, confusion_matrix
from sklearn.ensemble import GradientBoostingClassifier
import xgboost as xgb
import time

# 读取数据
data = pd.read_csv('WA_Fn-UseC_-Telco-Customer-Churn.csv')

# 数据预处理
data = data.drop(columns=['customerID'])
data['TotalCharges'] = pd.to_numeric(data['TotalCharges'], errors='coerce')
data = data.dropna()

# 编码分类变量
label_encoders = {}
for column in data.select_dtypes(include=['object']).columns:
    le = LabelEncoder()
    data[column] = le.fit_transform(data[column])
    label_encoders[column] = le

# 特征和标签
X = data.drop(columns=['Churn'])
y = data['Churn']

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 创建DMatrix
dtrain = xgb.DMatrix(X_train, label=y_train)
dtest = xgb.DMatrix(X_test, label=y_test)

# 设置XGBoost参数
params = {
    'max_depth': 3,
    'eta': 0.1,
    'objective': 'binary:logistic',
    'eval_metric': 'auc',
    'tree_method': 'hist'  # 使用并行处理的树构建方法
}

# 训练XGBoost模型
start_time = time.time()
bst = xgb.train(params, dtrain, num_boost_round=100, evals=[(dtest, 'test')], early_stopping_rounds=10)
xgb_train_time = time.time() - start_time

# XGBoost预测
start_time = time.time()
y_pred_prob = bst.predict(dtest)
xgb_predict_time = time.time() - start_time
y_pred = np.round(y_pred_prob).astype(int)

# 评估XGBoost模型
print("XGBoost Classification Report:\n", classification_report(y_test, y_pred))
print("XGBoost Confusion Matrix:\n", confusion_matrix(y_test, y_pred))
print("XGBoost Training Time:", xgb_train_time)
print("XGBoost Prediction Time:", xgb_predict_time)

# 创建GBDT模型
gbdt = GradientBoostingClassifier(
    n_estimators=100,
    learning_rate=0.1,
    max_depth=3,
    random_state=42
)

# 训练GBDT模型
start_time = time.time()
gbdt.fit(X_train, y_train)
gbdt_train_time = time.time() - start_time

# GBDT预测
start_time = time.time()
y_pred_gbdt = gbdt.predict(X_test)
gbdt_predict_time = time.time() - start_time

# 评估GBDT模型
print("GBDT Classification Report:\n", classification_report(y_test, y_pred_gbdt))
print("GBDT Confusion Matrix:\n", confusion_matrix(y_test, y_pred_gbdt))
print("GBDT Training Time:", gbdt_train_time)
print("GBDT Prediction Time:", gbdt_predict_time)

输出示例

xgboost train time=0.4810643196105957,predict time=0.0029926300048828125
GDBT train time=1.752678394317627,predict time=0.004985332489013672


this follow is report of xgboost:
              precision    recall  f1-score   support

           0       0.83      0.89      0.86      1023
           1       0.64      0.53      0.58       386

    accuracy                           0.79      1409
   macro avg       0.74      0.71      0.72      1409
weighted avg       0.78      0.79      0.78      1409

this follow is report of GDBT:
              precision    recall  f1-score   support

           0       0.83      0.89      0.86      1023
           1       0.65      0.52      0.57       386

    accuracy                           0.79      1409
   macro avg       0.74      0.70      0.72      1409
weighted avg       0.78      0.79      0.78      1409



xgboost matrix = [
   [910 113]
   [183 203]
 ]
GDBT matrix = [
   [914 109]
   [187 199]
 ]

对比可见:

  • 速度: XGBoost显著快于GBDT,而且XGBoost还可以拓展使用gpu更进一步加速。
  • 性能: 两个模型在准确率上几乎相同,在处理不平衡数据时,XGBoost略有优势。
  • 使用场景: 如果计算资源有限且对训练速度有要求,XGBoost是更好的选择;如果需要略微更好的正类预测,XGBoost也是更优选择。