adaboost与GBDT

adaboost

AdaBoost是最著名的Boosting族算法,是一种迭代算法,其核心思想是针对同一个训练集训练不同的分类器,即弱分类器,然后把这些弱分类器集合起来,构造一个更强的最终分类器。算法本身是改变数据分布实现的,它根据每次训练集之中的每个样本的分类是否正确,以及上次的总体分类的准确率,来确定每个样本的权值。将修改权值的新数据送给下层分类器进行训练,然后将每次训练得到的分类器融合起来,作为最后的决策分类器。

开始时,所有样本的权重相同,训练得到第一个基分类器。从第二轮开始,每轮开始前都先根据上一轮基分类器的分类效果调整每个样本的权重,上一轮分错的样本权重提高,分对的样本权重降低。之后根据新得到样本的权重指导本轮中的基分类器训练,即在考虑样本不同权重的情况下得到本轮错误率最低的基分类器。重复以上步骤直至训练到约定的轮数结束,每一轮训练得到一个基分类器。

可以想象到,远离边界(超平面)的样本点总是分类正确,而分类边界附近的样本点总是有大概率被弱分类器(基分类器)分错,所以权值会变高,即边界附近的样本点会在分类时得到更多的重视。

输入:训练数据集T={(x2,y2),(x1,y1),,(xn,yn)},xiXRn,yiY={1,+1};T= \begin{Bmatrix} (x_2,y_2),(x_1,y_1),……,(x_n,y_n)\end{Bmatrix},x_i\in X\subseteq R^n,y_i\in Y= \begin{Bmatrix}-1,+1\end{Bmatrix};

输出:最终分类器G(x)G(x)
步骤
(1) 初始化训练数据的权值分布D1=(w11,,w1i,,w1N),w1i=1N,i=1,2,,ND_1=(w_{11},……,w_{1i},……,w_{1N}),w_{1i}=\frac1N,i=1,2,……,N
(2) 对m=1,2,,Mm=1,2,……,M

  • 使用具有权值分布DmD_m的训练数据集学习,得到基本分类器Gm(x):x{1,+1}G_m(x):x\rightarrow \begin{Bmatrix}-1,+1\end{Bmatrix}
  • 计算Gm(x)G_m(x)在训练数据集上的分类误差率em=P(Gm(xi)yi)=i=1NwmiI(Gm(xi)yi)e_m=P(G_m(x_i)\neq y_i)=\sum_{i=1}^N w_{mi}I(G_m(x_i)\neq y_i)
  • 计算Gm(x)G_m(x)的系数αm=12log1emem\alpha_m=\frac12log\frac{1-e_m}{e_m}这里对数取自然对数。
  • 更新权值分布
    D1=(wm+1,1,,wm+1,i,,wm+1,N)D_1=(w_{m+1,1},……,w_{m+1,i},……,w_{m+1,N})
    wm+1,i=wmiZmexp(αmyiGm(xi)),i=1,2,,Nw_{m+1,i}=\frac{w_{mi}}{Z_m}exp(-\alpha_my_iG_m(x_i)),i=1,2,……,N

ZmZ_m是规范化因子,Zm=i=1Nwmiexp(αmyiGm(xi))Z_m=\sum_{i=1}^Nw_{mi}exp(-\alpha_my_iG_m(x_i)),它使Dm+1D_{m+1}成为一个概率分布。

(3) 构建基本分类器的线性组合,f(x)=m=1MαmGm(x)f(x)=\sum_{m=1}^M\alpha_mG_m(x)
得到最终分类器,G(x)=sign(f(x))=sign(m=1MαmGm(x))G(x)=sign(f(x))=sign(\sum_{m=1}^M\alpha_mG_m(x))

例子

我们用李航《统计学习方法》一个例子来看一下

x 0 1 2 3 4 5 6 7 8 9
y 1 1 1 -1 -1 -1 1 1 1 -1

数据集D共有10条数据,根据x的输入得到的y可以分为两类,即y=1与y=-1。我们每一轮使用最简单的决策树桩来构建基分类器,即每轮设定一个阈值θ,只要x<θ,就判定为正类(y=1),x>θ就判定为负类(y=-1)。(或者只要x<θ,就判定为正类(y=-1),x>θ就判定为负类(y=1))

第一轮

D1(x)D_1(x)
因为是第一轮,所有样本的权重相同为0.1(110\frac1{10})
D1(x)={110,110,110,110,110,110,110,110,110,110}D_1(\overline{x})=\begin{Bmatrix}\frac1{10},\frac1{10},\frac1{10},\frac1{10},\frac1{10},\frac1{10},\frac1{10},\frac1{10},\frac1{10},\frac1{10}\end{Bmatrix}

Θ\Theta
因为是离散数据,所以θ\theta可以依次取[0.5,1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5]来对x进行分类,有两种分类方法,
1、 x<θx<\theta时分为正类,x>θx>\theta时为负类
2、 x>θx>\theta时分为正类,x<θx<\theta时为负类

我们采用第一种方法,先类据一个例子,θ\theta取0.5时,x<0.5x<0.5时分为正类,此时只有一个正例,即全部分类正确,x>0.5x>0.5时为负类,此时有四个负例分类正确,5个正例分类错误,总共来看,有五个分类正确,有五个分类错误,即错误率为0.5;……

x=[0,1,2,3,4,5,6,7,8,9]
y=[1,1,1,-1,-1,-1,1,1,1,-1]

def err1(x,g):
    r=0#比值
    c=0#计数
    s=0#求和
    for i in range(len(x)):
        c=c+g[i]
        if x[i]<0:
            s=s+g[i]
        else:
            continue
            
    return c,s
def err2(x,g):
    r=0#比值
    c=0#计数
    s=0#求和
    for i in range(len(x)):
        c=c+g[i]
        if x[i]>0:
            s=s+g[i]
        else:
            continue
            
    return c,s

def err(x,y,g):
    m=[]
    for i in range(len(x)):
        R1=[]
        R2=[]
        c1=0
        c2=0
        R1=y[0:i+1]
        R2=y[i+1:len(y)]
        c1,s1=err1(R1,g)
        c2,s2=err2(R2,g)
        m.append(round((s1+s2)/(c1+c2),3))
    return m
    
err(x,y)  

[0.5, 0.4, 0.3, 0.4, 0.5, 0.6, 0.5, 0.4, 0.3]

得到e1e_1=[0.5, 0.4, 0.3, 0.4, 0.5, 0.6, 0.5, 0.4, 0.3]
最小值时0.3,即θ\theta取2.5时(或8.5)

第一层基分类器G1G_1的权重α1α_1

α1=1/2*log(1−ϵ1)/ϵ1=0.4236

def weight(e):
    return 1/2*np.log((1-e)/e)
    
def wm(x,y,g):
    wm=[]
    #k是最小错误率
    k=err(x,y,g).index(min(err(x,y,g)))
    #a权重系数
    a=weight(min(err(x,y,g)))
    for i in range(k+1):
        w=np.exp(-1*a*y[i]*1)*g[i]
        wm.append(round(w,4))
    for i in range(k+1,len(y)):
        w=np.exp(-1*a*y[i]*(-1))*g[i]
        wm.append(round(w,4))
    zm=round(np.sum(wm),4)
    wm=wm/zm
    return wm,zm,a,min(err(x,y,g))
第二轮

[0.07143636 0.07143636 0.07143636 0.07143636 0.07143636 0.07143636
0.16664849 0.16664849 0.16664849 0.07143636]

权重由全部是0.1变成上面的权重
下面就需要按照上面的矩阵来进行计算,这里就不一一进行计算了,需要注意的是这里是伪代码,并未写全,因为我们只看了对x进行分类时的第一种方法,其实是需要按照两种方法进行查看的
具体的原理运算过程可参考

最终结果入下:
sign(H(x))=sign(0.4236∗g1+0.6496∗g2+0.752∗g3)

这里进行简单的说明,前面的系数就是1/2log(1ϵ1)/ϵ11/2*log(1−ϵ1)/ϵ1
后面跟的是每次分类的方法,比如g1就是[1,1,1,-1,-1,-1,-1,-1,-1,-1],因为第一次我们取θ\theta取2.5时进行计算,即0,1,2三个位置小于0,而其他位置大于零,其他类似。

GBDT

GBDT(Gradient Boosting Decision Tree) 又叫 MART(Multiple Additive Regression Tree),是一种迭代的决策树算法,该算法由多棵决策树组成,所有树的结论累加起来做最终答案。它在被提出之初就和SVM一起被认为是泛化能力(generalization)较强的算法。近些年更因为被用于搜索排序的机器学习模型而引起大家关注。

而Gradient Boost与传统的Boost的区别是,每一次的计算是为了减少上一次的残差(residual),而为了消除残差,我们可以在残差减少的梯度(Gradient)方向上建立一个新的模型。所以说,在Gradient Boost中,每个新的模型的建立是为了使得之前模型的残差往梯度方向减少,与传统Boost对正确、错误的样本进行加权有着很大的区别。

输入:训练数据集T={(x2,y2),(x1,y1),,(xn,yn)},xiXRn,yiYR;T= \begin{Bmatrix} (x_2,y_2),(x_1,y_1),……,(x_n,y_n)\end{Bmatrix},x_i\in X\subseteq R^n,y_i\in Y\subseteq R;

输出:提升树fM(x)f_M(x)
步骤
(1) 初始化f0(x)=0f_0(x)=0
(2) 对m=1,2,,Mm=1,2,……,M

  • 计算残差rmi=yifm1(xi),i=1,2,,Nr_{mi}=y_i-f_{m-1}(x_i),i=1,2,……,N
  • 拟合残差rmir_{mi}学习一个回归树,得到T(x;Θm)T(x;\Theta_m)
  • 更新fm(x)=fm1(x)+T(x;Θm)f_m(x)=f_{m-1}(x)+T(x;\Theta_m)

(3) 得到回归问题提升树fM(x)=m=1MT(x;Θm)f_M(x)=\sum_{m=1}^MT(x;\Theta_m)

例子

我们用李航《统计学习方法》一个例子来看一下

x 1 2 3 4 5 6 7 8 9 10
y 5.56 5.7 5.91 6.4 6.8 7.05 8.9 8.7 9.0 9.05

我们看到x的取值范围是[0.5,10.5],y的取值范围[5.0,10.0]

按照我们上述的算法进行求解
第一步:求f1(x)f_1(x)即回归树T1(x)T_1(x)
首先求解优化问题:mins[minc1xiR1(yic1)2+minc2xiR2(yic2)2]\underbrace{min}_{s} \left[ \underbrace{min}_{c_1}\sum_{x_i\in R_1}(y_i-c_1)^2+ \underbrace{min}_{c_2}\sum_{x_i\in R_2}(y_i-c_2)^2\right]

求解训练数据的切分点s:R1={xxs},R2={xx>s}R_1=\begin{Bmatrix}x|x\leq s\end{Bmatrix}, R_2=\begin{Bmatrix}x|x> s\end{Bmatrix}
这里的切分点可以考虑「1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5,9.5」

我们也很容易得到在R1和R2内部使平方损失误差达到最小值的c1和c2为c1=1N1xiR1yi,c2=1N2xiR2yic_1=\frac1{N_1}\sum_{x_i\in R_1}y_i,c_2=\frac1{N_2}\sum_{x_i\in R_2}y_i

对于各个切分点,求出相应的R1,R2,c1,c2R_1,R_2,c_1,c_2以及m(s)=minc1xiR1(yic1)2+minc2xiR2(yic2)2m(s)=\underbrace{min}_{c_1}\sum_{x_i\in R_1}(y_i-c_1)^2+ \underbrace{min}_{c_2}\sum_{x_i\in R_2}(y_i-c_2)^2

我们python简易代码跑一下

x=[1,2,3,4,5,6,7,8,9,10]
y=[5.56,5.7,5.91,6.4,6.8,7.05,8.9,8.7,9.0,9.05]

def err(x):
    n=len(x)
    s=0
    avg=np.mean(x)
    for i in range(n):
        s=s+pow(x[i]-avg,2)
    return s
def m(x,y):
    m=[]
    for i in range(len(x)-1):
        R1=[]
        R2=[]
        c1=0
        c2=0
        R1=y[0:i+1]
        R2=y[i+1:len(y)]
        m1=err(R1)
        m2=err(R2)
        m.append(round(m1+m2,2))
    return m
m(x,y)

[15.72, 12.08, 8.37, 5.78, 3.91, 1.93, 8.01, 11.74, 15.74]

这里我们看到S=6.5时,残差值是最小的
这时R1=[1,2,3,4,5,6],R2=[7,8,9,10],c1=6.24,c2=8.91R_1=[1,2,3,4,5,6],R_2=[7,8,9,10],c_1=6.24,c_2=8.91

回归树T1(x)={6.24,x<6.58.91,x>=6.5T_1(x)=\begin{cases} 6.24, & \text {x<6.5}\\8.91, & \text {x>=6.5}\end{cases}
f1(x)=T1(x)f_1(x)=T_1(x)

f1(x)f_1(x)拟合训练数据集的残差,r2i=yif1(xi)r_{2i}=y_i-f_1(x_i)

x 1 2 3 4 5 6 7 8 9 10
r2ir_{2i} -0.68 -0.54 -0.33 0.16 0.56 0.81 -0.01 -0.21 0.09 0.14

第二步:
求回归树T2(x)T_2(x),与上面一样,不过现在需要拟合的是上表中的残差

m(x,r2)
#[1.42, 1.0, 0.79, 1.13, 1.66, 1.93, 1.93, 1.9, 1.91]

T2(x)={0.52,x<3.50.22,x>=3.5T_2(x)=\begin{cases} -0.52, & \text {x<3.5}\\0.22, & \text {x>=3.5}\end{cases}
f1(x)=T1(x)f_1(x)=T_1(x)
f2(x)=f1(x)+T2(x)={5.72,x<3.56.46,3.5 <= x<6.59.13,x>=6.5f_2(x)=f_1(x)+T_2(x)=\begin{cases} 5.72, & \text {x<3.5}\\6.46, & \text {3.5 <= x<6.5}\\9.13,& \text {x>=6.5}\end{cases}

总结

  • GBDT每一轮训练时所关注的重点是本轮产生结果的残差,下一轮以本轮残差作为输入,尽量去拟合这个残差,使下一轮输出的残差不断变小。所以GBDT可以做到每一轮一定向损失函数减小的梯度方向变化,而传统的boosting算法只能是尽量向梯度方向减小,这是GBDT与传统boosting算法最大的区别,这也是为什么GBDT相比传统boosting算法可以用更少的树个数与深度达到更好的效果。

  • 和AdaBoost一样,GradientBoosting也是重复选择一个表现一般的模型并且每次基于先前模型的表现进行调整。不同的是,AdaBoost是通过提升错分数据点的权重来定位模型的不足,而GBDT是通过算梯度来定位模型的不足。因此相比AdaBoost,GBDT可以使用更多种类的目标函数。

  • 抽象地说,模型的训练过程是对一任意可导目标函数的优化过程,通过反复地选择一个指向负梯度方向的函数,该算法可被看作在函数空间里对目标函数进行优化。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章