梯度提升树的调参指南
梯度提升树的调参指南
原文:
towardsdatascience.com/a-visual-guide-to-tuning-gradient-boosted-trees/
简介
我的之前 帖子探讨了标准的决策树和随机森林的奇迹。现在,为了完成这个三元组,我将可视化地探索
有许多梯度提升树库,包括 XGBoost、CatBoost 和 LightGBM。然而,对于这个项目,我将使用 sklearn 的库。为什么?简单来说,与其他库相比,它让我更容易可视化。在实践中,我倾向于使用其他库多于 sklearn;然而,这个项目是关于可视化学习,而不是纯性能。
基本上,GBT 是树的组合,只协同工作。虽然单个决策树(包括从随机森林中提取的一个)可以独立做出合理的预测,但从 GBT 中提取单个树不太可能得到任何有用的结果。
除了这个,一如既往,没有理论,没有数学——只有图表和超参数。就像以前一样,我将使用 scikit-learn 的加利福尼亚住房数据集(CC-BY),与我在之前的帖子中描述的相同的一般过程,代码在github.com/jamesdeluk/data-projects/tree/main/visualising-trees,下面的所有图像都是我制作的(除了 GIF,它来自Tenor)。
一个基本的梯度提升树
从一个基本的 GBT 开始:gb = GradientBoostingRegressor(random_state=42)。与其他树类型类似,min_samples_split、min_samples_leaf、max_leaf_nodes的默认设置分别是 2、1、None。有趣的是,默认的max_depth是 3,而不是决策树/随机森林中的None。值得注意的超参数,我稍后会进一步探讨,包括learning_rate(梯度有多陡,默认 0.1)和n_estimators(与随机森林类似——树的数量)。
调整需要 2.2 秒,预测需要 0.005 秒,结果如下:
| 指标 | max_depth=None |
|---|---|
| MAE | 0.369 |
| MAPE | 0.216 |
| MSE | 0.289 |
| RMSE | 0.538 |
| R² | 0.779 |
那么,比默认的随机森林快,但性能略差。对于我选择的块,它预测了 0.803(实际值为 0.894)。
可视化
这就是你们在这里的原因,对吧?
树
与之前类似,我们可以绘制一棵单独的树。这是第一棵,通过gb.estimators_[0, 0]访问:

我在之前的帖子中解释了这些,所以这里不再重复。不过,我要提醒你一点:注意这些值有多糟糕!三个叶子节点甚至有负值,我们知道这是不可能的。这就是为什么 GBT 只能作为一个组合集成工作,而不能像随机森林中的单独树那样独立工作。
预测和误差
我最喜欢的可视化 GBTs 的方法是使用预测与迭代图,使用 gb.staged_predict。对于我选择的块:

记得默认模型有 100 个估计器吗?嗯,这里就是它们。初始预测远远不准确——2!但每次它学习(记得 learning_rate 吗?),就越来越接近真实值。当然,它是基于训练数据训练的,而不是这个具体的数据,所以最终值是不准确的(0.803,大约 10% 的误差),但你可以清楚地看到这个过程。
在这种情况下,它在大约 50 次迭代后达到了相当稳定的状态。稍后我们将看到如何在这个阶段停止迭代,以避免浪费时间和金钱。
同样,误差(即预测值与真实值之差)也可以绘制。当然,这给出了相同的图表,只是 y 轴的值不同:

让我们更进一步!测试数据有超过 5000 个块需要预测;我们可以遍历每个块,并对每个迭代进行预测!

我喜欢这个图表。

它们都是从 2 开始,但在迭代过程中爆炸式增长。我们知道所有真实值从 0.15 到 5 变化,平均值为 2.1(检查我的 第一篇帖子),所以预测值的这种分散(从 ~0.3 到 ~5.5)是预期的。
我们也可以绘制误差图:

初看之下,这似乎有点奇怪——我们预计它们将从,比如说,±2 开始,并收敛到 0。但仔细观察后,这种情况确实发生在大多数情况下——可以在图表的左侧看到,大约前 10 次迭代。问题是,在这个图表上有超过 5000 条线,有很多重叠,使得异常值更加突出。也许有更好的可视化方法?比如...

中位数误差为 0.05——这非常好!IQR 小于 0.5,这也是不错的。所以,虽然有一些糟糕的预测,但大多数都是不错的。
超参数调整
决策树超参数
和之前一样,让我们比较一下原始决策树帖子中探索的超参数如何应用于 GBTs,使用默认超参数 learning_rate = 0.1, n_estimators = 100。min_samples_leaf、min_samples_split 和 max_leaf_nodes 的 max_depth 也设置为 10,以便与之前的帖子以及彼此进行公平的比较。
| 模型 | max_depth=None | max_depth=10 | min_samples_leaf=10 | min_samples_split=10 | max_leaf_nodes=100 |
|---|---|---|---|---|---|
| 拟合时间(秒) | 10.889 | 7.009 | 7.101 | 7.015 | 6.167 |
| 预测时间(秒) | 0.089 | 0.019 | 0.015 | 0.018 | 0.013 |
| MAE | 0.454 | 0.304 | 0.301 | 0.302 | 0.301 |
| MAPE | 0.253 | 0.177 | 0.174 | 0.174 | 0.175 |
| MSE | 0.496 | 0.222 | 0.212 | 0.217 | 0.210 |
| RMSE | 0.704 | 0.471 | 0.46 | 0.466 | 0.458 |
| R² | 0.621 | 0.830 | 0.838 | 0.834 | 0.840 |
| 选择预测 | 0.885 | 0.906 | 0.962 | 0.918 | 0.923 |
| 选择误差 | 0.009 | 0.012 | 0.068 | 0.024 | 0.029 |
与决策树和随机森林不同,深度更大的树表现远差!并且拟合时间更长。然而,将深度从 3(默认)增加到 10 提高了分数。其他约束条件导致了进一步的改进——再次表明所有超参数都可以发挥作用。
learning_rate
GBTs 通过根据每次迭代的误差调整预测来运行。调整幅度越大(即梯度,即学习率),预测在迭代之间的变化就越大。
学习率存在明显的权衡。比较 0.01(慢速)、0.1(默认)和 0.5(快速)的学习率,经过 100 次迭代:

更快的学习率可以更快地达到正确值,但它们更容易过度校正并跳过真实值(想想汽车打滑),并可能导致振荡。慢速学习率可能永远无法达到正确值(想想……没有足够转动方向盘,直接撞到树上)。至于统计数据:
| 模型 | 默认 | 快速 | 慢速 |
|---|---|---|---|
| 拟合时间(秒) | 2.159 | 2.288 | 2.166 |
| 预测时间(秒) | 0.005 | 0.004 | 0.015 |
| MAE | 0.370 | 0.338 | 0.629 |
| MAPE | 0.216 | 0.197 | 0.427 |
| MSE | 0.289 | 0.247 | 0.661 |
| RMSE | 0.538 | 0.497 | 0.813 |
| R² | 0.779 | 0.811 | 0.495 |
| 选择预测 | 0.803 | 0.949 | 1.44 |
| 选择误差 | 0.091 | 0.055 | 0.546 |
慢速学习模型的表现出人意料地糟糕。对于这个区块,快速模型整体上略好于默认模型。然而,我们可以从图中看到,至少对于所选区块,是最后 90 次迭代使快速模型比默认模型更准确——如果我们只进行到 40 次迭代,至少对于所选区块,默认模型会更好。可视化带来的乐趣!
n_estimators
如上所述,估计器的数量与学习率密切相关。一般来说,估计器越多越好,因为它提供了更多的迭代来测量和调整误差——尽管这会带来额外的时间成本。
如上图所示,足够高的估计器数量对于低学习率尤为重要,以确保达到正确的值。将估计器的数量增加到 500:

足够的迭代次数后,学习速度较慢的 GBT 确实达到了真实值。事实上,它们最终都接近了。统计数据证实了这一点:
| 模型 | 默认 More | 快速 More | 慢速 More |
|---|---|---|---|
| 拟合时间 (s) | 12.254 | 12.489 | 11.918 |
| 预测时间 (s) | 0.018 | 0.014 | 0.022 |
| 平均绝对误差 (MAE) | 0.323 | 0.319 | 0.410 |
| 平均绝对百分比误差 (MAPE) | 0.187 | 0.185 | 0.248 |
| 均方误差 (MSE) | 0.232 | 0.228 | 0.338 |
| 均方根误差 (RMSE) | 0.482 | 0.477 | 0.581 |
| R² | 0.823 | 0.826 | 0.742 |
| 选择预测 | 0.841 | 0.921 | 0.858 |
| 选择误差 | 0.053 | 0.027 | 0.036 |
毫不奇怪,将估计器的数量增加五倍显著增加了拟合时间(在这种情况下增加了六倍,但这可能只是偶然)。然而,我们还没有超过上述约束树的分数——我想我们需要进行超参数搜索,看看我们是否能打败它们。此外,对于所选块,如图所示,在约 300 次迭代后,没有模型真正得到改善。如果这在所有数据中都是一致的,那么额外的 700 次迭代是不必要的。我之前提到过,如何避免在没有改善的情况下浪费时间迭代;现在是时候深入研究这一点了。
n_iter_no_change,validation_fraction,和 tol
有可能额外的迭代不会改善最终结果,但运行它们仍然需要时间。这就是提前停止发挥作用的地方。
有三个相关的超参数。第一个,n_iter_no_change,是指在进行更多迭代之前,有多少次迭代没有变化。tol[erance] 是验证分数变化的大小,以被分类为“没有变化”。validation_fraction 是用作验证集以生成验证分数的训练数据量(注意这不同于测试数据)。
比较一个有 1000 个估计器的 GBT 和一个有相当激进的提前停止的 GBT——n_iter_no_change=5,validation_fraction=0.1,tol=0.005——后者在只有 61 个估计器后停止(因此只用了 5~6%的时间来拟合):

如预期的那样,结果更差:
| 模型 | 默认 | 提前停止 |
|---|---|---|
| 拟合时间 (s) | 24.843 | 1.304 |
| 预测时间 (s) | 0.042 | 0.003 |
| 平均绝对误差 (MAE) | 0.313 | 0.396 |
| 平均绝对百分比误差 (MAPE) | 0.181 | 0.236 |
| 均方误差 (MSE) | 0.222 | 0.321 |
| 均方根误差 (RMSE) | 0.471 | 0.566 |
| R² | 0.830 | 0.755 |
| 选择预测 | 0.837 | 0.805 |
| 选择误差 | 0.057 | 0.089 |
但一如既往,需要问的问题是:是否值得投入 20 倍的时间来提高 R² 10%,或者减少 20%的误差?
贝叶斯搜索
你可能期待看到这个。搜索空间:
search_spaces = {
'learning_rate': (0.01, 0.5),
'max_depth': (1, 100),
'max_features': (0.1, 1.0, 'uniform'),
'max_leaf_nodes': (2, 20000),
'min_samples_leaf': (1, 100),
'min_samples_split': (2, 100),
'n_estimators': (50, 1000),
}
大多数与我的之前的帖子相似;唯一的额外超参数是 learning_rate。
这到目前为止花费了最长时间,96 分钟(比随机森林多出约 50%)!最佳超参数如下:
best_parameters = OrderedDict({
'learning_rate': 0.04345459461297153,
'max_depth': 13,
'max_features': 0.4993693929975871,
'max_leaf_nodes': 20000,
'min_samples_leaf': 1,
'min_samples_split': 83,
'n_estimators': 325,
})
max_features、max_leaf_nodes 和 min_samples_leaf 与调整过的随机森林非常相似。n_estimators 也是如此,并且与上面选择的块图建议一致——额外的 700 次迭代大多是不必要的。然而,与调整过的随机森林相比,这些树只有三分之一的深度,而 min_samples_split 的值远高于我们迄今为止看到的。learning_rate 的值基于我们上面的观察并不令人惊讶。
以及交叉验证的分数:
| 度量 | 平均值 | 标准差 |
|---|---|---|
| MAE | -0.289 | 0.005 |
| MAPE | -0.161 | 0.004 |
| MSE | -0.200 | 0.008 |
| RMSE | -0.448 | 0.009 |
| R² | 0.849 | 0.006 |
在迄今为止的所有模型中,这是最好的,误差更小,R²更高,方差更低!
最后,我们老朋友,箱线图:

结论
因此,我们来到了关于三种最常见的基于树的模型系列的最后一篇。
我希望通过看到不同的树可视化方式,你现在(a)更好地理解了不同模型的工作原理,而无需查看方程式,并且(b)可以使用自己的图表来调整自己的模型。这也有助于利益相关者管理——高管们更喜欢漂亮的图片而不是数字表格,所以向他们展示树状图可以帮助他们理解为什么他们要求你做的事情是不可能的。
基于这个数据集和这些模型,梯度提升树模型略优于随机森林模型,而两者都远优于单独的决策树。然而,这可能是因为梯度提升树有更多的时间去搜索更好的超参数(它们通常计算成本更高——毕竟,迭代次数是相同的)。还值得注意的是,梯度提升树比随机森林更容易过拟合。尽管决策树的表现较差,但它要快得多——在某些用例中,这更为重要。此外,正如之前提到的,还有其他库,各有优缺点——例如,CatBoost 可以直接处理分类数据,而其他梯度提升树库通常需要预处理分类数据(例如,独热编码或标签编码)。或者,如果你真的很勇敢,为什么不尝试将不同类型的树在集成中使用,以获得更好的性能呢……
总之,直到下次再见!

浙公网安备 33010602011771号