標籤:

GBDT原理解析與手動實現

GBDT原理解析與手動實現

來自專欄 機器學習賺大錢

寫在前面:

GBDT與XGBoost在比賽中大放光芒,所以對其原理分析並手動不完美實現。

GBDT演算法的核心是回歸樹,學習時請忘記隨機森林,忘記決策樹(分類)!


在使用回歸做回歸時,難以避免在預測值與實際值之間產生誤差,GDBT主要是通過估算誤差,達到提升模型的泛化能力(預測能力,分類能力)。

y(i):對應第i個x的實際y值

yhat(i):對應第i個x的預測y值

L(y(i),yhat(i)):預測值與實際值之間的差異度,叫誤差。例如:做回歸時候,L()=y(i)-yhat(i),但並不是所有的誤差都是相減,例如在做概率預測時預測的概率就不能簡單的用做差來估算誤差。

下面以一個小例子來解釋GBDT在做什麼:

第一步:使用一個一層的回歸樹,根據最小方差(MSE)作為目標函數對其分類,後得到

第二步:計算誤差

第三步:這一步已經與前方沒用關係了,使用一個一層的回歸樹,根據最小方差(MSE)作為目標函數對其分類,後得到

最後的預測值是:

解釋:從上述過程發現,GBDT是通過不斷地預測誤差,將誤差與預測值加和,使得預測值接近真實值。GDBT不停的預測預測值與真實值間的誤差,被預測誤差的偏差(誤差),從而產生一顆顆縱向加深的樹,而隨機森林是橫向加寬的樹。


實際中,某些情況無法簡單計算出誤差。為解決這類問題的誤差,學者提出了一種新的方法。目標是使得L()=y(i)-yhat(i)最小,我們的目的並不是是為了求出L(),而且求出當yhat(i)為何值時L()最小,梯度下降演算法剛好符合這個要求。梯度下降演算法是通過改變自變數的值,使得因變數值最大或最小:

yhat[k+1] = yhat[k] - r* frac{partial L}{partial yhat}

注意了,這時的L()=y(i)-yhat(i)中,y(i)是常量、yhat(i)是自變數,與x等其他變數沒用關係,他們也不出現。

舉例:

這時我們假裝不知道他的殘差,用上訴提到的方法。回歸的損失函數是: L()=(y(i)-yhat(i))^{2}

對L()關於yhat求導得 L() =-2*(y(i)-yhat(i))

也就是說,其殘差變成了-2*(y(i)-yhat(i))

r我們直接取0.5

第一步:使用一個一層的回歸樹,根據最小方差(MSE)作為目標函數對其分類,後得到

第二步:計算誤差

帶入上述-2*(y(i)-yhat(i))*0.5公式

第三步:計算誤差的誤差

計算1000次的結果是:

我們發現越來越接近了


上文中,我們是直接給的學習率0.5

代碼如下:

import numpy as npfrom sklearn import tree from sklearn.tree import DecisionTreeRegressorfrom pylab import * if __name__ == __main__: X=[[1], [2], [3], [4], [5], [6], [7], [8], [9], [10]] Y=[5.56, 5.7, 5.91, 6.40, 6.8, 7.05, 8.9, 8.7, 9.0, 9.05] clf = DecisionTreeRegressor(max_depth=1) yhatL = Y r = Y result = np.zeros(len(X)) lr = 2.0*0.5 times = 1000 for i in range(times): clf = clf.fit(X, r) yhat = clf.predict(X) #count the loss r = lr*(yhatL - yhat) #ready loss for last DT yhatL = r #cout result result = result + yhat plot(1,result[0], . ) print(result) plot(1, 5.56, v)

但是,當我們給學習率變化時,取為 lr = 2.0*0.5*0.4

這時無法收斂到目標值,加大迭代次數也無法解決。

鄒博 - 計算機科學博士,深諳機器學習演算法原理

這是《機器學習升級版III》中「提升」章節的問題。

事實上,GBDT我恰好自己實現過一個版本,我當時第一版為了簡答,直接給定的固定學習率,發現是無法確保收斂的——後來分析了原因,因為不同的樹對於目標函數的降低影響不同,因此,這裡的每棵樹的權值是需要的。

如果有興趣,你也可以再實現嘗試下。

這裡提到學習率對其影響很大,這是因為不同的樹對於目標函數的降低影響不同造成的。所以學習率的設置需要一個好的方法,有些文章提到用ARAGrad演算法,還有提到線性搜索,在後續的文章中會給出具體代碼。

在SKlearn標準庫中,應該解決這個問題:

from sklearn.ensemble import GradientBoostingRegressorfrom pylab import * if __name__ == __main__: X=[[1], [2], [3], [4], [5], [6], [7], [8], [9], [10]] Y=[5.56, 5.7, 5.91, 6.40, 6.8, 7.05, 8.9, 8.7, 9.0, 9.05] times = 1000 for i in range(times): clf = GradientBoostingRegressor(n_estimators=(i+1), learning_rate=(1.0*2*0.2), max_depth=1, random_state=0).fit(X, Y) y = clf.predict(X) plot(1,y[0], . ) plot(1, 5.56, v)

結果:


推薦閱讀:

BAT機器學習面試1000題系列(286-290)
ML筆記 | 零基礎學懂機器學習(六)
GBM(Gradient Boosting Machine)的快速理解
GBDT的python源碼實現
即時配送的ETA問題之億級樣本特徵構造實踐

TAG:gbdt | 機器學習 |