摘要:從以上過程中可知,除了由損失函數引起的負梯度計算和葉子節點的最佳殘差擬合值的計算不同,二元GBDT分類和GBDT迴歸算法過程基本相似。二元GBDT分類算法和邏輯迴歸思想一樣,用一系列的梯度提升樹去擬合這個對數幾率,其分類模型可以表達爲:。

目錄:

  1. GBDT分類算法簡介

  2. GBDT二分類算法

  • 2.1 邏輯迴歸的對數損失函數

  • 2.2 GBDT二分類原理

  • GBDT二分類算法實例

  • 手撕GBDT二分類算法

    • 4.1 用Python3實現GBDT二分類算法

    • 4.2 用sklearn實現GBDT二分類算法

  • GBDT分類任務常見的損失函數

  • 總結

  • Reference

  • 本文的主要內容概覽:

    1. GBDT分類算法簡介

    GBDT無論用於分類還是迴歸,一直使用的是CART迴歸樹。GBDT不會因爲我們所選擇的任務是分類任務就選用分類樹,這裏的核心原因是GBDT每輪的訓練是在上一輪訓練模型的負梯度值基礎之上訓練的。這就要求每輪迭代的時候,真實標籤減去弱分類器的輸出結果是有意義的,即殘差是有意義的。如果選用的弱分類器是分類樹,類別相減是沒有意義的。對於這樣的問題,可以採用兩種方法來解決:

    • 採用指數損失函數,這樣GBDT就退化成了Adaboost,能夠解決分類的問題;

    • 使用類似於邏輯迴歸的對數似然損失函數,如此可以通過結果的概率值與真實概率值的差距當做殘差來擬合;

    下面我們就通過二分類問題,去看看GBDT究竟是如何做分類的。

    2. GBDT二分類算法

    2.1 邏輯迴歸的對數損失函數

    邏輯迴歸的預測函數爲:

    函數的值有特殊的含義,它表示結果取 的概率,因此對於輸入 分類結果爲類別 和類別 的概率分別爲:

    下面我們根據上式,推導出邏輯迴歸的對數損失函數。上式綜合起來可以寫成:

    然後取似然函數爲:

    因爲和 在同一 處取得極值,因此我們接着取對數似然函數爲:

    最大似然估計就是求使取最大值時的 。這裏對 取相反數,可以使用梯度下降法求解,求得的 就是要求的最佳參數:

    2.2 GBDT二分類原理

    邏輯迴歸單個樣本的損失函數可以表達爲:

    其中,是邏輯迴歸預測的結果。假設第 步迭代之後當前學習器爲 ,將 替換爲 帶入上式之後,可將損失函數寫爲:

    其中,第棵樹對應的響應值爲(損失函數的負梯度,即僞殘差):

    對於生成的決策樹,計算各個葉子節點的最佳殘差擬合值爲:

    由於上式沒有 閉式解(closed form solution) ,我們一般使用近似值代替:

    GBDT二分類算法完整的過程如下:

    (1)初始化第一個弱學習 器   :

    其中,是訓練樣本中 的比例,利用先驗信息來初始化學習器。

    (2)對於建立 棵分類迴歸樹 :

    a) 對 ,計算第 棵樹對應的響應值(損失函數的負梯度,即僞殘差):

    b) 對於,利用CART迴歸樹擬合數據 ,得到第 棵迴歸樹,其對應的葉子節點區域爲 ,其中 ,且 爲第棵迴歸樹葉子節點的個數。

    c) 對於個葉子節點區域 ,計算出最佳擬合值:

    d) 更新強學習器 :

    (3)得到最終的強學習器 的表達式:

    從以上過程中可知,除了由損失函數引起的負梯度計算和葉子節點的最佳殘差擬合值的計算不同,二元GBDT分類和GBDT迴歸算法過程基本相似。那麼二元GBDT是如何做分類呢?

    將邏輯迴歸的公式進行整理,我們可以得到,其中,也就是將給定輸入 預測爲正樣本的概率。邏輯迴歸用一個線性模型去擬合 這個事件的對數幾率(odds)。二元GBDT分類算法和邏輯迴歸思想一樣,用一系列的梯度提升樹去擬合這個對數幾率,其分類模型可以表達爲:

    3. GBDT二分類算法實例

    (1)數據集介紹

    訓練集如下表所示,一組數據的特徵有年齡和體重,把身高大於1.5米作爲分類邊界,身高大於1.5米的令標籤爲1,身高小於等於1.5米的令標籤爲0,共有4組數據。

    測試數據如下表所示,只有一組數據,年齡爲25、體重爲65,我們用在訓練集上訓練好的GBDT模型預測該組數據的身高是否大於1.5米?

    (2)模型訓練階段

    參數設置:

    • 學習率:learning_rate = 0.1

    • 迭代次數:n_trees = 5

    • 樹的深度:max_depth = 3

    1)初始化弱學習器:

    2)對於建立棵分類迴歸樹:

    由於我們設置了迭代次數: n_trees=5 ,這就是設置了。

    首先 計算負梯度,根據上文損失函數爲對數損失時,負梯度(即僞殘差、近似殘差)爲:

    我們知道梯度提升類算法,其關鍵是利用損失函數的負梯度的值作爲迴歸問題提升樹算法中的殘差的近似值,擬合一個迴歸樹。這裏,爲了稱呼方便,我們把負梯度叫做殘差。

    現將殘差的計算結果列表如下:

    此時將殘差作爲樣本的標籤來訓練弱學習器,即下表數據:

    接着 尋找回歸樹的最佳劃分節點,遍歷每個特徵的每個可能取值。從年齡特徵值爲開始,到體重特徵爲結束,分別計算分裂後兩組數據的對數似然損失(Log-likelihood Error),爲左節點的對數損失, 爲右節點的對數損失,找到使對數損失和 最小的那個劃分節點,即爲最佳劃分節點。

    例如:以年齡爲劃分節點,將小於的樣本劃分爲到左節點,大於等於的樣本劃分爲右節點。左節點包括 ,右節點包括樣本 , , ,,所有可能的劃分情況如下表所示:

    以上劃分點的總對數似然損失最小爲,有兩個劃分點:年齡和體重,所以隨機選一個作爲劃分點,這裏我們選年齡。現在我們的第一棵樹長這個樣子:

    我們設置的參數中樹的深度 max_depth=3 ,現在樹的深度只有,需要再進行一次劃分,這次劃分要對左右兩個節點分別進行劃分,但是我們在生成樹的時候,設置了三個樹繼續生長的條件:

    • 深度沒有到達最大。樹的深度設置爲3,意思是需要生長成3層;

    • 點樣本數 >= min_samples_split;

    • 此節點上的樣本的標籤值不一樣。如果值一樣說明已經劃分得很好了,不需要再分; (本程序滿足這個條件,因此樹只有2層)

    最終 我們的第一棵迴歸樹長下面這個樣子:

    此時 我們的樹滿足了設置,還需要做一件事情,給這棵樹的每個葉子節點分別賦一個參數,來擬合殘差。

    根據上述劃分結果,爲了方便表示,規定從左到右爲第個葉子結點,其計算值過程如下:

    此時的第一棵樹長下面這個樣子:

    接着 更新強學習器,需要用到學習率: learning_rate=0.1 ,用 lr 表示。更新公式爲:

    爲什麼要用學習率呢?這是Shrinkage的思想,如果每次都全部加上擬合值,即學習率爲,很容易一步學到位導致GBDT過擬合。

    重複此步驟,直到 結束,最後生成棵樹。

    下面將展示每棵樹最終的結構,這些圖都是我GitHub上的代碼生成的,感興趣的同學可以去運行一下代碼。https://github.com/Microstrong0305/WeChat-zhihu-csdnblog-code/tree/master/Ensemble%20Learning/GBDT_GradientBoostingBinaryClassifier

    第一棵樹:

    第二棵樹:

    第三棵樹:

    第四棵樹:

    第五棵樹:

    3)得到最後的強學習器:

    (3)模型預測階段

    • 在 中,測試樣本的年齡爲,大於劃分節點歲,所以被預測爲。

    • 在 中,測試樣本的年齡爲,大於劃分節點歲,所以被預測爲。

    • 在 中,測試樣本的年齡爲,大於劃分節點歲,所以被預測爲。

    • 在 中,測試樣本的年齡爲,大於劃分節點歲,所以被預測爲。

    • 在 中,測試樣本的年齡爲,大於劃分節點歲,所以被預測爲。

    最終預測結果爲:

    4. 手撕GBDT二分類算法

    本篇文章所有數據集和代碼均在我的GitHub中,地址:https://github.com/Microstrong0305/WeChat-zhihu-csdnblog-code/tree/master/Ensemble%20Learning

    4.1 用Python3實現GBDT二分類算法

    需要的Python庫:

    pandas、PIL、pydotplus、matplotlib

    其中 pydotplus 庫會自動調用 Graphviz ,所以需要去 Graphviz 官網下載 graphviz-2.38.msi 安裝,再將安裝目錄下的 bin 添加到系統環境變量,最後重啓計算機。

    由於用Python3實現GBDT二分類算法代碼量比較多,我這裏就不列出詳細代碼了,感興趣的同學可以去我的GitHub中看一下,地址:https://github.com/Microstrong0305/WeChat-zhihu-csdnblog-code/tree/master/Ensemble%20Learning/GBDT_GradientBoostingBinaryClassifier

    4.2 用sklearn實現GBDT二分類算法

    import numpy as np

    from sklearn.ensemble import GradientBoostingClassifier


    '''

    調參:

    loss:損失函數。有deviance和exponential兩種。deviance是採用對數似然,exponential是指數損失,後者相當於AdaBoost。

    n_estimators:最大弱學習器個數,默認是100,調參時要注意過擬合或欠擬合,一般和learning_rate一起考慮。

    learning_rate:步長,即每個弱學習器的權重縮減係數,默認爲0.1,取值範圍0-1,當取值爲1時,相當於權重不縮減。較小的learning_rate相當於更多的迭代次數。

    subsample:子採樣,默認爲1,取值範圍(0,1],當取值爲1時,相當於沒有采樣。小於1時,即進行採樣,按比例採樣得到的樣本去構建弱學習器。這樣做可以防止過擬合,但是值不能太低,會造成高方差。

    init:初始化弱學習器。不使用的話就是第一輪迭代構建的弱學習器.如果沒有先驗的話就可以不用管


    由於GBDT使用CART迴歸決策樹。以下參數用於調優弱學習器,主要都是爲了防止過擬合

    max_feature:樹分裂時考慮的最大特徵數,默認爲None,也就是考慮所有特徵。可以取值有:log2,auto,sqrt

    max_depth:CART最大深度,默認爲None

    min_sample_split:劃分節點時需要保留的樣本數。當某節點的樣本數小於某個值時,就當做葉子節點,不允許再分裂。默認是2

    min_sample_leaf:葉子節點最少樣本數。如果某個葉子節點數量少於某個值,會同它的兄弟節點一起被剪枝。默認是1

    min_weight_fraction_leaf:葉子節點最小的樣本權重和。如果小於某個值,會同它的兄弟節點一起被剪枝。一般用於權重變化的樣本。默認是0

    min_leaf_nodes:最大葉子節點數

    '''


    gbdt = GradientBoostingClassifier(loss='deviance', learning_rate=0.1, n_estimators=5, subsample=1

    , min_samples_split=2, min_samples_leaf=1, max_depth=3

    , init=None, random_state=None, max_features=None

    , verbose=0, max_leaf_nodes=None, warm_start=False

    )


    train_feat = np.array([[1, 5, 20],

    [2, 7, 30],

    [3, 21, 70],

    [4, 30, 60],

    ])

    train_label = np.array([[0], [0], [1], [1]]).ravel()


    test_feat = np.array([[5, 25, 65]])

    test_label = np.array([[1]])

    print(train_feat.shape, train_label.shape, test_feat.shape, test_label.shape)


    gbdt.fit(train_feat, train_label)

    pred = gbdt.predict(test_feat)


    total_err = 0

    for i in range(pred.shape[0]):

    print(pred[i], test_label[i])

    err = (pred[i] - test_label[i]) / test_label[i]

    total_err += err * err

    print(total_err / pred.shape[0])

    用sklearn中的GBDT庫實現GBDT二分類算法的難點在於如何更好的調節下列參數:

    用sklearn實現GBDT二分類算法的GitHub地址:https://github.com/Microstrong0305/WeChat-zhihu-csdnblog-code/tree/master/Ensemble%20Learning/GBDT_Classification_sklearn

    5. GBDT分類任務常見的損失函數

    對於GBDT分類算法,其損失函數一般有對數損失函數和指數損失函數兩種:

    (1)如果是指數損失函數,則損失函數表達式爲:

    其負梯度計算和葉子節點的最佳負梯度擬合可以參看Adaboost算法過程。

    (2)如果是對數損失函數,分爲二元分類和多元分類兩種,本文主要介紹了GBDT二元分類的損失函數。

    6. 總結

    在本文中,我們首先簡單介紹瞭如何把GBDT迴歸算法變成分類算法的思路;然後從邏輯迴歸的對數損失函數推導出GBDT的二分類算法原理;其次不僅用Python3實現GBDT二分類算法,還用sklearn實現GBDT二分類算法;最後介紹了GBDT分類任務中常見的損失函數。GBDT可以完美的解決二分類任務,那麼它對多分類任務是否有效呢?如果有效,GBDT是如何做多分類呢?這些問題都需要我們不停的探索和挖掘GBDT的深層原理。讓我們期待一下GBDT在多分類任務中的表現吧!

    7. Reference

    【1】Friedman J H. Greedy function approximation: a gradient boosting machine[J]. Annals of statistics, 2001: 1189-1232.
    【2】GBDT詳細講解&常考面試題要點,地址:https://mp.weixin.qq.com/s/M2PwsrAnI1S9SxSB1guHdg
    【3】機器學習算法GBDT的面試要點總結-上篇,地址:https://www.cnblogs.com/ModifyRong/p/7744987.html
    【4】Gradient Boosting Decision Tree,地址:http://gitlinux.net/2019-06-11-gbdt-gradient-boosting-decision-tree/
    【5】GBDT算法用於分類問題 - hunter7z的文章 - 知乎,地址:https://zhuanlan.zhihu.com/p/46445201
    【6】當我們在談論GBDT:Gradient Boosting 用於分類與迴歸 - 余文毅的文章 - 知乎 ,地址:https://zhuanlan.zhihu.com/p/25257856
    【7】 GBDT原理與Sklearn源碼分析-分類篇,地址:https://blog.csdn.net/qq_22238533/article/details/79192579
    【8】 《推薦系統算法實踐》,黃美靈著。
    【9】《百面機器學習》,諸葛越主編、葫蘆娃著。
    【10】GBDT模型,地址:https://www.jianshu.com/p/0bc32c8e4ca8
    【11】代碼實戰之GBDT,地址:https://louisscorpio.github.io/2018/01/19/%E4%BB%A3%E7%A0%81%E5%AE%9E%E6%88%98%E4%B9%8BGBDT/

    AI學習路線和優質資源,在後臺回覆"AI"獲取

    相關文章