AdaBoost
前面我们介绍了使用 Boosting
思想的 AdaBoost
,它是通过前一轮决策的结果来给样本设置权重,决策正确的权重减小,决策错误的权重增加;然后将加权后的数据集输入下一个弱学习器训练,直到达到训练停止条件。
Boosting
思想的GBDT
、XGBoost
,在目前的竞赛和工业界中使用非常频繁,能够有效的应用到分类、回归,更是因为近几年被应用于构建搜索排序的机器学习模型而引起广泛关注。虽然用起来不难,但是要想完整理解它的原理及推导不是那么容易,本篇尽可能通过简单的方式来介绍。
本篇代码可见:Github
在介绍 GBDT
前,我们先来理解何为提升树:
提升树是以决策树为基本分类器(弱分类器)的提升方法,提升树被认为是模型性能最好的方法之一。
提升树模型可以表示为决策树的加法模型:
f M ( x ) = ∑ m = 1 M T ( x ; Θ m ) f_M(x) = \sum_{m=1}^M T(x;\ Θ_m) fM(x)=m=1∑MT(x; Θm)
其中, T ( x ; Θ m ) T(x;\ Θ_m) T(x; Θm)表示决策树; Θ m Θ_m Θm表示决策树的参数; M M M表示数的个数
由于提升树是树的线性组合,而树的线性组合可以很好地拟合训练数据,即使数据中的输入和输出之间的关系很复杂也是如此,所以提升树是一个高功能的学习算法。
提升树学习算法的主要区别在于使用的损失函数不同:
\quad\quad 对于二分类问题,提升树只需要将 AdaBoost
算法中的基本分类器(弱学习器)限定为二分类数即可,可以说这时的提升树是AdaBoost
算法的特殊情况,具体参考 AdaBoost 的介绍来理解。
\quad\quad 已知一个训练数据集 T = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . , ( x N , y N ) } T = \{(x_1,y_1),(x_2,y_2),...,(x_N,y_N)\} T={(x1,y1),(x2,y2),...,(xN,yN)}, x i ∈ X ⊆ R n x_i \in \mathcal{X} \subseteq R^{n} xi∈X⊆Rn, X \mathcal{X} X为输入空间, y i ∈ Y ⊆ R y_i \in \mathcal{Y} \subseteq R yi∈Y⊆R, Y \mathcal{Y} Y为输出空间。
如果将输入空间划分为 J J J 个互相不相交的区域 R 1 , R 2 , . . . , R J R_1,R_2,...,R_J R1,R2,...,RJ,并且在每个区域上确定输出的常量 c j c_j cj,那么决策树可表示为:
T ( x ; Θ ) = ∑ j = 1 J c j I ( x ∈ R j ) T(x; Θ) = \sum_{j=1}^J c_jI(x \in R_j) T(x;Θ)=j=1∑JcjI(x∈Rj)
I ( x ∈ R j ) I(x \in R_j) I(x∈Rj)为指示函数,表示 如果 x x x 在分区 R j R_j Rj中返回1,否则返回0;$T(x; Θ) $表示每个区域的输出常量的集合
其中,参数 Θ = { ( R 1 , c 1 ) , ( R 2 , c 2 ) , . . . , ( R j , c j ) } Θ = \{(R_1,c_1),(R_2,c_2),...,(R_j,c_j)\} Θ={(R1,c1),(R2,c2),...,(Rj,cj)}表示数的区域划分和各区域上的常量; J J J是回归树的复杂度,即叶子节点
回归问题提升树使用以下前向分步算法:
f 0 ( x ) = 0 f_0(x) = 0 f0(x)=0
f m ( x ) = f m − 1 ( x ) + T ( x ; Θ m ) m = 1 , 2 , 3 , . . . , M f_m(x) = f_{m-1}(x) + T(x; Θ_m)\quad\quad m = 1,2,3,...,M fm(x)=fm−1(x)+T(x;Θm)m=1,2,3,...,M
f M ( x ) = ∑ m = 1 M T ( x ; Θ m ) f_M(x) = \sum_{m=1}^M T(x; Θ_m) fM(x)=m=1∑MT(x;Θm)
在前向分步算法的第m步,给定当前模型 f m − 1 ( x ) f_{m-1}(x) fm−1(x),需求解:
Θ m ^ = a r g min Θ m ∑ i = 1 N L ( y i , f m − 1 ( x i ) + T ( x ; Θ m ) ) \hat{Θ_m} = arg \min_{Θ_m} \sum_{i=1}^N L\Big(y_i, f_{m-1}(x_i) + T(x;Θ_m)\Big) Θm^=argΘmmini=1∑NL(yi,fm−1(xi)+T(x;Θm))
得到 Θ m ^ \hat{Θ_m} Θm^ ,即第m棵树的参数。
其中, L ( y i , f m − 1 ( x i ) + T ( x ; Θ m ) ) L\Big(y_i, f_{m-1}(x_i) + T(x;Θ_m)\Big) L(yi,fm−1(xi)+T(x;Θm))为损失函数,当使用平方误差损失时:
L ( y , f ( x ) ) = ( y − f ( x ) ) 2 L(y, f(x)) = (y - f(x)) ^2 L(y,f(x))=(y−f(x))2
y y y为真实值, f ( x ) f(x) f(x)为预测值
则 Θ m ^ \hat{Θ_m} Θm^中的损失变为:
L ( y i , f m − 1 ( x i ) + T ( x ; Θ m ) ) L\Big(y_i, f_{m-1}(x_i) + T(x;Θ_m)\Big) L(yi,fm−1(xi)+T(x;Θm))
= [ y − ( f m − 1 ( x ) + T ( x ; Θ m ) ] 2 = [y - (f_{m-1}(x) + T(x;Θ_m)]^2 =[y−(fm−1(x)+T(x;Θm)]2
= [ r − T ( x ; Θ m ) ] 2 = [r -T(x;Θ_m)]^2 =[r−T(x;Θm)]2
其中, r = y − f m − 1 ( x ) r = y - f_{m-1}(x) r=y−fm−1(x)是当前模型拟合数据的残差
所以对于回归问题的提升树算法来说,只需要简单地拟合当前模型的残差即可。
回归问题的提升树算法:
输入: T = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . , ( x N , y N ) } T = \{(x_1,y_1),(x_2,y_2),...,(x_N,y_N)\} T={(x1,y1),(x2,y2),...,(xN,yN)}, x i ∈ X ⊆ R n x_i \in \mathcal{X} \subseteq R^{n} xi∈X⊆Rn, y i ∈ Y ⊆ R y_i \in \mathcal{Y} \subseteq R yi∈Y⊆R;
输出:提升树 f M ( x ) f_M(x) fM(x)
(1)初始化树 f 0 ( x ) = 0 f_0(x) = 0 f0(x)=0
(2)对 m = 1 , 2 , . . . , M m = 1,2,...,M m=1,2,...,M
r m i = y i − f m − 1 ( x i ) i = 1 , 2 , . . . , N r_{mi} = y_i - f_{m-1}(x_i) \quad\quad i = 1,2,...,N rmi=yi−fm−1(xi)i=1,2,...,N
(3)得到回归提升树:
f M ( x ) = ∑ m = 1 M T ( x ; Θ m ) f_M(x) = \sum_{m=1}^M T(x; Θ_m) fM(x)=m=1∑MT(x;Θm)
通过数据数据进一步理解回归提升树。已知训练数据 x x x的取值范围为 [ 0.5 , 10.5 ] [0.5, 10.5] [0.5,10.5], y y y的取值范围为 [ 5.0 , 10.0 ] [5.0, 10.0] [5.0,10.0],如下表:
x i x_i xi | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
y i y_i yi | 5.56 | 5.70 | 5.91 | 6.40 | 6.80 | 7.05 | 8.90 | 8.70 | 9.00 | 9.05 |
下面就按照上面的回归问题的提升树算法来求:
考虑以下优化问题:
min s [ min c 1 ∑ x i ∈ R 1 ( y i − c 1 ) 2 + min c 2 ∑ x i ∈ R 2 ( y i − c 2 ) 2 ] \min_s[\min_{c_1}\sum_{x_i \in R_1}(y_i - c_1)^2 +\min_{c_2}\sum_{x_i \in R_2}(y_i - c_2)^2 ] smin[c1minxi∈R1∑(yi−c1)2+c2minxi∈R2∑(yi−c2)2]
求解训练数据的切分点s:
R 1 = { x ∣ x ⩽ s } R 2 = { x ∣ x > s } R_1=\{x|x \leqslant s\} \quad\quad R_2= \{x|x > s\} R1={x∣x⩽s}R2={x∣x>s}
容易求得在 R 1 , R 2 R_1,R_2 R1,R2内部使平方损失误差达到最小值的 c 1 , c 2 c_1,c_2 c1,c2为:
c 1 = 1 N ∑ x i ∈ R 1 y i c 2 = 1 N ∑ x i ∈ R 2 y i c_1 = \frac{1}{N}\sum_{x_i \in R_1} y_i \quad\quad c_2 = \frac{1}{N}\sum_{x_i \in R_2} y_i c1=N1xi∈R1∑yic2=N1xi∈R2∑yi
这里 N 1 , N 2 N_1,N_2 N1,N2是 R 1 , R 2 R_1,R_2 R1,R2的样本点数。
第一步:求 T 1 ( x ) T_1(x) T1(x)
求训练数据的切分点,根据所给数据,考虑如下切分点:
1.5 , 2.5 , 3.5 , 4.5 , 5.5 , 6.5 , 7.5 , 8.5 , 9.5 1.5,\ 2.5,\ 3.5,\ 4.5,\ 5.5,\ 6.5,\ 7.5,\ 8.5,\ 9.5 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5
对各切分点,不难求出相应的 R 1 , R 2 , c 1 , c 2 R_1,R_2,c_1,c_2 R1,R2,c1,c2及
m ( s ) = min c 1 ∑ x i ∈ R 1 ( y i − c 1 ) 2 + min c 2 ∑ x i ∈ R 2 ( y i − c 2 ) 2 m(s) = \min_{c_1}\sum_{x_i \in R_1}(y_i - c_1)^2 +\min_{c_2}\sum_{x_i \in R_2}(y_i - c_2)^2 m(s)=c1minxi∈R1∑(yi−c1)2+c2minxi∈R2∑(yi−c2)2
例如,当 s = 1.5 s = 1.5 s=1.5时, R 1 = { 1 } , R 2 = { 2 , 3 , . . . , 10 } , c 1 = 5.56 , c 2 = 7.50 R_1=\{1\},R_2 = \{2,3,...,10\},c_1=5.56,c_2=7.50 R1={1},R2={2,3,...,10},c1=5.56,c2=7.50
m ( s ) = min c 1 ∑ x i ∈ R 1 ( y i − c 1 ) 2 + min c 2 ∑ x i ∈ R 2 ( y i − c 2 ) 2 = 0 + 15.72 = 15.72 m(s) = \min_{c_1} \sum_{x_i \in R_1}(y_i - c_1)^2 + \min_{c_2} \sum_{x_i \in R_2}(y_i - c_2)^2 = 0 + 15.72 = 15.72 m(s)=c1minxi∈R1∑(yi−c1)2+c2minxi∈R2∑(yi−c2)2=0+15.72=15.72
计算所有切分点 s s s的 m ( s ) m(s) m(s),如下表:
s | 1.5 | 2.5 | 3.5 | 4.5 | 5.5 | 6.5 | 7.5 | 8.5 | 9.5 |
---|---|---|---|---|---|---|---|---|---|
m ( s ) m(s) m(s) | 15.72 | 12.07 | 8.36 | 5.78 | 3.91 | 1.93 | 8.01 | 11.73 | 15.74 |
由上表可知,当 s = 6.5 s = 6.5 s=6.5时 m ( s ) m(s) m(s)达到最小值,此时 R 1 = { 1 , 2 , 3 , 4 , 5 , 6 } , R 2 = { 7 , 8 , 9 , 10 } , c 1 = 6.24 , c 2 = 8.91 R_1=\{1,2,3,4,5,6\},R_2=\{7,8,9,10\},c_1=6.24,c_2=8.91 R1={1,2,3,4,5,6},R2={7,8,9,10},c1=6.24,c2=8.91,所以回归树 T 1 ( x ) T_1(x) T1(x)为:
T 1 ( x ) = { 6.24 , x < 6.5 8.91 , x ⩾ 6.5 T_1(x)=\begin{cases} 6.24, \quad x < 6.5 \\ 8.91, \quad x \geqslant 6.5 \end{cases} T1(x)={6.24,x<6.58.91,x⩾6.5
f 1 ( x ) = T 1 ( x ) f_1(x) = T_1(x) f1(x)=T1(x)
用 f 1 ( x ) f_1(x) f1(x) 拟合训练数据的残差如下表, r 2 i = y i − f 1 ( x i ) , i = 1 , 2 , . . . , 10 r_{2i} = y_i - f_1(x_i),\quad i=1,2,...,10 r2i=yi−f1(xi),i=1,2,...,10
x i x_i xi | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
r 2 i r_{2i} r2i | -0.68 | -0.54 | -0.33 | 0.16 | 0.56 | 0.81 | -0.01 | -0.21 | 0.09 | 0.14 |
用 f 1 ( x ) f_1(x) f1(x) 拟合训练数据的平方损失误差:
L ( y , f 1 ( x ) ) = ∑ i = 1 10 ( y i − f 1 ( x i ) ) 2 = 1.93 L(y, f_1(x)) = \sum_{i=1}^{10}(y_i - f_1(x_i))^2 = 1.93 L(y,f1(x))=i=1∑10(yi−f1(xi))2=1.93
第二步:求 T 2 ( x ) T_2(x) T2(x)
方法与第一步一样,只是拟合的数据从原数据变为残差数据,可以得到:
T 2 ( x ) = { − 0.52 , x < 3.5 0.22 , x ⩾ 3.5 T_2(x)=\begin{cases} -0.52, \quad x < 3.5 \\ 0.22, \ \ \ \quad x \geqslant 3.5 \end{cases} T2(x)={−0.52,x<3.50.22, x⩾3.5
f 2 ( x ) = f 1 ( x ) + T 2 ( x ) = { 5.72 , x < 3.5 6.46 , 3.5 ⩽ x < 6.5 9.13 , x ⩾ 6.5 f_2(x) = f_1(x) + T_2(x) = \begin{cases} 5.72, \quad x < 3.5 \\ 6.46, \quad 3.5 \leqslant x < 6.5 \\ 9.13, \quad x \geqslant 6.5 \end{cases} f2(x)=f1(x)+T2(x)=⎩⎪⎨⎪⎧5.72,x<3.56.46,3.5⩽x<6.59.13,x⩾6.5
用 f 2 ( x ) f_2(x) f2(x) 拟合训练数据的平方损失误差:
L ( y , f 2 ( x ) ) = ∑ i = 1 10 ( y i − f 2 ( x i ) ) 2 = 0.79 L(y, f_2(x)) = \sum_{i=1}^{10}(y_i - f_2(x_i))^2 = 0.79 L(y,f2(x))=i=1∑10(yi−f2(xi))2=0.79
重复以上步骤,求得:
T 3 ( x ) = { 0.15 , x < 6.5 − 0.22 , x ⩾ 6.5 T_3(x)=\begin{cases} 0.15, \ \ \ \quad x < 6.5 \\ -0.22, \quad x \geqslant 6.5 \end{cases} T3(x)={0.15, x<6.5−0.22,x⩾6.5
L ( y , f 3 ( x ) ) = 0.47 L(y, f_3(x)) = 0.47 L(y,f3(x))=0.47
T 4 ( x ) = { − 0.16 , x < 4.5 0.11 , x ⩾ 4.5 T_4(x)=\begin{cases} -0.16, \quad x < 4.5 \\ 0.11, \ \ \ \quad x \geqslant 4.5 \end{cases} T4(x)={−0.16,x<4.50.11, x⩾4.5
L ( y , f 4 ( x ) ) = 0.30 L(y, f_4(x)) = 0.30 L(y,f4(x))=0.30
T 5 ( x ) = { 0.07 , x < 6.5 − 0.11 , x ⩾ 6.5 T_5(x)=\begin{cases} 0.07, \ \ \ \quad x < 6.5 \\ -0.11, \quad x \geqslant 6.5 \end{cases} T5(x)={0.07, x<6.5−0.11,x⩾6.5
L ( y , f 5 ( x ) ) = 0.23 L(y, f_5(x)) = 0.23 L(y,f5(x))=0.23
T 6 ( x ) = { − 0.15 , x < 2.5 0.04 , x ⩾ 2.5 T_6(x)=\begin{cases} -0.15, \quad x < 2.5 \\ 0.04, \ \ \ \quad x \geqslant 2.5 \end{cases} T6(x)={−0.15,x<2.50.04, x⩾2.5
f 6 ( x ) = f 5 ( x ) + T 6 ( x ) = T 1 ( x ) + T 2 ( x ) + T 3 ( x ) + T 4 ( x ) + T 5 ( x ) + T 6 ( x ) f_6(x) = f_5(x) + T_6(x) = T_1(x)+T_2(x)+T_3(x)+T_4(x)+T_5(x)+T_6(x) f6(x)=f5(x)+T6(x)=T1(x)+T2(x)+T3(x)+T4(x)+T5(x)+T6(x)
f 6 ( x ) = { 5.63 , x < 2.5 5.82 , 2.5 ⩽ x < 3.5 6.56 , 3.5 ⩽ x < 4.5 6.83 , 4.5 ⩽ x < 6.5 8.95 , x ⩾ 6.5 f_6(x)= \begin{cases} 5.63, \quad x<2.5 \\ 5.82, \quad 2.5 \leqslant x < 3.5 \\ 6.56, \quad 3.5 \leqslant x < 4.5 \\ 6.83, \quad 4.5 \leqslant x < 6.5 \\ 8.95, \quad x \geqslant 6.5 \end{cases} f6(x)=⎩⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎧5.63,x<2.55.82,2.5⩽x<3.56.56,3.5⩽x<4.56.83,4.5⩽x<6.58.95,x⩾6.5
L ( y , f 3 ( x ) ) = 0.17 L(y, f_3(x)) = 0.17 L(y,f3(x))=0.17
假设此时已经满足误差要求,那么 f ( x ) = f 6 ( x ) f(x) = f_6(x) f(x)=f6(x) 即为所求提升树。
GBDT(Gradient Boosting Decison Tree)
(梯度提升迭代决策树)别名:GBT(Gradient Boosting Tree)
、GTB(Gradient Tree Boosting)
、GBRT(Gradient Boosting Regression Tree)
、MART(Multiple Additive Regression Tree)
GBDT
与 AdaBoost
的区别:AdaBoost
算法是利用前一轮的弱学习器的误差来更新样本权重值,然后一轮一轮的迭代;GBDT
也是迭代,但是GBDT
要求弱学习器必须是CART
模型,而且GBDT
在模型训练的时候,是要求模型预测的样本损失尽可能的小。
- 如图,此过程便是上面提到的提升树。假设我们有训练集 ( x 1 , x 2 , x 3 , 30 ) (x_1,x_2,x_3,30) (x1,x2,x3,30) ,x为特征,30为年龄;
- 第一次训练的弱分类器预测为20,然后我们用真实值-第一个弱分类器的预测值=残差,作为第二个弱分类器的训练数据 ( x 1 , x 2 , x 3 , 10 ) (x_1,x_2,x_3,10) (x1,x2,x3,10)
- 第二次训练的弱分类器预测为6,同样计算残差作为第三个弱分类器的训练数据, ( x 1 , x 2 , x 3 , 4 ) (x_1,x_2,x_3,4) (x1,x2,x3,4)
- 第三次训练的弱分类器预测为4,同样计算残差作为第四个弱分类器的训练数据, ( x 1 , x 2 , x 3 , 1 ) (x_1,x_2,x_3,1) (x1,x2,x3,1)
- 第四次训练的弱分类器预测为1,此时残差为0,训练结束
假设有个新的待预测数据,按构建子树的顺序进行预测,然后将每个子树的预测结果累加便是预测结果。
假设训练集如下:
样本编号 | 购物金额 | 上网时长 | 上网时段 | 对百度知道的使用方式 | 年龄 |
---|---|---|---|---|---|
A | 0.5k | 0.5h | 晚上上网 | 提问 | 14 |
B | 0.8k | 1.5h | 晚上上网 | 回答 | 16 |
C | 1.5k | 3.0h | 全天上网 | 提问 | 24 |
D | 2.0k | 3.0h | 晚上上网 | 回答 | 26 |
对于训练集,此决策树的准确率为100%;
我们知道在构建决策树的时候,为了尽可能正确分类训练样本,节点划分过程不断重复,有时候就会导致决策树节点过多,造成模型过拟合;
- 假设待预测数据为:购物金额0.5k,上网时长1.5h,晚上上网,提问,14岁
- 传统决策树会预测为16岁
GBDT
来训练由于数据比较少,我们限定2棵子树,每个子树深度为1,训练结果如下图:
图中,上面一棵树还是按有收入是否划分,下面一棵树以前面一个数的残差作为训练样本,当新的预测值与残差相等(也就第二次计算的残差中为0的),则只需把第二棵树的结论累加到第一棵树上就能得到真实年龄;第二棵树的残差都为0,说明所有样本都正确预测了
其实,我们发现两个方法的准确率都是100%,那么为什么要用GBDT
呢?
原因就是,传统的决策树容易过拟合,假设有个新数据待预测:购物金额0.5k,上网时长1.5h,晚上上网,提问,14岁;
GBDT
预测为:(-1)+15=14岁;现在,我们回头来看看上图,由20变为0,变化比较大,容易造成过拟合;
可以给定步长step
,在构建下一棵树的时候使用step
* 残差值作为输入,这样可以避免过拟合。
GBDT
算法推导GBDT
由三部分构成:DT(Regression Decistion Tree)
、GB(Gradient Boosting)
和Shrinkage(衰减)
DT(Regression Decistion Tree)
——回归决策树GBDT
中的决策树都是回归树,不是分类树:
我们知道GBDT
的思想使用了集成学习,也就是将每棵决策树(弱学习器)的结果累加,得到最终结果:
因此 GBDT
中决策树只能回归树。
GB(Gradient Boosting)
——梯度提升 \quad\quad 本篇一开始介绍了提升树利用加法模型与前向分步算法实现学习的优化过程。提升树使用平方误差损失和指数损失函数时,每一步优化都可以如上面的步骤简单实现。但是对于一般损失函数而言,往往每一步优化并不那么容易,针对这个问题,Freidman
提出了梯度提升算法,这是利用最速下降法的近似方法,其关键是利用损失函数的负梯度在当前模型的值。
假设 F ( X ) F(X) F(X) 是一组最优基函数 f i ( X ) f_i(X) fi(X)的线性组合:
F ( X ) = ∑ i = 0 M f i ( X ) F(X) = \sum_{i=0}^Mf_i(X) F(X)=i=0∑Mfi(X)
损失函数为:
l o s s = L ( y , F ( X ) ) loss = L(y,F(X)) loss=L(y,F(X))
最优解为:
F ∗ ( X ) = a r g min F L ( y , F ( X ) ) F^*(X) = arg \min_F L(y,F(X)) F∗(X)=argFminL(y,F(X))
(1)假设第m-1轮强学习器为:
F m − 1 ( X ) = ∑ i = 1 m − 1 f i ( X ) F_{m-1}(X) = \sum_{i=1}^{m-1}f_i(X) Fm−1(X)=i=1∑m−1fi(X)
损失函数为:
l o s s = L ( y , F m − 1 ( X ) ) loss = L\Big(y,F_{m-1}(X)\Big) loss=L(y,Fm−1(X))
(2)第m轮强学习器为:
F m ( X ) = ∑ i = 1 m f i ( X ) = F m − 1 ( X ) + f m ( X ) F_{m}(X) = \sum_{i=1}^{m}f_i(X)=F_{m-1}(X) + f_m(X) Fm(X)=i=1∑mfi(X)=Fm−1(X)+fm(X)
损失函数为:
l o s s = L ( y , ( F m − 1 ( X ) + f m ( X ) ) ) loss = L\Big(y, (F_{m-1}(X)+f_m(X))\Big) loss=L(y,(Fm−1(X)+fm(X)))
(3)求解本轮的最优 F m ∗ ( X ) F_m^*(X) Fm∗(X)
F m ∗ ( X ) = F m − 1 ( X ) + L ( y , ( F m − 1 ( X ) + f m ( X ) ) ) F_m^*(X) = F_{m-1}(X) + L\Big(y, (F_{m-1}(X)+f_m(X))\Big) Fm∗(X)=Fm−1(X)+L(y,(Fm−1(X)+fm(X)))
= F m − 1 ( X ) + a r g min f ∑ i = 1 n L ( y i , ( F m − 1 ( x i ) + f m ( x i ) ) ) = F_{m-1}(X) +arg \min_f\sum_{i=1}^nL\Big(y_i,\big(F_{m-1}(x_i) + f_m(x_i)\big)\Big) =Fm−1(X)+argfmini=1∑nL(yi,(Fm−1(xi)+fm(xi)))
其中, n n n 为样本数
以上在每次选择最优基函数 f m ( X ) f_m(X) fm(X)时比较困难,可以使用梯度下降的方法近似计算:
给定常数 f 0 ( X ) = F 0 ( X ) f_0(X) = F_0(X) f0(X)=F0(X):
f 0 ( X ) = F 0 ( X ) = a r g min c ∑ i = 1 n L ( y i , c ) f_0(X) =F_0(X) = arg \min_c \sum_{i=1}^n L(y_i,c) f0(X)=F0(X)=argcmini=1∑nL(yi,c)
根据梯度下降计算学习率:
α i m = [ ∂ L ( y i , F ( x i ) ) ∂ F ( x i ) ] F ( x i ) = F m − 1 ( x i ) \alpha_{im} = \Big[\frac{\partial L(y_i,F(x_i))}{\partial F(x_i)}\Big]_{F(x_i) = F_{m-1}(x_i)} αim=[∂F(xi)∂L(yi,F(xi))]F(xi)=Fm−1(xi)
使用数据 ( x i , α i m ) , i = 1 , 2 , . . . , n (x_i,\alpha_{im}),\quad i = 1,2,...,n (xi,αim),i=1,2,...,n计算拟合残差找到一个CART
回归树,得到第m棵树:
c m j = a r g min c ∑ x i ∈ l e a f j L ( y i , ( f m − 1 ( x i ) + c ) ) c_{mj} = arg \min_c \sum_{x_i \in leaf_j} L\Big(y_i, \big(f_{m-1}(x_i)+c\big)\Big) cmj=argcminxi∈leafj∑L(yi,(fm−1(xi)+c))
h m ( x ) = ∑ j = 1 ∣ l e a f ∣ m c m j I ( x ∈ l e a f m j ) h_m(x)=\sum_{j=1}^{|leaf|_m}c_{mj} I(x \in leaf_{mj}) hm(x)=j=1∑∣leaf∣mcmjI(x∈leafmj)
更新模型:
F m ( X ) = F m − 1 ( X ) + ∑ j = 1 ∣ l e a f ∣ m c m j I ( x ∈ l e a f m j ) F_m(X) = F_{m-1}(X) + \sum_{j=1}^{|leaf|_m}c_{mj} I(x \in leaf_{mj}) Fm(X)=Fm−1(X)+j=1∑∣leaf∣mcmjI(x∈leafmj)
F ( X ) = f 0 ( X ) + ∑ m = 1 M ∑ j = 1 ∣ l e a f ∣ m c m j I ( x ∈ l e a f m j ) F(X) = f_0(X) + \sum_{m=1}^M\sum_{j=1}^{|leaf|_m}c_{mj} I(x \in leaf_{mj}) F(X)=f0(X)+m=1∑Mj=1∑∣leaf∣mcmjI(x∈leafmj)
训练弱学习器: h t ( x ) h_t(x) ht(x)使:
f t − 1 ( x ) → f t ( x ) f_{t-1}(x) \rightarrow f_t(x) ft−1(x)→ft(x)
L ( y , f t − 1 ( x ) ) → L ( y , ( f t − 1 ( x ) + h t ( x ) ) ) L(y,f_{t-1}(x)) \rightarrow L\Big(y,\big(f_{t-1}(x)+h_t(x)\big)\Big) L(y,ft−1(x))→L(y,(ft−1(x)+ht(x)))
Shrinkage(衰减)
\quad\quad 每次走一小步逐渐逼近结果的效果,要比每次迈一大步很快逼近结果的方式更容易避免过拟合。换句话说缩减思想不完全信任每一个棵残差树,它认为每棵树只学到了真理的一小部分,累加的时候只累加一小部分,只有通过多学几棵树才能弥补不足。
Shrinkage
仍然以残差作为学习目标,但由于它采用的是逐步逼近目标的方式,导致各个树的残差是渐变的而不是陡变的。之所以这样做也是基于模型过拟合的考虑。
GBDT
案例sklearn
库 ensemble.GradientBoostingRegressor
类API:
sklearn.ensemble.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.0, max_depth=3,
min_impurity_decrease=0.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=’auto’, validation_fraction=0.1, n_iter_no_change=None, tol=0.0001)
常用参数说明:
参数 | 描述 |
---|---|
loss: {‘ls’,‘lad’,‘huber’,‘quantile’},可选(默认值=‘ls’) | 损失函数。'ls’指的是最小二乘回归;‘lad’(最小绝对偏差)是一种高度鲁棒的损失函数,仅基于输入变量的顺序信息;'huber’是两者的结合;'quantile’允许分位数回归(使用alpha来指定分位数)。 |
learning_rate : float,optional(默认值= 0.1) | 学习率通过learning_rate缩小每棵树的贡献。在learning_rate和n_estimators之间进行权衡。 |
n_estimators : int(默认值= 100) | 决策树数目,较大数目通常会产生更好的性能 |
max_depth : int,optional(默认= 3) | 每个决策树的深度 |
alpha : float(默认值= 0.9) | huber损失函数和分位数损失函数的α分位数。只有当loss='huber’或loss=‘quantile’ |
其他参数,有些在之前都有遇到过,也可参考官方文档
GBDT
集成线性回归本案例使用波士顿房屋租赁数据实现线性回归和GBDT预测,并对结果进行比较:
线性回归结果:
训练集上R^2:0.77301
测试集上R^2:0.58922
GBDT结果:
训练集上R^2:0.76730
测试集上R^2:0.64739
可以发现,在测试集上效果有所提升
代码可见:07_GBDT.py
XGBoost
XGBoost
是 GBDT
的升级版,前面介绍到,GBDT
是一种基于 Boosting
集成思想的学习器,并采用梯度提升的方法进行每一轮的迭代最终组合出强学习器,这样的话算法的运行往往要生成一定数量的树才能达到令我们满意的准确率。当数据集大且较为复杂时,运行一次极有可能需要几千次的迭代运算,这将对我们使用算法造成巨大的计算瓶颈。
针对这一问题,华盛顿大学的陈天奇博士开发出了 XGBoost
,XGBoost
最大的特点在于它能够自动利用CPU的多线程进行并行计算,同时在算法上加以改进,极大地提升了模型训练速度和预测精度。
在 XGBoost
算法中,目标函数的形式为:
O b j ( θ ) = L ( θ ) + Ω ( Θ ) Obj(\theta) = L(\theta) +Ω(Θ) Obj(θ)=L(θ)+Ω(Θ)
其中, L ( θ ) L(\theta) L(θ)为损失函数,常用损失函数有:
Logistic
损失: L ( θ ) = ∑ i [ y i l n ( 1 + e − y i ^ ) + ( 1 − y i ) l n ( 1 + e y ^ i ) ] L(\theta) = \sum_i [y_iln(1+e^{-\hat{y_i}}) + (1-y_i)ln(1 + e^{\hat{y}_i})] L(θ)=∑i[yiln(1+e−yi^)+(1−yi)ln(1+ey^i)]Ω ( Θ ) Ω(Θ) Ω(Θ):正则化项
已知目标函数:
O b j ( θ ) = L ( θ ) + Ω ( Θ ) Obj(\theta) = L(\theta) +Ω(Θ) Obj(θ)=L(θ)+Ω(Θ)
- 如果目标函数中的损失函数权重过高,那么模型的预测精度则不尽人意;
- 反之如果正则项的权重过高,所生成的模型则会出现过拟合情况,难以对新的数据集做出有效预测;
- 只有平衡好两者之间的关系,控制好模型复杂度,并在此基础上对参数进行求解,生成的模型才会“简单有效”。
XGBoost
推导过程假设某次迭代后集成的模型表示为:
y i ^ = ∑ k = 1 K f k ( X ) , f k ∈ F \hat{y_i} = \sum_{k=1}^Kf_k(X),f_k \in F yi^=k=1∑Kfk(X),fk∈F
其中, y i ^ \hat{y_i} yi^也就是前文的 f m ( X ) f_m(X) fm(X)
相对应的目标函数:
O b j = ∑ i n L ( y i , y i ^ ) + ∑ k = 1 K Ω ( f k ) Obj = \sum_i^nL(y_i,\hat{y_i}) + \sum_{k=1}^KΩ(f_k) Obj=i∑nL(yi,yi^)+k=1∑KΩ(fk)
接下来,我们按之前介绍GBDT
的方式来介绍
这里先给出一些数据,以便接下来使用;假设有如下数据,判断谁愿意去玩游戏:
编号 | 是否玩电脑 | 性别 | 年龄 |
---|---|---|---|
A | 是 | 男 | 12 |
B | 否 | 女 | 14 |
C | 是 | 男 | 25 |
D | 否 | 女 | 26 |
E | 否 | 女 | 27 |
图中权重表示该人愿意去玩游戏的得分,得分越大越愿意;得分为负,表示不愿意
最终A的得分为2.9,B的得分为-0.8,C的得分为-0.1,D的得分为-1.9,E的得分为-1.9;
(1)第 t − 1 t-1 t−1 轮的模型可表示为:
y i ^ ( t − 1 ) = ∑ k = 1 t − 1 f k ( X ) \hat{y_i}^{(t-1)} = \sum_{k=1}^{t-1} f_k(X) yi^(t−1)=k=1∑t−1fk(X)
损失函数为:
O b j ( t − 1 ) = ∑ i n L ( y i , y i ^ ( t − 1 ) ) + ∑ k = 1 t − 1 Ω ( f k ) Obj^{(t-1)}= \sum_i^nL(y_i,\hat{y_i}^{(t-1)}) + \sum_{k=1}^{t-1}Ω(f_k) Obj(t−1)=i∑nL(yi,yi^(t−1))+k=1∑t−1Ω(fk)
(2)第 t t t 轮的模型可表示为:
y i ^ ( t ) = ∑ k = 1 t f k ( X ) = y i ^ ( t − 1 ) + f t ( X ) \hat{y_i}^{(t)} = \sum_{k=1}^{t} f_k(X)=\hat{y_i}^{(t-1)} + f_t(X) yi^(t)=k=1∑tfk(X)=yi^(t−1)+ft(X)
目标函数为:
O b j ( t ) = ∑ i n L ( y i , ( y i ^ ( t − 1 ) + f t ( X ) ) ) + ∑ k = 1 t Ω ( f t ) Obj^{(t)} = \sum_i^nL\Big(y_i,\big(\hat{y_i}^{(t-1)} + f_t(X)\big)\Big) + \sum_{k=1}^{t}Ω(f_t) Obj(t)=i∑nL(yi,(yi^(t−1)+ft(X)))+k=1∑tΩ(ft)
= ∑ i n L ( y i , ( y i ^ ( t − 1 ) + f t ( X ) ) ) + Ω ( f t ) + c o n s t a n t = \sum_i^nL\Big(y_i,\big(\hat{y_i}^{(t-1)} + f_t(X)\big)\Big) +Ω(f_t) + constant =i∑nL(yi,(yi^(t−1)+ft(X)))+Ω(ft)+constant
(3)考虑使用平方误差作为损失函数,目标函数可写为:
O b j ( t ) = ∑ i n ( y i − ( y i ^ ( t − 1 ) + f t ( x i ) ) ) 2 + Ω ( f t ) + c o n s t a n t Obj^{(t)} = \sum_i^n\Big(y_i - \big(\hat{y_i}^{(t-1)} + f_t(x_i)\big)\Big)^2 +Ω(f_t) + constant Obj(t)=i∑n(yi−(yi^(t−1)+ft(xi)))2+Ω(ft)+constant
= ∑ i n [ 2 y i ( y i ^ ( t − 1 ) + f t ( x i ) ) + f t 2 ( x i ) ] + Ω ( f t ) + c o n s t a n t = \sum_i^n\Big[2y_i \big(\hat{y_i}^{(t-1)}+ f_t(x_i)\big) + f_t^2(x_i)\Big] +Ω(f_t) + constant =i∑n[2yi(yi^(t−1)+ft(xi))+ft2(xi)]+Ω(ft)+constant
如果使用其他损失函数,可以采用泰勒展开近似来定义一个近似的目标函数,方便我们进行进一步的计算
泰勒展开: f ( x + Δ x ) ≈ f ( x ) + f ′ ( x ) Δ x + 1 2 f ′ ′ ( x ) Δ 2 x f(x+\Delta x) \approx f(x) + f'(x)\Delta x + \frac{1}{2}f''(x)\Delta^2x f(x+Δx)≈f(x)+f′(x)Δx+21f′′(x)Δ2x
(4)按泰勒展开目标函数又可写为:
O b j ( t ) = ∑ i = 1 n [ L ( y i , y i ^ ( t − 1 ) ) + g i f t ( x i ) + 1 2 h i f t 2 ( x i ) ] + Ω ( f t ) + c o n s t a n t Obj^{(t)} =\sum_{i=1}^n\Big[L(y_i,\hat{y_i}^{(t-1) }) + g_if_t(x_i) + \frac{1}{2}h_if^2_t(x_i)\Big]+Ω(f_t) + constant Obj(t)=i=1∑n[L(yi,yi^(t−1))+gift(xi)+21hift2(xi)]+Ω(ft)+constant
其中,
g i = ∂ L ( y i , y i ^ ( t − 1 ) ) ∂ y i ^ ( t − 1 ) g_i = \frac{\partial L(y_i,\hat{y_i}^{(t-1) })}{\partial \hat{y_i}^{(t-1)}} gi=∂yi^(t−1)∂L(yi,yi^(t−1))
h i = ∂ 2 L ( y i , y i ^ ( t − 1 ) ) ∂ y i ^ ( t − 1 ) h_i = \frac{\partial^2 L(y_i,\hat{y_i}^{(t-1) })}{\partial \hat{y_i}^{(t-1)}} hi=∂yi^(t−1)∂2L(yi,yi^(t−1))
(5)移除常数项目标函数写为:
O b j ( t ) = ∑ i = 1 n [ g i f t ( x i ) + 1 2 h i f t 2 ( x i ) ] + Ω ( f t ) Obj^{(t)} = \sum_{i=1}^n\Big[ g_if_t(x_i) + \frac{1}{2}h_if^2_t(x_i)\Big]+Ω(f_t) Obj(t)=i=1∑n[gift(xi)+21hift2(xi)]+Ω(ft)
Ω ( f ) = γ T + 1 2 λ ∑ j = 1 T w j 2 Ω(f) = \gamma T + \frac{1}{2}\lambda\sum_{j=1}^Tw_j^2 Ω(f)=γT+21λj=1∑Twj2
上式包含了一棵树里面节点的个数(左侧),以及每个树叶子节点上面输出分数的 L 2 L_2 L2 模平方(右侧)
- T T T :叶子的个数
- w w w:叶子节点的权重
- γ \gamma γ 作为叶子节点的系数,使
XGBoost
在优化目标函数的同时相当于做了预剪枝;- λ \lambda λ 作为 L 2 L_2 L2 平方模的系数也是要起到防止过拟合的作用
具体计算如下图:
其中, γ , λ \gamma,\lambda γ,λ由人为给定
O b j ( t ) ≈ ∑ i = 1 n [ g i f t ( x i ) + 1 2 h i f t 2 ( x i ) ] + γ T + 1 2 λ ∑ j = 1 T w j 2 Obj^{(t)} \approx \sum_{i=1}^n\Big[ g_if_t(x_i) + \frac{1}{2}h_if^2_t(x_i)\Big] +\gamma T + \frac{1}{2}\lambda\sum_{j=1}^Tw_j^2 Obj(t)≈i=1∑n[gift(xi)+21hift2(xi)]+γT+21λj=1∑Twj2
f t ( x i ) = w q ( x ) f_t(x_i) = w_{q(x)} ft(xi)=wq(x)
- 树的结构函数 q q q表示把输入x映射到对应叶子节点上
- w w w 给定了每个叶子节点对应的分数,即权重
因此,目标函数可以写为:
O b j ( t ) ≈ ∑ i = 1 n [ g i w q ( x i ) + 1 2 h i w q ( x i ) 2 ] + γ T + 1 2 λ ∑ j = 1 T w j 2 Obj^{(t)} \approx \sum_{i=1}^n\Big[ g_iw_{q(x_i)}+ \frac{1}{2}h_iw^2_{q(x_i)}\Big] +\gamma T + \frac{1}{2}\lambda\sum_{j=1}^Tw_j^2 Obj(t)≈i=1∑n[giwq(xi)+21hiwq(xi)2]+γT+21λj=1∑Twj2
= ∑ j = 1 T [ ( ∑ i ∈ I j g i ) w j + 1 2 ( ∑ i ∈ I j h i + λ ) w j 2 ] + γ T =\sum_{j=1}^T\Big[(\sum_{i \in I_j}g_i)w_j + \frac{1}{2}(\sum_{i \in I_j}h_i + \lambda)w_j^2\Big]+\gamma T =j=1∑T[(i∈Ij∑gi)wj+21(i∈Ij∑hi+λ)wj2]+γT
记: G j = ∑ i ∈ I j g i , H i = ∑ i ∈ I j h i G_j=\sum_{i \in I_j}g_i,H_i = \sum_{i \in I_j}h_i Gj=i∈Ij∑gi,Hi=i∈Ij∑hi
上式化简为:
O b j ( t ) = ∑ j = 1 T [ G j w j + 1 2 ( H j + λ ) w j 2 ] + γ T Obj^{(t)}=\sum_{j=1}^T\Big[G_jw_j + \frac{1}{2}(H_j + \lambda)w_j^2\Big]+\gamma T Obj(t)=j=1∑T[Gjwj+21(Hj+λ)wj2]+γT
将上式看作一个一元二次方程求最小值问题(变量为 w j w_j wj),处于对称轴处:
f ( x ) = a x 2 + b x + c , a > 0 f(x) = ax^2+bx+c ,a>0 f(x)=ax2+bx+c,a>0;最小值为: f ( − b 2 a ) f(-\frac{b}{2a}) f(−2ab)
故:
w j ∗ = − G j H j + λ w_j^* = -\frac{G_j}{H_j + \lambda} wj∗=−Hj+λGj
O b j ∗ = − 1 2 ∑ j = 1 T G j 2 H j + λ + γ T Obj^* = -\frac{1}{2}\sum_{j=1}^T\frac{G_j^2}{H_j + \lambda} + \gamma T Obj∗=−21j=1∑THj+λGj2+γT
- 如果树的结构函数 q q q确定了,那么相应的目标函数就能够根据上式计算出来。那么树的生成问题也就转换为找到一个最优的树结构 q q q,使得它具有最小的目标函数;
- 计算求得的 O b j Obj Obj 代表了当指定一个树的结构的时候,目标函数上面最多减少多少。所有我们可以把它叫做结构分数
\quad\quad 当寻找到最优的树结构时,我们可以不断地枚举不同树的结构,利用这个打分函数来寻找出一个最优结构的树,加入到我们的模型中,然后再重复这样的操作;不过枚举所有树结构这个操作不太可行,在这里 XGBoost
采用了常用的贪心法,即每一次尝试去对已有的叶子加入一个分割。对于一个具体的分割方案,我们可以获得的增益可以由如下公式计算得到:
G a i n = 1 2 [ G L 2 H L + λ + G R 2 H R + λ − ( G L + G R ) 2 H L + H R + λ ] − γ Gain = \frac{1}{2}\Big[\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}\Big] - \gamma Gain=21[HL+λGL2+HR+λGR2−HL+HR+λ(GL+GR)2]−γ
其中:
G L 2 H L + λ , G R 2 H R + λ , ( G L + G R ) 2 H L + H R + λ \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} HL+λGL2,HR+λGR2,HL+HR+λ(GL+GR)2
分别代表左子树、右子树和不分割时可以获得的分数, γ \gamma γ代表加入新叶子节点引入的代价
遍历所有分割,选择变化最大的作为最合适的分割;类似决策树中信息增益的作用;
XGBoost
案例需要先安装依赖:pip install xgboost
官方文档:XGBoost
官方: Github
实现步骤如下:
代码可见:08_使用XGBoost算法实现波士顿房价预测.py
Stacking
思想 \quad\quad 集成学习除了Bagging
、Boosting
思想,还有Stacking
,此处只提一下,不做具体介绍,因为现在基本不使用了。
\quad\quad Stacking
是指训练一个模型用于组合(combine)其它模型(基模型/基学习器)的技术。即首先训练出多个不同的模型,然后再以之前训练的各个模型的输出作为输入来新训练一个新的模型,从而得到一个最终的模型。一般情况下使用单层的Logistic
回归作为组合模型。
Stacking
跟现在比较火的深度学习很相似,所以现在一般不使用Stacking