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可以使用更多種類的目標函數。

  • 抽象地說,模型的訓練過程是對一任意可導目標函數的優化過程,通過反覆地選擇一個指向負梯度方向的函數,該算法可被看作在函數空間裏對目標函數進行優化。

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