殘差~貸款~2y~obj~$\Omega$~泰勒
例子~遍歷~GH~衡量~分裂~遞歸
一、XGBoost起源
XGBoost的全稱是ExtremeGradient Boosting,2014年2月誕生,作者為華盛頓大學研究機器學習的大牛——陳天奇。
他在研究中深深的體會到現有庫的計算速度和精度問題,為此而着手搭建完成 xgboost 項目。
XGBoost問世后,因其優良的學習效果以及高效的訓練速度而獲得廣泛的關注,並在各種算法大賽上大放光彩。
二、參數解析
XGBoost的作者把所有的參數分成了三類:
通用參數:宏觀函數控制。
Booster參數:控制每一步的booster(tree/regression)。
學習目標參數:控制訓練目標的表現
1)通用參數
booster[默認gbtree]
選擇每次迭代的模型,有兩種選擇:
gbtree:基於樹的模型
gbliner:線性模型
盡管有兩種booster可供選擇,tree booster的表現遠遠勝過linear booster,所以linear booster很少用到
silent[默認0]
當這個參數值為1時,靜默模式開啟,不會輸出任何信息。
一般這個參數就保持默認的0,因為這樣能幫我們更好地理解模型。
nthread[默認值為最大可能的線程數]
這個參數用來進行多線程控制,應當輸入系統的核數。
如果你希望使用CPU全部的核,那就不要輸入這個參數,算法會自動檢測它。
2)booster參數
-
1. learning_rate[默認0.3]
典型值為0.01-0.2。
-
2. min_child_weight[默認1]
決定最小葉子節點樣本權重和。這個參數用於避免過擬合。當它的值較大時,可以避免模型學習到局部的特殊樣本。但是如果這個值過高,會導致欠擬合。這個參數需要使用CV來調整。
-
3. max_depth[默認6]
這個值也是用來避免過擬合的。max_depth越大,模型會學到更具體更局部的樣本。需要使用CV函數來進行調優。典型值:3-10
-
4. max_leaf_nodes
樹上最大的節點或葉子的數量。可以替代max_depth的作用。因為如果生成的是二叉樹,一個深度為n的樹最多生成n2個葉子。
-
5. gamma[默認0]
在節點分裂時,只有分裂后損失函數的值下降了,才會分裂這個節點。Gamma指定了節點分裂所需的最小損失函數下降值。這個參數的值越大,算法越保守。這個參數的值和損失函數息息相關,所以是需要調整的。
-
6. max_delta_step[默認0]
這參數限制每棵樹權重改變的最大步長。如果這個參數的值為0,那就意味着沒有約束。如果它被賦予了某個正值,那么它會讓這個算法更加保守。通常,這個參數不需要設置。但是當各類別的樣本十分不平衡時,它對邏輯回歸是很有幫助的。
這個參數一般用不到,但是你可以挖掘出來它更多的用處。
-
7. subsample[默認1]
這個參數控制對於每棵樹,隨機采樣的比例。減小這個參數的值,算法會更加保守,避免過擬合。但是,如果這個值設置得過小,它可能會導致欠擬合。典型值:0.5-1
-
8. colsample_bytree[默認1]
用來控制每棵隨機采樣的列數的占比(每一列是一個特征)。典型值:0.5-1
-
9. colsample_bylevel[默認1]
用來控制樹的每一級的每一次分裂,對列數的采樣的占比。
我個人一般不太用這個參數,因為subsample參數和colsample_bytree參數可以起到相同的作用。但是如果感興趣,可以挖掘這個參數更多的用處。
-
10. lambda[默認1]
權重的L2正則化項。(和Ridge regression類似)。這個參數是用來控制XGBoost的正則化部分的。雖然大部分數據科學家很少用到這個參數,但是這個參數在減少過擬合上還是可以挖掘出更多用處的。
-
11. alpha[默認0]
權重的L1正則化項。(和Lasso regression類似)。可以應用在很高維度的情況下,使得算法的速度更快。
-
12. scale_pos_weight[默認1]
在各類別樣本十分不平衡時,把這個參數設定為一個正值,可以使算法更快收斂。
3)學習目標參數:這個參數用來控制理想的優化目標和每一步結果的度量方法。
objective(默認reg:linear):這個參數定義需要被最小化的損失函數。最常用的值有:
binary:logistic 二分類的邏輯回歸,返回預測的概率(不是類別)。
multi:softmax 使用softmax的多分類器,返回預測的類別(不是概率)。 在這種情況下,你還需要多設一個參數:num_class(類別數目)。
multi:softprob 和multi:softmax參數一樣,但是返回的是每個數據屬於各個類別的概率。
eval_metric(默認值取決於objective參數的取值)
對於有效數據的度量方法。
對於回歸問題,默認值是rmse,對於分類問題,默認值是error。
典型值有:
seed(默認0):隨機數的種子
三、Xgboost原理推導
1)基本原理
首先使用訓練集(包含:標准答案,即標簽)訓練一棵樹,然后使用這棵樹預測訓練集,得到每個樣本的預測值,由於預測值與真值存在偏差,所以真值與預測值相減可以得到“殘差”(這里相當於用訓練集訓練模型,再反過來作用於訓練集-不要以為就能完全學到所有樣本的真值,那樣會過擬合的)
接下來訓練第二棵樹,此時不再使用真值,而是使用殘差作為標准答案。兩棵樹訓練完成后,可以再次得到每個樣本的殘差
然后進一步訓練第三棵樹,以此類推。樹的總棵數可以人為指定,也可以監控某些指標(例如驗證集上的誤差)來停止訓練
2)示例
a)預測客戶去銀行審批貸款的額度,假設客戶的額度為1000
使用第一顆樹預測,其目標函數為1000。假設模型預測的結果為920,則殘差為80
構造第二課樹預測,這時其目標函數就要基於第一顆樹的預測結果,第二顆樹的目標函數為80。假設第二顆樹預測的結果為50,則與真實值的殘差還剩下30,即會作為第三顆樹的目標值
構造第三棵樹預測,此時的目標函數為30,假設第三課樹又找回來12
依次類推,串行構造,需要把前一顆樹的結果當成一個整體。最終結果值為n棵樹的結果相加。比如例中,如果只做三顆樹預測,最終結果為982
b)用兩顆樹來預測一個人是否喜歡玩游戲。最下面的一行數2、0.1、-1為得分值
模型的結果為兩顆樹的值相加。比如男孩愛玩游戲的得分為2.9,老人愛玩游戲的得分為-1.9
3)簡單流程
假設我們構造k顆樹,則對於樣本i來說,輸出值就是k顆樹的輸出值累加:
其中K表示總共K個決策樹,k表示第k個決策樹,F表示決策樹的函數空間
每一個決策樹都有獨立的樹結構q和葉節點權重w
首先,我們想問“樹的參數是什么”?我們需要學習的是函數\(f_k\)包含獨立的樹結構q和葉節點權重w,這比傳統的利用梯度法求解的優化問題要難得多
由於同時訓練所有的樹不容易,我們選用另一策略:將已經學習的樹固定,每次向其中添加一棵新的樹,在第t顆樹后獲得的預測值記為:,因此我們構建流程如下:
所以整個流程就是每一輪增加一顆什么樣的樹\(f_t(x_i)\),才能使模型最優
4)推導
我們希望每輪增加的樹可以優化目標函數:
這里要注意:Constant是前t-1棵樹的懲罰項,前t-1樹結構已經確定
懲罰項主要防止樹模型過大,由葉子數量和L2正則組成:
其中懲罰項計算如下:注意-葉子節點權重w(其實就是預測值)
在推導之前,需要讀者先了解泰勒公式:
這里可以這么理解:$x$為原來的模型,紅框內的$\Delta x$當作新的樹模型,即新增加一個模型
這樣我們就可以進行如下泰勒展開
而我們的目標函數是:
如果用MSE-平方損失作為損失函數,將上式展開(注意:將平方項展開后的常數項已經用新的constant代替):
但是對於其他的損失函數,我們未必能得出如此漂亮的式子,所以,對於一般的損失函數,我們可以采用如下的泰勒展開近似來定義一個近似的目標函數,如下所示:
值得注意的是,損失函數l是給定的,y的真實值是知道的,預測值是根據前t-1顆樹知道的,則gi和hi是可算的
這里如果我們的損失函數是平方損失函數,則gi和hi計算如下:
這里有必要再明確一下,gi和hi的含義。gi怎么理解呢?現有t-1棵樹是不是?這t-1棵樹組成的模型對第i個訓練樣本有一個預測值\(y_i\)是不是?
這個預測值與第i個樣本的真實標簽\(yi\)肯定有差距是不是?這個差距可以用上面的損失函數來衡量是不是?現在gi和hi的含義你已經清楚了是不是?
我們來看一個實例,假設我們正在優化第11棵CART樹,也就是說前10棵 CART樹已經確定了。這10棵樹對樣本\((x_i,y_i=1)\)的預測值是\(y_i=-1\),假設我們現在是做分類,我們的損失函數是:
我們可以求出這個損失函數在\(y_i=-1\)點的梯度:
將\(y_i=-1\)帶入上式,計算得到-0.2689。這個-0.2689就是g_i。該值是負的,也就是說,如果我們想要減小這10棵樹在該樣本點上的預測損失,我們應該沿着梯度的反方向去走,也就是要增大
來答一個小問題,在優化第t棵樹時,有多少個gi和hi要計算?嗯,沒錯就是各有N個,N是訓練樣本的數量。如果有10萬樣本,在優化第t棵樹時,就需要計算出個10萬個gi和hi
感覺好像很麻煩是不是?但是你再想一想,這10萬個gi之間是不是沒有啥關系?是不是可以並行計算呢?聰明的你想必再一次感受到了,為什么xgboost會辣么快!
好,現在我們來審視下這個式子,哪些是常量,哪些是變量。式子最后有一個constant項,聰明如你,肯定猜到了,它就是前t-1棵樹的正則化項。l(yi, yi^t-1)也是常數項
剩下的三個變量項分別是第t棵CART樹的一次式,二次式,和整棵樹的正則化項。再次提醒,這里所謂的樹的一次式,二次式,其實都是某個葉子節點的值的一次式,二次式
我們的目標是讓這個目標函數最小化,常數項顯然沒有什么用,我們把它們去掉,就變成了下面這樣:
5)重新定義決策樹
一個xi的樣本進入決策樹分類是由最終的的葉子權值決定,即黑色實心圓,而中間的空心圓只是決定的 xi 樣本落入到哪一個葉子
q(x)表示樣本x落入的葉子,即是q是將每個樣本分配到相應葉子的函數
Wq(x)表示樣本x落入葉子的權值,即W是葉節點上的得分向量
所以一顆決策樹的核心是:“樹結構”與“葉權值”,如下:
6)正則項定義
決策樹的復雜度可參考葉節點數和葉權值(在XGBoost里,如下定義復雜度):
舉例:
注意:當然,不止一種方式可以定義復雜度,但實踐中上面提到的就能很好得起作用。正則化項在很多樹模型包里都沒有很好地處理,甚至直接忽略
這是因為,傳統樹模型只強調提升模型的純度,而模型復雜度控制采用啟發式方法。通過公式定義,我們可以更好得理解學習器訓練過程,並起獲得較好的實踐結果
下面是公式推導里神奇的部分!將樹模型重新公式化表示之后,可以將第t棵樹的目標值記作:
也就是下面的解釋:
也就是衡量了我們當前樹的模型效果的好壞
7)目標函數計算總結:
定義如下式子:
得:
對W求偏導:
代入目標函數:
舉例:XGBoost公式做的事情
8)找出最優的樹結構
有了評判樹的結構好壞的標准,我們就可以先求最佳的樹結構,這個定出來后,最佳的葉子結點的值實際上在上面已經求出來了
問題是:樹的結構近乎無限多,一個一個去測算它們的好壞程度,然后再取最好的顯然是不現實的。所以,我們仍然需要采取一點策略,這就是逐步學習出最佳的樹結構
這與我們將K棵樹的模型分解成一棵一棵樹來學習是一個道理,只不過從一棵一棵樹變成了一層一層節點而已。如果此時你還是有點蒙,沒關系,下面我們就來看一下具體的學習過程
我們以上文提到過的判斷一個人是否喜歡計算機游戲為例子。最簡單的樹結構就是一個節點的樹。我們可以算出這棵單節點的樹的好壞程度obj*。假設我們現在想按照年齡將這棵單節點樹進行分叉,我們需要知道:
1、按照年齡分是否有效,也就是是否減少了obj的值
2、如果可分,那么以哪個年齡值來分
為了回答上面兩個問題,我們可以將這一家五口人按照年齡做個排序。如下圖所示:
按照這個圖從左至右掃描,我們就可以找出所有的切分點。對每一個確定的切分點,我們衡量切分好壞的標准如下:
這個Gain實際上就是單節點的obj*減去切分后的兩個節點的樹obj*,Gain如果是正的,並且值越大,表示切分后obj*越小於單節點的obj*,就越值得切分
同時,我們還可以觀察到,Gain的左半部分如果小於右側的γ,則Gain就是負的,表明切分后obj反而變大了。γ在這里實際上是一個臨界值,它的值越大,表示我們對切分后obj下降幅度要求越嚴
這個值也是可以在xgboost中設定的。 掃描結束后,我們就可以確定是否切分,如果切分,對切分出來的兩個節點,遞歸地調用這個切分過程,我們就能獲得一個相對較好的樹結構
注意:xgboost的切分操作和普通的決策樹切分過程是不一樣的。普通的決策樹在切分的時候並不考慮樹的復雜度,而依賴后續的剪枝操作來控制。xgboost在切分的時候就已經考慮了樹的復雜度,就是那個γ參數。所以,它不需要進行單獨的剪枝操作
四、感謝
Xgboost基本原理好理解,但是推導過程比較復雜抽象,自己也花了幾天的時間去看博客和文章,這里感謝下面的博客,正是你們的抽象變具體,才讓我加深了對Xgboost的理解,真誠的感謝!
1.https://blog.csdn.net/xinzhi8/article/details/73466554
2.https://blog.csdn.net/PbGc396Dwxjb77F2je/article/details/78786959
3.https://blog.csdn.net/cymy001/article/details/79037785
4.https://www.cnblogs.com/kuangsyx/p/9043168.html
視頻參考:https://www.bilibili.com/video/BV1KE411M7Pi?p=1(講的不錯哦)