當前位置:
首頁 > 知識 > GBDT回歸的原理及Python實現

GBDT回歸的原理及Python實現


程序員大咖

點擊右側關注,免費進階高級!





作者:

李小文


Github: https://gith

ub.com/tushu

shu


提到GBDT回歸相信大家應該都不會覺得陌生,本文就GBDT回歸的基本原理進行講解,並手把手、肩並肩地帶您實現這一演算法。完整實現代碼請參考本人的github。

一、原理篇


我們用人話而不是大段的數學公式來講講GBDT回歸是怎麼一回事。


1.1 溫故知新


回歸樹是GBDT的基礎,之前的一篇文章曾經講過回歸樹的原理和實現。鏈接如下:


回歸樹的原理及Python實現


1.2 預測年齡


仍然以預測同事年齡來舉例,從《回歸樹》那篇文章中我們可以知道,如果需要通過一個常量來預測同事的年齡,平均值是最佳選擇之一。


1.3 年齡的殘差


我們不妨假設同事的年齡分別為5歲、6歲、7歲,那麼同事的平均年齡就是6歲。所以我們用6歲這個常量來預測同事的年齡,即[6, 6, 6]。每個同事年齡的殘差 = 年齡 - 預測值 = [5, 6, 7] - [6, 6, 6],所以殘差為[-1, 0, 1]


1.4 預測年齡的殘差


為了讓模型更加準確,其中一個思路是讓殘差變小。如何減少殘差呢?我們不妨對殘差建立一顆回歸樹,然後預測出準確的殘差。假設這棵樹預測的殘差是[-0.9, 0, 0.9],將上一輪的預測值和這一輪的預測值求和,每個同事的年齡 = [6, 6, 6] + [-0.9, 0, 0.9] = [5.1, 6, 6.9],顯然與真實值[5, 6, 7]更加接近了, 年齡的殘差此時變為[-0.1, 0, 0.1],預測的準確性得到了提升。


1.5 GBDT

重新整理一下思路,假設我們的預測一共迭代3輪 年齡:[5, 6, 7]


第1輪預測:6, 6, 6


第1輪殘差:[-1, 0, 1]


第2輪預測:6, 6, 6 + -0.9, 0, 0.9 = [5.1, 6, 6.9]


第2輪殘差:[-0.1, 0, 0.1]

第3輪預測:6, 6, 6 + -0.9, 0, 0.9 + -0.08, 0, 0.07 = [5.02, 6, 6.97]


第3輪殘差:[-0.08, 0, 0.03]


看上去殘差越來越小,而這種預測方式就是GBDT演算法。


1.6 公式推導


看到這裡,相信您對GBDT已經有了直觀的認識。這麼做有什麼科學依據么,為什麼殘差可以越來越小呢?前方小段數學公式低能預警。


因此,我們需要通過用第m-1輪殘差的均值來得到函數fm,進而優化函數Fm。而回歸樹的原理就是通過最佳劃分區域的均值來進行預測。所以fm可以選用回歸樹作為基礎模型,將初始值,m-1顆回歸樹的預測值相加便可以預測y。


二、實現篇


本人用全宇宙最簡單的編程語言——Python實現了GBDT回歸演算法,沒有依賴任何第三方庫,便於學習和使用。簡單說明一下實現過程,更詳細的注釋請參考本人github上的代碼。


2.1 導入回歸樹類


回歸樹是我之前已經寫好的一個類,在之前的文章詳細介紹過,代碼請參考:

https:

/

/github.com/tushushu/imylu/blob/master/imylu/tree/regression

_tree.py


from

 ..tree.regression_tree 

import

 RegressionTree

2.2 創建GradientBoostingBase類


初始化,存儲回歸樹、學習率、初始預測值和變換函數。(註:回歸不需要做變換,因此函數的返回值等於參數)

class

 

GradientBoostingBase(object)

:


    

def

 

__init__(self)

:


        self.trees = 

None


        self.lr = 

None


        self.init_val = 

None


        self.fn = 

lambda

 x: x

2.3 計算初始預測值


初始預測值即y的平均值。

def

 

_get_init_val(

self

, y)

:
    

return

 sum(y) / len(y)

2.4 計算殘差

def

 

_get_residuals

(

self

, y, y_hat)

:
    

return

 [yi - 

self

.fn(y_hat_i) 

for

 yi, y_hat_i 

in

 zip(y, y_hat)]

2.5 訓練模型



訓練模型的時候需要注意以下幾點: 1. 控制樹的最大深度max_depth; 2. 控制分裂時最少的樣本量min_samples_split; 3. 訓練每一棵回歸樹的時候要乘以一個學習率lr,防止模型過擬合; 4. 對樣本進行抽樣的時候要採用有放回的抽樣方式。

def

 

fit(

self

, X, y, n_estimators, lr, max_depth, min_samples_split, subsample=None)

:
    

self

.init_val = 

self

._get_init_val(y)

    n = len(y)
    y_hat = [

self

.init_val] * n
    residuals = 

self

._get_residuals(y, y_hat)

    

self

.trees = []
    

self

.lr = lr
    

for

 

_

 

in

 range(n_estimators):
        idx = range(n)
        

if

 subsample is 

not

 

None:


            k = int(subsample * n)
            idx = choices(population=idx, k=k)
        X_sub = [X[i] 

for

 i 

in

 idx]
        residuals_sub = [residuals[i] 

for

 i 

in

 idx]
        y_hat_sub = [y_hat[i] 

for

 i 

in

 idx]

        tree = RegressionTree()
        tree.fit(X_sub, residuals_sub, max_depth, min_samples_split)

        

self

._update_score(tree, X_sub, y_hat_sub, residuals_sub)

        y_hat = [y_hat_i + lr * res_hat_i 

for

 y_hat_i,
                    res_hat_i 

in

 zip(y_hat, tree.predict(X))]

        residuals = 

self

._get_residuals(y, y_hat)
        

self

.trees.append(tree)

2.6 預測一個樣本

def

 

_predict(

self

, Xi)

:
    

return

 

self

.fn(

self

.init_val + sum(

self

.lr * tree._predict(Xi) 

for

 tree 

in

 

self

.trees))

2.7 預測多個樣本

def

 

predict(

self

, X)

:
    

return

 [

self

._predict(Xi) 

for

 Xi 

in

 X]

三、效果評估


3.1 main函數


使用著名的波士頓房價數據集,按照7:3的比例拆分為訓練集和測試集,訓練模型,並統計準確度。

@run_time


def

 

main()

:


    print(

"Tesing the accuracy of GBDT regressor..."

)

    X, y = load_boston_house_prices()

    X_train, X_test, y_train, y_test = train_test_split(
        X, y, random_state=

10

)

    reg = GradientBoostingRegressor()
    reg.fit(X=X_train, y=y_train, n_estimators=

4

,
            lr=

0.5

, max_depth=

2

, min_samples_split=

2

)

    get_r2(reg, X_test, y_test)

3.2 效果展示


最終擬合優度0.851,運行時間5.0秒,效果還算不錯~


3.3 工具函數


本人自定義了一些工具函數,可以在github上查看

https:

//github.com/tushushu/imylu/blob/master/imylu/utils.py





  1. run_time - 測試函數運行時間



  2. load_boston_house_prices - 載入波士頓房價數據



  3. train_test_split - 拆分訓練集、測試集



  4. get_r2 - 計算擬合優度


四、總結


GBDT回歸的原理:平均值加回歸樹


GBDT回歸的實現:加加減減for循環 


【點擊成為源碼大神】

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 Python開發 的精彩文章:

呀!抓個正著!!
Python爬蟲 --- 1.3 BS4庫的解析器

TAG:Python開發 |