基于树模型的集成算法---GBDT

一、模型介绍

GBDT 的全称是 Gradient Boosting Decision Tree,梯度提升决策树。 GBDT 也是集成学习 Boosting 家族的成员,但是却和传统的 Adaboost 有很大的不同。
回顾下 Adaboost,我们是利用前一轮迭代弱学习器的误差率来更新训练集的权重,这样一轮轮的迭代下去。GBDT 也是迭代,使用了前向分布算法,但是弱学习器限定了只能使用 CART 回归树模型,无论是处理回归问题还是二分类以及多分类,GBDT 使用的决策树通通都是 CART 回归树。因为 GBDT 每次迭代要拟合的是梯度值,是连续值所以要用回归树。同时迭代思路和 Adaboost 也有很大不同。 在 RF、Adaboost 等加法模型中,都是通过直接拟合真实值来构建模型的,而在 GBDT 里面:非首轮迭代的模型拟合的目标值不再是真实值,而是一个梯度值,主要是通过拟合损失函数的负梯度值在当前模型的值来构建模型。

二、模型原理

Gradient Bossting:梯度提升树

梯度提升树(Grandient Boosting)是提升树(Boosting Tree)的一种改进算法。
首先我们来看一下提升树的思想:假如有个人 30 岁,我们首先用 20 岁去拟合,发现损失有 10 岁,这时我们用 6 岁去拟合剩下的损失,发现差距还有 4 岁,第三轮我们用 3 岁拟合剩下的差距,差距就只有一岁了。如果我们的迭代轮数还没有完,可以继续迭代下面,每一轮迭代,拟合的岁数误差都会减小。最后将每次拟合的岁数加起来便是模型输出的结果。

    1. 初始化
    1. 对 m = 1,2,3……M
      (1) 计算残差
      (2) 拟合残差 学习一个回归树,得到 .
      (3) 更新
    1. 得到回归树

在提升树算法中,假设我们上一轮迭代得到的强学习器是 ,损失函数是 ,我们本轮迭代的目标是找到一个弱学习器 ,当我们采用平方损失函数时
这里的 是当前模型拟合数据的残差(residual)。所以,对于提升树来说只需要简单地拟合当前模型的残差。
当损失函数是平方损失和指数损失函数时,梯度提升树每一步优化是很简单的,但是对于一般损失函数而言,往往每一步优化起来不那么容易,针对这一问题,Freidman 提出了梯度提升树算法,这是利用最速下降的近似方法,其关键是利用损失函数的负梯度作为提升树算法中的残差的近似值。

  • 对于负梯度:
    第 t 轮的第 i 个样本的损失函数的负梯度为:

    根据上式可以看出,不同的损失函数将会得到不同的负梯度,如果选择平方损失:
    负梯度:

    可以看出,此时的负梯度就是残差。所以对于回归问题来说,我们要拟合的就是残差。对于分类问题,损失函数都是 log loss。

原理:

上面介绍完了 Gradient Bossting 的原理,那么对于 GBDT 的算法原理如下:

    1. 初始化弱学习器
    1. 对于 m = 1,2,3……M 有:
      (1)对每个样本 i = 1,2,3……N,计算负梯度,即残差
      (2)将上面得到的残差作为样本新的真实值,并将数据 作为下棵树的训练数据,得到一棵新的回归树 其对应的叶子节点区域为 其中 J 为回归树 t 的叶子节点的个数。
      (3)对叶子区域 j = 1,2,3……J,计算最佳拟合值
      (4)更新强学习器
    1. 得到最终学习器:

三、模型细节

1. 对于分类算法来说, GBDT 如何实现?

GBDT 的分类算法从思想上和 GBDT 的回归算法没有区别,但是由于样本输出不是连续的值,而是离散的类别,导致无法直接从输出类别去拟合类别输出的误差。为了解决这个问题,主要有两个方法,一个是用指数损失函数,此时 GBDT退化为 Adaboost 算法。另一种方法是用类似于逻辑回归的对数似然损失函数的方法。也就是说,用的是类别的预测概率值和真实概率值的差来拟合损失。接下来讨论用对数似然损失函数的 GBDT。而对于对数似然损失函数,又有二元分类和多元分类的区别。

2. GBDT 常用的损失函数

  • 指数损失函数,同 Adaboost 算法中的损失函数。
  • 对数损失函数,分为二元分类和多元分类两种。
  • 均方差,这个是最常见的回归损失函数。
  • 绝对损失, 基于残差的GBDT在解决回归问题上也不算是一个好的选择,一个比较明显的缺点就是对异常值过于敏感。一般回归类的损失函数会用绝对损失或者huber损失函数来代替平方损失函数。
  • Huber损失,它是均方差和绝对损失的折中产物,对于远离中心的异常点,采用绝对损失,而中心附近的点采用均方差。这个界限一般用分位数点度量。
  • 分位数损失。它对应的是分位数回归的损失函数。

对于Huber损失和分位数损失,主要用于健壮回归,也就是减少异常点对损失函数的影响。

3. 对于 GBDT 的正则化

  • 第一种是和 Adaboost 类似的正则化项,即步长 (learning rate)。对于同样的训练集学习效果,较小的步长意味着需要更多的弱学习器的迭代次数。通常用步长和迭代最大次数一起来决定算法的拟合效果。
    1. 第二种正则化的方式是通过子采样比例(subsample)。取值为(0,1]。注意这里的子采样和随机森林不一样,随机森林使用的是放回抽样,而这里是不放回抽样。如果取值为1,则全部样本都使用,等于没有使用子采样。如果取值小于1,则只有一部分样本会去做 GBDT 的决策树拟合。选择小于1的比例可以减少方差,即防止过拟合,但是会增加样本拟合的偏差,因此取值不能太低。推荐在[0.5, 0.8]之间。使用了子采样的 GBDT 有时也称作随机梯度提升树 (Stochastic Gradient Boosting Tree, SGBT)。由于使用了子采样,程序可以通过采样分发到不同的任务去做 boosting 的迭代过程,最后形成新树,从而减少弱学习器难以并行学习的弱点。
    1. 第三种是对于弱学习器即CART回归树进行正则化剪枝。

四、模型优缺点

优点:

    1. 可以灵活处理各种类型的数据,包括连续值和离散值。
    1. 在较少的调参情况下,预测的也能有较高的准确率。
    1. 使用一些健壮的损失函数,对异常值的鲁棒性非常强。比如 Hube 损失函数和 Quantile 损失函数。

缺点:

    1. 由于弱学习器之间存在依赖关系,难以并行训练数据。不过可以通过自采样的 SGBT 来达到部分并行。

五、模型使用

from sklearn.ensemble import GradientBoostingClassifier, GradientBoostingRegressor
gbclf = GradientBoostingClassifier(loss='deviance', learning_rate=0.1, n_estimators=100,
                 subsample=1.0, criterion='friedman_mse', min_samples_split=2,
                 min_samples_leaf=1, min_weight_fraction_leaf=0.,
                 max_depth=3, min_impurity_decrease=0.,
                 min_impurity_split=None, init=None,
                 random_state=None, max_features=None, verbose=0,
                 max_leaf_nodes=None, warm_start=False,
                 presort='deprecated', validation_fraction=0.1,
                 n_iter_no_change=None, tol=1e-4, ccp_alpha=0.0)
gbclf.fit(x,y)
gbclf.predict(test_x)


gbreg = GradientBoostingRegressor(loss='ls', learning_rate=0.1, n_estimators=100,
                 subsample=1.0, criterion='friedman_mse', min_samples_split=2,
                 min_samples_leaf=1, min_weight_fraction_leaf=0.,
                 max_depth=3, min_impurity_decrease=0.,
                 min_impurity_split=None, init=None, random_state=None,
                 max_features=None, alpha=0.9, verbose=0, max_leaf_nodes=None,
                 warm_start=False, presort='deprecated',
                 validation_fraction=0.1,
                 n_iter_no_change=None, tol=1e-4, ccp_alpha=0.0)
gbreg.fit(x,y)
gbreg.predict(test_x)

你可能感兴趣的:(基于树模型的集成算法---GBDT)