集成学习(GBDT)

参考了统计学习方法,西瓜书,Machine Learnig with python做的总结,还包含自己用sklearn做的一些对比实验,原文是写在jupyter上的,这里是直接转为.md导过来的,所以格式有些问题,有些东西还待完善…
参考博客
https://www.cnblogs.com/pinard/p/6140514.html,
https://blog.csdn.net/qq_22238533/article/details/79185969

建议先看 决策树,回归树,随机森林,Adaboosting,boosting tree

(三) 梯度提升(gradient boosting decision tree)

当损失函数是平方损失和指数函数损失函数,每一步优化很简单,但对于一般的损失函数而言往往不易这就引入了梯度提升,利用最速下降法的近似方法,关键是使用损失函数的负梯度在当前模型的值

梯度提升树算法(GBDT)-回归算法

输入:训练数据集 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);损失函数 L ( y , f ( x ) ) L(y,f(x)) L(y,f(x));
输出:回归树 f ^ ( x ) \hat{f}(x) f^(x)
(1)初始化 f 0 ( x ) = a r g m i n c ∑ i = 1 N L ( y i , c ) f_0(x)=argmin_c\sum_{i=1}^NL(y_i,c) f0(x)=argminci=1NL(yi,c)

(2)对 m = 1 , 2 , . . . , M m=1,2,...,M m=1,2,...,M:
\quad\quad a.对 i = 1 , 2 , . . . , N i=1,2,...,N i=1,2,...,N计算 r m i = − [ ∂ L ( y i , f ( x i ) ) ∂ f ( x i ) ] f ( x ) = f m − 1 ( x ) r_{mi}=-[\frac{\partial L(y_i,f(x_i)) }{\partial f(x_i) }]_{f(x)=f_{m-1}(x)} rmi=[f(xi)L(yi,f(xi))]f(x)=fm1(x)
\quad\quad b.对新数据集 ( x i , r m i ) (x_i,r_{mi}) (xi,rmi)拟合一个CART回归树,注意里标签值是 r m i r_{mi} rmi,得到第 m m m棵树的叶节点区域 R m j , j = 1 , 2 , . . , J R_{mj},j=1,2,..,J Rmj,j=1,2,..,J
\quad\quad c.对 j = 1 , 2 , . . . , J j=1,2,...,J j=1,2,...,J,计算 c m j = a r g m i n c ∑ x i ∈ R m j L ( y i , f m − 1 ( x i ) + c ) ( C A R T 回 归 树 中 是 各 个 区 域 标 签 均 值 ) c_{mj}=argmin_c \sum_{x_i\in R_{mj}}L(y_i,f_{m-1}(x_i)+c)(CART回归树中是各个区域标签均值) cmj=argmincxiRmjL(yi,fm1(xi)+c)CART
\quad\quad 得到回归树 T m = ∑ m = 1 J c m j I ( x ∈ R m j ) T_{m}=\sum_{m=1}^Jc_{mj}I(x\in R_{mj}) Tm=m=1JcmjI(xRmj)
\quad\quad d.更新 f m ( x ) = f m − 1 ( x ) + ∑ j = 1 J c m j I ( x ∈ R m j ) f_m(x)=f_{m-1}(x)+\sum_{j=1}^Jc_{mj}I(x\in R_{mj}) fm(x)=fm1(x)+j=1JcmjI(xRmj)
(3)得到回归树 f ^ ( x ) = f M ( x ) = ∑ m = 1 M ∑ j = 1 J c m j I ( x ∈ R m j ) \hat{f}(x)=f_M(x)=\sum_{m=1}^M\sum_{j=1}^Jc_{mj}I(x\in R_{mj}) f^(x)=fM(x)=m=1Mj=1JcmjI(xRmj)
注意:
1.算法第一步初始化,估计使损失函数极小化的常数值,它是只有根节点的树
2.第2(a)步中计算损失函数的负梯度在当前模型的值,将它作为残差估计,对于平方损失函数,它就是通常所说的残差,对于一般损失函数,它就是残差近似值
3.第2(b)步估计回归树叶节点区域,以拟合残差近似值
4.第2©步利用线性搜索估计叶节点区域的值,使损失函数极小化

例子
import pandas as pd
import numpy as np
data0={"x":[1,2,3,4,5,6,7,8,9,10],
     "y":[5.56,5.70,5.91,6.40,6.80,7.05,8.90,8.70,9.00,9.05]}#来自统计学习方法
data0=pd.DataFrame(data0)
data0
xy
015.56
125.70
235.91
346.40
456.80
567.05
678.90
788.70
899.00
9109.05

现在我们来计算其GBRT模型,选取的最小化整体损失函数是 ∑ i = 1 N ( y i − f ( x i ) ) 2 \sum_{i=1}^N(y_i-f(x_i))^2 i=1N(yif(xi))2,其单个样本损失函数为 ( y i − f ( x i ) ) 2 (y_i-f(x_i))^2 (yif(xi))2梯度为 − [ ∂ L ( y i , f ( x i ) ) ∂ f ( x i ) ] = 2 ( y i − f ( x i ) ) -[\frac{\partial L(y_i,f(x_i))}{\partial f(x_i)}]=2(y_i-f(x_i)) [f(xi)L(yi,f(xi))]=2(yif(xi))这里直接使用 y i − f ( x i ) y_i-f(x_i) yif(xi)

第一步先求 f 0 ( x ) f_0(x) f0(x)即回归树 T 0 ( x ) T_0(x) T0(x),也就是求 f ( x ) = a r g m i n c 0 ∑ i = 0 9 ( y i − c 0 ) 2 f(x)=argmin_{c_0} \sum_{i=0}^9(y_i-c_0)^2 f(x)=argminc0i=09(yic0)2,对此式求导可得 c 0 = ∑ i = 0 N y i N c_0=\frac{\sum_{i=0}^Ny_i}{N} c0=Ni=0Nyi

data_y=data0["y"]
data_L0=[]
c_0=np.sum(data0["y"])/len(data0)
print(c_0)
data_L0.append(np.sum((data_y-c_0)**2))
print(data_L0)
7.307
[19.114210000000003]

根据上面计算当我们选取 f 0 ( x ) = 7.05 f_0(x)=7.05 f0(x)=7.05,损失函数有最小值

第二步根据第2a步求出残差表

f_0=7.307
data1={"x":[1,2,3,4,5,6,7,8,9,10],
     "r":list(data0["y"]-f_0)}
data1=pd.DataFrame(data1)
data1
xr
01-1.747
12-1.607
23-1.397
34-0.907
45-0.507
56-0.257
671.593
781.393
891.693
9101.743

第三步对残差进行拟合回归树(见CART回归树的建立):
首先计算搜索最优切分特征和最优切分点,由于特征就一个所以就是 x x x,现在搜索最优切分点

data_L1=[]
C11=[]
C12=[]
# S=[(data1["x"][i]+data1["x"][i+1])/2 for i in  range(len(data1["x"])-1)]#备选切分点,这里用的是x间隔均值
# print(S)
# for s in S:
#     sum=0
#     c1=[]
#     c2=[]
#     for x,r in zip(data1["x"],data1["r"]):
#         if x<=s:
#             c1.append(r)
#         else:
#             c2.append(r)
#     c1=np.mean(c1)
#     c2=np.mean(c2)
#     for x,r in zip(data1["x"],data1["r"]):
#         if x<=s:
#             sum+=(r-c1)**2
#         else:
#             sum+=(r-c2)**2
#     data_L1.append(sum)

##直接选取x作为备选切分点
for s in data1["x"]:
    sum=0
    c11=[]
    c12=[]
    for x,r in zip(data1["x"],data1["r"]):
        if x<=s:
            c11.append(r)
        else:
            c12.append(r)
    c11=np.mean(c1)
    c12=np.mean(c2)
    C11.append(c1)
    C12.append(c2)
    for x,r in zip(data1["x"],data1["r"]):
        if x<=s:
            sum+=(r-c11)**2
        else:
            sum+=(r-c12)**2
    data_L1.append(sum)
print(data_L1)
print("c11:",C11[5])
print("c12:",C12[5])
[15.723088888888887, 12.0833875, 8.365638095238095, 5.775475000000003, 3.9113200000000017, 1.9300083333333335, 8.009809523809526, 11.735399999999997, 15.738599999999998, 19.11421]
c1: -1.0703333333333338
c2: 1.6054999999999997

可以得知最优切分点是 x = 6 x=6 x=6,个各区域输出值为 c 11 = − 1.0703 , c 12 = 1.6055 c_{11}=-1.0703,c_{12}=1.6055 c11=1.0703,c12=1.6055,所以我们可以得到回归树 f 1 ( x i ) = 7.307 + ∑ k = 1 2 c 1 k I ( x i ∈ R 1 k ) f_1(x_i)=7.307+\sum_{k=1}^2c_{1k}I(x_i\in R_{1k}) f1(xi)=7.307+k=12c1kI(xiR1k)

第一轮迭代已经完成

进行第二轮迭代,首先还是计算新的需要拟合的数据

def F1(x):
    if x<=6:
        return 7.307-1.0703
    else:
        return 7.307+1.6055

求新残差表

data2={"x":[1,2,3,4,5,6,7,8,9,10],
     "r":[data0["y"][i]-F1(data0["x"][i]) for i in range(10)]}
data2=pd.DataFrame(data2)
data2
xr
01-0.6767
12-0.5367
23-0.3267
340.1633
450.5633
560.8133
67-0.0125
78-0.2125
890.0875
9100.1375

第三步对残差进行拟合回归树(见CART回归树的建立):
首先计算搜索最优切分特征和最优切分点,由于特征就一个所以就是?,现在搜索最优切分点

data_L2=[]
C21=[]
C22=[]
for s in data2["x"]:
    sum=0
    c21=[]
    c22=[]
    for x,r in zip(data2["x"],data2["r"]):
        if x<=s:
            c21.append(r)
        else:
            c22.append(r)
    c21=np.mean(c21)
    c22=np.mean(c22)
    C21.append(c21)
    C22.append(c22)
    for x,r in zip(data2["x"],data2["r"]):
        if x<=s:
            sum+=(r-c21)**2
        else:
            sum+=(r-c22)**2
    data_L2.append(sum)
print(data_L2)
print("c21:",C21[2])
print("c22:",C22[2])
[1.421235199999999, 1.0098567799999985, 0.8006163352380933, 1.1402758533333317, 1.665360511999999, 1.930008333333334, 1.9299332152380952, 1.89835646, 1.9089952799999999, 1.9300083360000004]
c21: -0.5133666666666675
c22: 0.2199857142857142

可以得知最优切分点是 x = 3 x=3 x=3,个各区域输出值为 c 21 = − 0.5134 , c 22 = 0.22 c_{21}=-0.5134,c_{22}=0.22 c21=0.5134,c22=0.22,所以我们可以得到回归树 f 2 ( x i ) = 7.307 + ∑ k = 1 2 c 1 k I ( x i ∈ R 1 k ) + ∑ k = 1 2 c 2 k I ( x i ∈ R 2 k ) f_2(x_i)=7.307+\sum_{k=1}^2c_{1k}I(x_i\in R_1k)+\sum_{k=1}^2c_{2k}I(x_i\in R_{2k}) f2(xi)=7.307+k=12c1kI(xiR1k)+k=12c2kI(xiR2k)

进行第三轮迭代,首先还是计算新的需要拟合的数据

def F2(x):
    f1=F1(x)
    if x<=3:
        return f1-0.5134
    else:
        return f1+0.22
    

求新残差表

data3={"x":[1,2,3,4,5,6,7,8,9,10],
     "r":[data0["y"][i]-F2(data0["x"][i]) for i in range(10)]}
data3=pd.DataFrame(data3)
data3
xr
01-0.1633
12-0.0233
230.1867
34-0.0567
450.3433
560.5933
67-0.2325
78-0.4325
89-0.1325
910-0.0825

第三步对残差进行拟合回归树(见CART回归树的建立):
首先计算搜索最优切分特征和最优切分点,由于特征就一个所以就是?,现在搜索最优切分点

data_L3=[]
C31=[]
C32=[]
for s in data3["x"]:
    sum=0
    c31=[]
    c32=[]
    for x,r in zip(data3["x"],data3["r"]):
        if x<=s:
            c31.append(r)
        else:
            c32.append(r)
    c31=np.mean(c31)
    c32=np.mean(c32)
    C31.append(c31)
    C32.append(c32)
    for x,r in zip(data3["x"],data3["r"]):
        if x<=s:
            sum+=(r-c31)**2
        else:
            sum+=(r-c32)**2
    data_L3.append(sum)
print(data_L3)
print("c31:",C31[5])
print("c32:",C32[5])
[0.7709864622222217, 0.7788541149999993, 0.8006163352380948, 0.7992815233333329, 0.767737584, 0.47794967333333394, 0.6009705066666668, 0.771725715, 0.7930538399999999, 0.8006163399999996]
c31: 0.14666666666666592
c32: -0.2200000000000002

可以得知最优切分点是 x = 6 x=6 x=6,个各区域输出值为 c 31 = 0.1467 , c 32 = − 0.22 c_{31}=0.1467,c_{32}=-0.22 c31=0.1467,c32=0.22,所以我们可以得到回归树 f 3 ( x i ) = 7.307 + ∑ k = 1 2 c 1 k I ( x i ∈ R 1 k ) + ∑ k = 1 2 c 2 k I ( x i ∈ R 2 k ) + ∑ k = 1 2 c 3 k I ( x i ∈ R 3 k ) f_3(x_i)=7.307+\sum_{k=1}^2c_{1k}I(x_i\in R_1k)+\sum_{k=1}^2c_{2k}I(x_i\in R_{2k})+\sum_{k=1}^2c_{3k}I(x_i\in R_{3k}) f3(xi)=7.307+k=12c1kI(xiR1k)+k=12c2kI(xiR2k)+k=12c3kI(xiR3k)

这样继续迭代下去直至满足停止条件

梯度提升树算法-分类

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

梯度提升树算法(GBDT)-二分类

对于二元分类GBDT,这里使用类似于逻辑回归的对数似然损失函数,则单样本损失函数为: L ( y , f ( x ) ) = − l o g P ( Y = y ∣ x ) = l o g ( 1 + e x p ( − y f ( x ) ) ) ( 1 ) L(y,f(x))=-logP(Y=y|x)=log(1+exp(-yf(x))) (1) L(y,f(x))=logP(Y=yx)=log(1+exp(yf(x)))(1)

这个损失函数这么来的:
对于 x i x_i xi,其标签是 y i y_i yi,那么我们当然希望模型判断 x i x_i xi y i y_i yi的概率 P ( Y = y i ∣ x i ) P(Y=y_i|x_i) P(Y=yixi)越大越好,也就是希望 − P ( Y = y i ∣ x i ) -P(Y=y_i|x_i) P(Y=yixi)越小越好。在二分类中 y ∈ { − 1 , + 1 } y\in \{-1,+1\} y{1,+1} P ( Y = y ∣ x ) = e x p ( y f ( x ) ) 1 + e x p ( y f ( x ) ) P(Y=y|x)=\frac{exp(yf(x))}{1+exp(yf(x))} P(Y=yx)=1+exp(yf(x))exp(yf(x))所以有:
P ( Y = 1 ∣ x ) = e x p ( f ( x ) ) 1 + e x p ( f ( x ) ) P(Y=1|x)=\frac{exp(f(x))}{1+exp(f(x))} P(Y=1x)=1+exp(f(x))exp(f(x)) P ( Y = − 1 ∣ x ) = 1 − P ( Y = 1 ∣ x ) = e x p ( − f ( x ) ) 1 + e x p ( − f ( x ) ) = 1 1 + e x p ( f ( x ) ) P(Y=-1|x)=1-P(Y=1|x)=\frac{exp(-f(x))}{1+exp(-f(x))}=\frac{1}{1+exp(f(x))} P(Y=1x)=1P(Y=1x)=1+exp(f(x))exp(f(x))=1+exp(f(x))1.

所以可以得到 L ( y , f ( x ) ) = − l o g P ( Y = y ∣ x ) = − l o g ( e x p ( y f ( x ) ) 1 + e x p ( y f ( x ) ) ) = l o g ( 1 + e x p ( y f ( x ) ) e x p ( y f ( x ) ) ) L(y,f(x))=-logP(Y=y|x)=-log(\frac{exp(yf(x))}{1+exp(yf(x))})=log(\frac{1+exp(yf(x))}{exp(yf(x))}) L(y,f(x))=logP(Y=yx)=log(1+exp(yf(x))exp(yf(x)))=log(exp(yf(x))1+exp(yf(x))) = l o g ( 1 + e x p ( − y f ( x ) ) ) =log(1+exp(-yf(x))) =log(1+exp(yf(x)))这就是式(1)

则此时的负梯度误差为 r m i = − [ ∂ L ( y , f ( x i ) ) ∂ f ( x i ) ] f ( x ) = f m − 1 ( x ) = y i 1 + e x p ( y i f ( x i ) ) r_{mi}=-[\frac{\partial L(y,f(x_i))}{\partial f(x_i)}]_{f(x)=f_{m-1}(x)}=\frac{y_i}{1+exp(y_if(x_i))} rmi=[f(xi)L(y,f(xi))]f(x)=fm1(x)=1+exp(yif(xi))yi

对于生成的决策树,各个叶子节点的最佳负梯度拟合值为 c m k = a r g m i n c ∑ x i ∈ R m k l o g ( 1 + e x p ( − y i ( f t − 1 ( x i ) + c ) ) ) c_{mk}=argmin_c\sum_{x_i\in R_{mk}}log(1+exp(-y_i(f_{t-1}(x_i)+c))) cmk=argmincxiRmklog(1+exp(yi(ft1(xi)+c)))

上式难解,一般使用近似值代替 c m k = ∑ x i ∈ R m k r m i ∑ x i ∈ R m i ∣ r m k ∣ ( 1 − ∣ r m k ∣ ) c_{mk}=\frac{\sum_{x_i\in R_{mk}}r_{mi}}{\sum_{x_i\in R_{mi}}}|r_{mk}|(1-|r_{mk}|) cmk=xiRmixiRmkrmirmk(1rmk)

也就是除了负梯度计算和叶子结点的最佳负梯度拟合,二元GBDT分类同GBDT回归算法过程相同

注意

在上面推导中若 y ∈ { 1 , 0 } y\in \{1,0\} y{1,0},则单样本损失函数可以写成逻辑回归的对数似然函数 L ( y , f ( x ) ) = y l o g ( P ( Y = 1 ∣ x ) ) + ( 1 − y ) l o g ( 1 − P ( Y = 1 ∣ x ) ) L(y,f(x))=ylog(P(Y=1|x))+(1-y)log(1-P(Y=1|x)) L(y,f(x))=ylog(P(Y=1x))+(1y)log(1P(Y=1x))

其中 P ( Y = 1 ∣ x ) = e x p ( f ( x ) ) 1 + e x p ( f ( x ) ) P(Y=1|x)=\frac{exp(f(x))}{1+exp(f(x))} P(Y=1x)=1+exp(f(x))exp(f(x)) P ( Y = 0 ∣ x ) = 1 − P ( Y = 1 ∣ x ) = 1 1 + e x p ( f ( x ) ) P(Y=0|x)=1-P(Y=1|x)=\frac{1}{1+exp(f(x))} P(Y=0x)=1P(Y=1x)=1+exp(f(x))1.就不能写为 P ( Y = y ∣ x ) = e x p ( y f ( x ) ) 1 + e x p ( y f ( x ) ) P(Y=y|x)=\frac{exp(yf(x))}{1+exp(yf(x))} P(Y=yx)=1+exp(yf(x))exp(yf(x))的合体形式

梯度提升树算法(GBDT)-多分类

注意:
1.对于多分类任务,GDBT的做法是采用一对多的策略,即,对每个类别训练 M M M个分类器。假设有 K K K个类别,那么训练完之后总共有 M × K M\times K M×K颗树。
2. K K K个类别都拟合完第一颗树之后才开始拟合第二颗树,不允许先把某一个类别的M颗树学习完,再学习另外一个类别

对于多元分类,我们假设有 K K K类,则此时的单样本对数似然损失函数函数 L ( y , f ( x ) ) = − ∑ k = 1 K y k l o g ( P ( Y = k ∣ x ) ) L(y,f(x))=-\sum_{k=1}^Ky_klog(P(Y=k|x)) L(y,f(x))=k=1Kyklog(P(Y=kx))

整体的就是 L ( y , f ( x ) ) = − ∑ i = 1 N y i l o g ( P ( Y = y i ∣ x i ) ) L(y,f(x))=-\sum_{i=1}^Ny_ilog(P(Y=y_i|x_i)) L(y,f(x))=i=1Nyilog(P(Y=yixi))

其中如若模型对样本 x x x输出类别为 y k y_k yk y k = 1 y_k=1 yk=1,否则 y k = 0 y_k=0 yk=0,也就是实际上只算了其标签类别对应的预测值得损失函数 P ( Y = k ∣ x ) = e x p ( f k ( x ) ) ∑ l = 1 K e x p ( f l ( x ) ) P(Y=k|x)=\frac{exp(f_k(x))}{\sum_{l=1}^Kexp(f_l(x))} P(Y=kx)=l=1Kexp(fl(x))exp(fk(x))

也就是实际上模型输出的是一个K维向量,表示样例属于各个类别的相对可能性,然后通过上式进行归一化处理.

此时,在第 m m m轮迭代,第 i i i个样本对应类别 l l l的负梯度误差是 r m i l = − [ ∂ L ( y , f ( x i ) ) ∂ f ( x i ) ] f ( x ) = f m − 1 l ( x ) = y i l − P ( Y = l ∣ x ) r_{mil}=-[\frac{\partial L(y,f(x_i))}{\partial f(x_i)}]_{f(x)=f_{m-1}l(x)}=y_{il}-P(Y=l|x) rmil=[f(xi)L(y,f(xi))]f(x)=fm1l(x)=yilP(Y=lx)

对于各个类别生成的决策树,各个叶子节点的最佳负梯度拟合值为 c m l k = a r g m i n c ∑ x i ∈ R m l k L ( l , f m − 1 , l ( x ) + c ) c_{mlk}=argmin_{c}\sum_{x_i\in R_mlk}L(l,f_{m-1,l}(x)+c) cmlk=argmincxiRmlkL(l,fm1,l(x)+c) c m l k c_{mlk} cmlk就表示 l l l类别的第 m m m轮迭代的决策树的第 k k k个分区的拟合值.

由于上式难优化,所以用近似值代替 c m l k = K − 1 K ∑ x i ∈ R m l k r m l k ∑ x i ∈ R m l k ∣ r m l k ∣ ( 1 − ∣ r m l k ∣ ) c_{mlk}=\frac{K-1}{K}\frac{\sum_{x_i\in R_{mlk}}r_{mlk}} {\sum_{x_i\in R_{mlk}}|r_{mlk}|(1-|r_{mlk}|)} cmlk=KK1xiRmlkrmlk(1rmlk)xiRmlkrmlk这里K表示类别数

那么就可以得到 l l l类别第 m m m轮迭代的决策树 T m l = ∑ i = 1 N c m l k I ( x i ∈ R m l k ) T_{ml}=\sum_{i=1}^Nc_{mlk}I(x_i\in R_{mlk}) Tml=i=1NcmlkI(xiRmlk)

那么当所有类别的第 m m m轮迭代分类器都生成了之后再继续下一轮迭代

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值