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*
注意了,這時的L()=y(i)-yhat(i)中,y(i)是常量、yhat(i)是自變數,與x等其他變數沒用關係,他們也不出現。
舉例:
這時我們假裝不知道他的殘差,用上訴提到的方法。回歸的損失函數是:
對L()關於yhat求導得
也就是說,其殘差變成了-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問題之億級樣本特徵構造實踐