为什么 xgboost 比 sklearn GradientBoostingClassifier 快这么多?

数据挖掘 scikit-学习 xgboost gbm
2021-09-18 21:42:18

我正在尝试用 100 个数字特征训练超过 50k 个示例的梯度提升模型。XGBClassifier在我的机器上在 43 秒内处理 500 棵树,而GradientBoostingClassifier在 1 分 2 秒内只处理 10 棵树(!):( 我没有费心尝试种植 500 棵树,因为这需要几个小时。我正在使用相同learning_ratemax_depth设置, 见下文。

是什么让 XGBoost 如此之快?它是否使用了一些 sklearn 家伙不知道的新的梯度提升实现?还是“偷工减料”,种植较浅的树木?

ps 我知道这个讨论:https ://www.kaggle.com/c/higgs-boson/forums/t/10335/xgboost-post-competition-survey但无法在那里得到答案......

XGBClassifier(base_score=0.5, colsample_bylevel=1, colsample_bytree=1,
gamma=0, learning_rate=0.05, max_delta_step=0, max_depth=10,
min_child_weight=1, missing=None, n_estimators=500, nthread=-1,
objective='binary:logistic', reg_alpha=0, reg_lambda=1,
scale_pos_weight=1, seed=0, silent=True, subsample=1)

GradientBoostingClassifier(init=None, learning_rate=0.05, loss='deviance',
max_depth=10, max_features=None, max_leaf_nodes=None,
min_samples_leaf=1, min_samples_split=2,
min_weight_fraction_leaf=0.0, n_estimators=10,
presort='auto', random_state=None, subsample=1.0, verbose=0,
warm_start=False)
1个回答

由于您提到“数字”特征,我猜您的特征不是分类的并且具有很高的数量(它们可以采用很多不同的值,因此有很多可能的分割点)。在这种情况下,种植树木很困难,因为有 [很多特征× 很多分裂点]来评估。

我的猜测是,最大的影响来自 XGBoost 在分割点上使用近似值这一事实。如果您有一个具有 10000 个可能分割的连续特征,XGBoost 默认只考虑“最好的”300 个分割(这是一种简化)。此行为由参数控制,您可以在 docsketch_eps中阅读有关它的更多信息您可以尝试降低它并检查它产生的差异。由于scikit-learn 文档中没有提到它,我猜它不可用。您可以在他们的论文 (arxiv)中了解 XGBoost 方法是什么

XGBoost 还使用了对此类分割点的评估的近似值。我不知道 scikit learn 是根据哪个标准来评估拆分,但它可以解释其余的时间差。


处理评论

关于分割点的评价

但是,您所说的“XGBoost 也在评估此类分割点时使用了近似值”是什么意思?据我了解,对于评估,他们正在使用最佳目标函数的精确缩减,如本文的等式(7)所示。

为了评估分割点,您必须计算L(y,Hi1+hi)在哪里L是成本函数,y目标,Hi1迄今为止建立的模型,以及hi当前添加。请注意,这不是 XGBoost 正在做的事情。他们正在简化成本函数L通过泰勒展开,这导致了一个非常简单的计算函数。他们必须计算梯度和 HessianL 关于 Hi1,并且他们可以在阶段将这些数字重复用于所有潜在的拆分 i,使总体计算速度更快。您可以查看Loss function Approximation With Taylor Expansion (CrossValidated Q/A)了解更多详细信息,或者他们论文中的推导。

关键是他们找到了一种近似的方法 L(y,Hi1+hi)有效率的。如果你要评估L完全没有内部知识允许优化或避免或冗余计算,每次拆分将花费更多时间。就这点而言,它是一个近似值。然而,其他梯度提升实现也使用代理成本函数来评估分割,我不知道 XGBoost 近似在这方面是否比其他方法更快。