提到GBDT迴歸相信大家應該都不會覺得陌生(不陌生你點進來幹嘛[捂臉]),本文就GBDT迴歸的基本原理進行講解,並手把手、肩並肩地帶您實現這一演算法。

完整實現程式碼請參考本人的p。。。哦不是。。。github:

1。 原理篇

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

1。1 溫故知新

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

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] (第1顆迴歸樹) = [5。1, 6, 6。9]

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

第3輪預測:[6, 6, 6] (平均值) + [-0。9, 0, 0。9] (第1顆迴歸樹) + [-0。08, 0, 0。07] (第2顆迴歸樹) = [5。02, 6, 6。97]

第3輪殘差:[-0。08, 0, 0。03]

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

1。6 公式推導

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

假設要做m輪預測,預測函式為Fm,初始常量或每一輪的迴歸樹為fm,輸入變數為X,有:

F_m(X) = F_{m-1}(X) + f_m(X)

設要預測的變數為y,採用MSE作為損失函式:

Loss(y, F_m(X)) = \Large\frac{1}{n}\normalsize\sum_{i=0}^n((y_i - F_m(x_i)) ^ 2)

我們知道泰勒公式的一階展開式是長成這個樣子滴:

f(x + x_0) = f(x) + f

如果:

f(x) = g

那麼,根據式3和式4可以得出:

g

根據式2可以知道,損失函式的一階偏導數為:

Loss

根據式6可以知道,損失函式的二階偏導數為:

Loss

蓄力結束,開始放大招。根據式1,損失函式的一階導數為:

Loss

根據式5,將式8進一步展開為:

Loss

令式9,即損失函式的一階導數為0,那麼:

f_m(X) = - Loss

將式6,式7代入式9得到:

f_m(X) = \Large\frac{1}{n}\normalsize\sum_{i=0}^n(y_i - F_{m-1}(x_i))

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

2。 實現篇

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

2。1 匯入迴歸樹類

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

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 效果評估

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秒,效果還算不錯~

GBDT迴歸的原理及Python實現

3。3 工具函式

本人自定義了一些工具函式,可以在github上檢視

1。 run_time - 測試函式執行時間

2。 load_boston_house_prices - 載入波士頓房價資料

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

4。 get_r2 - 計算擬合優度

總結

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

GBDT迴歸的實現:加加減減for迴圈