GBDT算法梳理
GBDT(Gradient Boosting Decision Tree)是一种可用于处理分类(classification)和回归(regression)任务的机器学习集成算法,和其它Boosting族的算法类似地分步构建模型,然后通过对任意可微的损失函数(loss function)的优化来进行推广运用。
Gradient Boosting的思想起源于Leo Briman的评论:Boosting可以解释为一个基于合适的损失函数的优化算法。随后Friedman开发了显式回归梯度提升算法,同时部分学者从更通用的函数梯度下降(functional gradient descent)视角进行跟进,发表了将boosting算法作为迭代函数梯度下降算法(iterative functinal gradient descent algorithms)的观点。也就是说,GBDT是一种通过迭代选定的指向负梯度方向的函数(弱学习器)在函数空间对损失函数进行优化的算法。这种将boosting视为函数梯度的观点也推动了boosting族算法在回归和分类以外的其它机器(统计)学习领域的发展。
前向分步算法
考虑加法模型(additive model)
其中,为基函数,为基函数的参数,为基函数的系数。
在给定训练数据以及损失函数的条件下,学习加法模型成为经验风险极小化即损失函数极小化问题:
通常来说,这是一个复杂的优化问题,NP难。
而前向分步算法(forward stage-wise algorithm)求解这一优化问题采用的是贪心策略:
- 因为是加法模型,从前往后,每一步只学习一个基函数及其系数
- 通过迭代,逐步逼近优化目标函数,求局部最优解,达到简化优化的复杂度
- 每步只需优化的如下损失函数:
前向分步算法的具体流程如下:
-
输入:
- 训练数据集;损失函数 ;基函数集
-
输出:
- 加法模型
-
初始化
-
对
- 极小化损失函数,得到参数
- 更新
-
得到加法模型
这样,前向分步算法将同时求解从到所有参数的优化问题简化为逐次求解各个的优化问题。
负梯度拟合
负梯度拟合,顾名思义,就是在损失函数梯度的负方向上进行拟合,这个和梯度下降算法咋看起来非常类似,梯度下降是在参数空间沿着负梯度的方向进行拟合,而Gradient Boosting是在函数空间沿着负梯度的方向进行拟合。这一方法由Freidman最早提出,用损失函数的负梯度来拟合本轮损失的近似值,第轮的第个样本的损失函数的负梯度表示为:
那么问题来了,为什么要拟合负梯度?这就涉及到泰勒公式和梯度下降算法了。
泰勒公式
-
定义:泰勒公式是一个用函数在某点的信息描述其附近取值的近似公式,具有局部 有效性。
-
基本形式
- 一阶泰勒展开:
$$f(x)\approx f(x_0)+f'(x_0)(x-x_0)$$
- 二阶泰勒展开:
$$f(x)\approx f(x_0)+f'(x_0)(x-x_0)+f''(x_0)\frac{(x-x_0)^2}{2}$$
- 迭代形式
假设,将在处进行泰勒展开:
$$
## 梯度下降法
在机器学习任务中,需要最小化损失函数
\begin{align}
L(\theta^t) &=L(\theta^{t-1}+\Delta \theta,) \
& \approx L(\theta{t-1})+L’(\theta{t-1}),\Delta\theta
\end{align}
- 要使得
- 对数似然损失函数(二分类):
- 对数似然损失函数(多分类):
回归问题
- 平方损失函数:
此时,负梯度正好与每一步迭代损失函数的残差相等,拟合负梯度也等同于拟合残差。
- 绝对损失函数:
对应负梯度方向为:
- Huber损失,它是均方差和绝对损失的折中产物,对于远离中心的异常点,采用绝对损失误差,而对于靠近中心的点则采用平方损失。这个界限一般用分位数点度量。损失函数如下:
对应的负梯度误差为:
- 分位数损失,它对应的是分位数回归的损失函数,表达式为:
其中为分位数,需要我们再回归前制定。对应的负梯度误差为:
对于Huber损失和分位数损失,主要用于健壮回归,也就是减少异常点对损失函数的影响。
回归
有了损失函数和损失函数拟合策略,下面来看看GBDT的具体实现。考虑到回归问题处理负梯度相对简单,那么从回归问题开始讲。
-
输入:
- 训练数据集;损失函数;最大迭代次数 。
-
输出:
- 回归树
-
初始化弱学习器 $$f_0(x)=\mathop{\arg\min}{c}\sum{i=1}^{N}L(y_i,c)$$
-
对
- 对,计算损失函数在当前模型的负梯度:
- 利用,拟合一棵CART树,得到第棵树,其对应的叶子节点区域为。其中为树的叶子节点的个数。
- 对,在损失函数极小化条件下,估计出相应叶节点区域的最佳拟合值:
- 更新强学习器:
-
得到强学习器的表达式:
分类
下面再看看GBDT分类算法,GBDT的分类算法从思想上和GBDT的回归算法没有区别,但是由于样本输出不是连续的值,而是离散的类别,导致我们无法直接从输出类别去拟合类别输出的误差,好在GBDT可以根据学习任务灵活选择相应的损失函数。
为了解决这个问题,有两个方法,一个是用指数损失函数,此时GBDT退化为Adaboost算法。另一种方法用类似逻辑回归的对数似然函数的方法。也就是说,我们用的是类别的预测概率值和真实概率值的差来拟合损失。Adaboost算法已经在随机森林算法梳理涉及,此处仅讨论用对数似然函数的GBDT分类算法。并且,分布讨论采用对数似然损失函数的二元分类和多元分类的区别。
二分类
-
输入:
- 训练数据集;损失函数;最大迭代次数。
-
输出:
- 分类树
-
初始化弱学习器 $$f_0(x)=\mathop{\arg\min}{c}\sum{i=1}^{N}L(y_i,c)$$
-
对
- 对,计算损失函数在当前模型的负梯度:
- 利用,拟合一棵CART树,得到第棵树,其对应的叶子节点区域为。其中为树的叶子节点的个数。
- 对,在损失函数极小化条件下,估计出相应叶节点区域的最佳拟合值:
- 由于上式比较难优化,我们一般使用近似值代替:
- 更新强学习器:
-
得到强学习器的表达式:
不难发现,除了负梯度计算和叶子节点的最佳负梯度拟合的线性搜索,二元GBDT分类和GBDT回归算法过程相同。
多分类
考虑到分类和回归算法的过程相似性,以下就阐述多分类GBDT算法的时候不再给出具体的流程,而仅仅列出差异的部分。
多分类GBDT比二分类GBDT复杂些,对应的是多元逻辑回归和二元逻辑回归的复杂度差别。假设类别数为,则此时我们的对数似然损失函数为:
其中如果样本输出类别为 ,则 =1,第 类的概率 的表达式为:
集合上两式,我们可以计算出第 轮的第 个样本对应类别 的负梯度误差为:
观察上式可以看出,其实这里的误差就是样本 对应类别 的真实概率和 轮预测概率的差值。
对于生成的决策树,我们各个叶子节点的最佳负梯度拟合值为:
由于上式比较难优化,我们一般使用近似值代替:
除了负梯度计算和叶子节点的最佳负梯度拟合的线性搜索,多分类GBDT与二分类GBDT以及GBDT回归算法过程相同。
正则化
GBDT有非常快降低Loss的能力,这也会造成一个问题:Loss迅速下降,模型偏差(bias),方差(variance)高,造成过拟合。下面简单介绍GBDT中抵抗过拟合的方法:
- 限制树的复杂度,即对弱学习器CART树进行正则化剪枝,比如如控制树的最大深度、节点的最少样本数、最大叶子节点数、节点分支的最小样本数等
- Shrinkage,其思想认为,每次走一小步逐渐逼近结果的效果,要比每次迈一大步很快逼近结果的方式更容易避免过拟合。即它不完全信任每一个棵残差树,它认为每棵树只学到了真理的一小部分,累加的时候只累加一小部分,通过多学几棵树弥补不足。用方程来看更清晰,即给每棵数的输出结果乘上一个步长(learning rate)
对于前面的弱学习器的迭代:
加上正则化项,则有
此处,的取值范围为(0,1]。对于同样的训练集学习效果,较小的意味着需要更多的弱学习器的迭代次数。通常我们用步长和迭代最大次数一起决定算法的拟合效果。
下面是Sklearn的实现关于该参数设置的片段,XGBoost类似:
1 | #code snippets from sklearn.ensemble.gradient_boosting |
- 子采样比例(subsample),取值范围为(0,1],GBDT这里的做法是在每一轮建树时,样本是从原始训练集中采用无放回随机抽样的方式产生,与随机森立的有放回抽样产生采样集的方式不同。若取值为1,则采用全部样本进行训练,若取值小于1,则不选取全部样本进行训练。选择小于1的比例可以减少方差,防止过拟合,但可能会增加样本拟合的偏差。取值要适中,推荐**[0.5,0.8]**
- Early stop,因为GBDT的可叠加性,我们使用的模型不一定是最终的ensemble,而根据测试集的测试情况,选择使用前若干棵树
优缺点
优点
- 可以灵活处理各种类型的数据,包括连续值和离散值
- 具有伸缩不变性,不用归一化特征
- 具有特征组合和特征选择的作用
- 可自然地处理缺失值
- 相对SVM而言,在相对较少的调参时间情况下,预测的准确率也比较高
- 在使用一些健壮的损失函数,对异常值得鲁棒性非常强。比如Huber损失函数和Quantile损失函数
缺点
- 由于弱学习器之间存在较强依赖关系,难以整体并行训练
sklearn中的参数解释
在sklearn当中按学习任务的不同一共有两个(暂不考虑其它对GBDT优化的框架)与GBDT相关的类:GradientBoostingClassifier应用于分类学习任务,GradientBoostingRegressor应用于回归学习任务。
GradientBoostingClassifier
参数(parameters)
-
loss : {‘deviance’, ‘exponential’}, optional (default=’deviance’)
- 需要优化的损失函数
-
learning_rate : float, optional (default=0.1)
- 学习率(learning_rate),与
n_estimators之间有个平衡
- 学习率(learning_rate),与
-
n_estimators : int (default=100)
- boosting迭代步数,Gradient boosting通常对于过拟合有鲁棒性,一个较大的数通常意味着更好的性能,整型,默认是100
-
subsample : float, optional (default=1.0)
- 用于训练基学习器的样本采样比例,小于1.0则等同于随机梯度提升(Stochasitc Gradient Boosting),与
n_estimators相互作用,如果小于1则会减少方差,增加偏差
- 用于训练基学习器的样本采样比例,小于1.0则等同于随机梯度提升(Stochasitc Gradient Boosting),与
-
criterion : string, optional (default=”friedman_mse”)
- 衡量特征分裂质量的函数,这是一个与基学习器决策树相关的参数,字符串类型,可选项,默认是”friedman_mse”
-
min_samples_split : int, float, optional (default=2)
- 用于分裂一个内部结点的最小所需的样本数,整型或者浮点型,可选项,默认是2
-
min_samples_leaf : int, float, optional (default=1)
- 一个叶子结点所要求的最小样本个数,这个参数有平滑模型的作用,特别是回归的学习任务里面。整型或者浮点型,可选项,默认是1
-
min_weight_fraction_leaf : float, optional (default=0.)
- 一个叶子结点所有输入样本权重总和的最小权重分数,浮点型,可选项,默认为0.
-
max_depth : integer, optional (default=3)
- 单棵回归树的最大深度,需要进行调参来获得更好的性能
-
min_impurity_decrease : float, optional (default=0.)
- 最小不纯度减少值,结点将会继续分裂,如果这个分裂对于不纯度的减少能够大于或者等于该值。浮点型,可选项,默认为0.
-
min_impurity_split : float, (default=1e-7)
- 建树过程中早起停止的阈值。如果节点的不纯度大于该值将会继续分裂,否则停止,成为叶子结点。浮点型,默认为1e-7
- 后续将会被
min_impurity_decrease参数替代
-
init : estimator or ‘zero’, optional (default=None)
- 用来模型初始化的学习器对象,可以提供
fit或者predict对象,如果是“zero”则初始预测为0
- 用来模型初始化的学习器对象,可以提供
-
random_state : int, RandomState instance or None, optional (default=None)
- 随机状态,有以下三种方式
- int, random_state is the seed used by the random number generator;
- RandomState instance, random_state is the random number generator;
- None, the random number generator is the RandomState instance used by np.random.
- 随机状态,有以下三种方式
-
max_features : int, float, string or None, optional (default=”auto”)
-
寻找最优分裂时所考虑的特征个数,整型、浮点型、字符串或者None,可选项,默认是“auto”
- int, then consider max_features features at each split.
- float, then max_features is a fraction and int(max_features * n_features) features are considered at each split.
- “auto”, then max_features=sqrt(n_features).
- “sqrt”, then max_features=sqrt(n_features) (same as “auto”).
- “log2”, then max_features=log2(n_features).
- None, then max_features=n_features.
-
-
verbose : int, optional (default=0)
- 控制在学习和预测时是否输出中间结果,整型,可选项,默认是0
-
max_leaf_nodes : int or None, optional (default=None)
- 以最好的方式用
max_leaf_nodes来建树,如果是None的话则对叶子结点的个数不限制,整型或者Node,可选项,默认是Node
- 以最好的方式用
-
warm_start : bool, optional (default=False)
- 布尔型,可选项,默认为False,如果设置为True,将重复使用上一次调用的解来学习并加入更多的学习器到集成算法当中
-
presort : bool or ‘auto’, optional (default=’auto’)
- 在寻找最佳分裂时是否预排序。自动模式将对稠密数据进行预排序,对稀疏数据进行自然排序,对于稀疏数据采用预排序将会报错
-
validation_fraction : float, optional, default 0.1
- Early stopping时作为验证集的比例,只有在
n_iter_no_change为整型时才起作用
- Early stopping时作为验证集的比例,只有在
-
n_iter_no_change : int, default None
- 在验证分数不再提高时用来决定是否采用early stopping来结束训练,整型,默认是None,不考虑early stopping
-
tol : float, optional, default 1e-4
- early stopping的容差(tolerance),在early stopping启用时,在经过
n_iter_no_change步迭代的提升都没有超过tol时,则停止训练
- early stopping的容差(tolerance),在early stopping启用时,在经过
属性(attributes)
-
n_estimators_ : int
- 当early stopping启用时则是early stopping选定的学习器个数,否则等同于
n_estimators
- 当early stopping启用时则是early stopping选定的学习器个数,否则等同于
-
feature_importances_ : array, shape (n_features,)
- 特征重要性系数
-
oob_improvement_ : array, shape (n_estimators,)
- 包外样本相对于前一步迭代的损失提升,
oob_improvement_[0]是第一步迭代相对于init学习器的损失提升
- 包外样本相对于前一步迭代的损失提升,
-
train_score_ : array, shape (n_estimators,)
- 第i个得分
train_score_[i]是指模型第i步迭代时对包内样本的损失,如果subsample == 1,则是对所有训练集的损失
- 第i个得分
-
loss_ : LossFunction
- 损失函数对象
-
init_ : estimator
- 用于模型初始化的学习器对象
-
estimators_ : array of DecisionTreeRegressor, shape (n_estimators, 1)
- 拟合后的基学习器集合
方法(methods)
| 方法名称 | 方法解释 |
|---|---|
| apply(self, X) | Apply trees in the ensemble to X, return leaf indices. |
| decision_function(self, X) | Compute the decision function of X. |
| fit(self, X, y[, sample_weight, monitor]) | Fit the gradient boosting model. |
| get_params(self[, deep]) | Get parameters for this estimator. |
| predict(self, X) | Predict class for X. |
| predict_log_proba(self, X) | Predict class log-probabilities for X. |
| predict_proba(self, X) | Predict class probabilities for X. |
| score(self, X, y[, sample_weight]) | Returns the mean accuracy on the given test data and labels. |
| set_params(self, **params) | Set the parameters of this estimator. |
| staged_decision_function(self, X) | Compute decision function of X for each iteration. |
| staged_predict(self, X) | Predict class at each stage for X. |
| staged_predict_proba(self, X) | Predict class probabilities at each stage for X. |
GradientBoostingRegressor
参数(parameters)
-
loss : {‘ls’, ‘lad’, ‘huber’, ‘quantile’}, optional (default=’ls’)
- 需要优化的损失函数
-
learning_rate : float, optional (default=0.1)
- 学习率(learning_rate),与
n_estimators之间有个平衡
- 学习率(learning_rate),与
-
n_estimators : int (default=100)
- boosting迭代步数,Gradient boosting通常对于过拟合有鲁棒性,一个较大的数通常意味着更好的性能,整型,默认时100
-
subsample : float, optional (default=1.0)
- 用于训练基学习器的样本采样比例,小于1.0则等同于随机梯度提升(Stochasitc Gradient Boosting),与
n_estimators相互作用,如果小于1则会减少方差,增加偏差
- 用于训练基学习器的样本采样比例,小于1.0则等同于随机梯度提升(Stochasitc Gradient Boosting),与
-
criterion : string, optional (default=”friedman_mse”)
- 衡量特征分裂质量的函数,这是一个与基学习器决策树相关的参数,字符串类型,可选项,默认是”friedman_mse”
-
min_samples_split : int, float, optional (default=2)
- 用于分裂一个内部结点的最小所需的样本数,整型或者浮点型,可选项,默认是2
-
min_samples_leaf : int, float, optional (default=1)
- 一个叶子结点所要求的最小样本个数,这个参数有平滑模型的作用,特别是回归的学习任务里面。整型或者浮点型,可选项,默认是1
-
min_weight_fraction_leaf : float, optional (default=0.)
- 一个叶子结点所有输入样本权重总和的最小权重分数,浮点型,可选项,默认为0.
-
max_depth : integer, optional (default=3)
- 单棵回归树的最大深度,需要进行调参来获得更好的性能
-
min_impurity_decrease : float, optional (default=0.)
- 最小不纯度减少值,结点将会继续分裂,如果这个分裂对于不纯度的减少能够大于或者等于该值。浮点型,可选项,默认为0.
-
min_impurity_split : float, (default=1e-7)
- 建树过程中早起停止的阈值。如果节点的不纯度大于该值将会继续分裂,否则停止,成为叶子结点。浮点型,默认为1e-7
- 后续将会被
min_impurity_decrease参数替代
-
init : estimator or ‘zero’, optional (default=None)
- 用来模型初始化的学习器对象,可以提供
fit或者predict对象,如果是“zero”则初始预测为0
- 用来模型初始化的学习器对象,可以提供
-
random_state : int, RandomState instance or None, optional (default=None)
- 随机状态,有以下三种方式
- int, random_state is the seed used by the random number generator;
- RandomState instance, random_state is the random number generator;
- None, the random number generator is the RandomState instance used by np.random.
- 随机状态,有以下三种方式
-
max_features : int, float, string or None, optional (default=”auto”)
-
寻找最优分裂时所考虑的特征个数,整型、浮点型、字符串或者None,可选项,默认是“auto”
- int, then consider max_features features at each split.
- float, then max_features is a fraction and int(max_features * n_features) features are considered at each split.
- “auto”, then max_features=sqrt(n_features).
- “sqrt”, then max_features=sqrt(n_features) (same as “auto”).
- “log2”, then max_features=log2(n_features).
- None, then max_features=n_features.
-
-
alpha : float (default=0.9)
- 当
loss='huber'或者loss='quantile'时起作用,对应损失函数当中的参数
- 当
-
verbose : int, optional (default=0)
- 控制在学习和预测时是否输出中间结果,整型,可选项,默认是0
-
max_leaf_nodes : int or None, optional (default=None)
- 以最好的方式用
max_leaf_nodes来建树,如果是Nonde的话则对叶子结点的个数不限制,整型或者Node,可选项,默认是Node
- 以最好的方式用
-
warm_start : bool, optional (default=False)
- 布尔型,可选项,默认为False,如果设置为True,将重复使用上一次调用的解来学习并加入更多的学习器到集成算法当中
-
presort : bool or ‘auto’, optional (default=’auto’)
- 在寻找最佳分裂时是否预排序。自动模式将对稠密数据进行预排序,对稀疏数据进行自然排序,对于稀疏数据采用预排序将会报错
-
validation_fraction : float, optional, default 0.1
- Early stopping时作为验证集的比例,只有在
n_iter_no_change为整型时才起作用
- Early stopping时作为验证集的比例,只有在
-
n_iter_no_change : int, default None
- 在验证分数不再提高时用来决定是否采用early stopping来结束训练,整型,默认是None,不考虑early stopping
-
tol : float, optional, default 1e-4
- early stopping的容差(tolerance),在early stopping启用时,在经过
n_iter_no_change步迭代的提升都没有超过tol时,则停止训练
- early stopping的容差(tolerance),在early stopping启用时,在经过
属性(attributes)
-
feature_importances_ : array, shape (n_features,)
- 特征重要性系数
-
oob_improvement_ : array, shape (n_estimators,)
- 包外样本相对于前一步迭代的损失提升,
oob_improvement_[0]是第一步迭代相对于init学习器的损失提升
- 包外样本相对于前一步迭代的损失提升,
-
train_score_ : array, shape (n_estimators,)
- 第i个得分
train_score_[i]是指模型第i步迭代时对包内样本的损失,如果subsample == 1,则是对所有训练集的损失
- 第i个得分
-
loss_ : LossFunction
- 损失函数对象
-
init_ : estimator
- 用于模型初始化的学习器对象
-
estimators_ : array of DecisionTreeRegressor, shape (n_estimators, 1)
- 拟合后的基学习器集合
方法(methods)
| 方法名称 | 方法解释 |
|---|---|
| apply(self, X) | Apply trees in the ensemble to X, return leaf indices. |
| fit(self, X, y[, sample_weight, monitor]) | Fit the gradient boosting model. |
| get_params(self[, deep]) | Get parameters for this estimator. |
| predict(self, X) | Predict regression target for X. |
| score(self, X, y[, sample_weight]) | Returns the coefficient of determination R^2 of the prediction. |
| set_params(self, **params) | Set the parameters of this estimator. |
| staged_predict(self, X) | Predict regression target at each stage for X. |
应用场景
GBDT应用场景广泛,几乎可用于所有回归问题(线性/非线性),相对logistic regression仅能用于线性回归,GBDT的适用面非常广。亦可用于二分类问题(设定阈值,大于阈值为正例,反之为负例)。
此外,GBDT能够起到特征组合和特征选择的作用,可以作为终端学习器的前置作为特征工程的工具之一,比如Facebook就利用GBDT的这一特性,在GBDT后面接一个LR模型构建CRT模型来预测广告点击率,具体参阅相关论文Practical Lessons from Predicting Clicks on Ads at
Facebook。这也是GBDT在推荐系统场景的应用。
另外,在金融领域中的需求如欺诈检测、信用评级等,GBDT算法也能够发挥巨大的作用,有着大量基于GBDT算法的反欺诈模型、信用评分卡模型案例。