機器學習--boosting家族之XGBoost算法


一、概念

  XGBoost全名叫(eXtreme Gradient Boosting)極端梯度提升,經常被用在一些比賽中,其效果顯著。它是大規模並行boosted tree的工具,它是目前最快最好的開源boosted tree工具包。XGBoost 所應用的算法就是 GBDT(gradient boosting decision tree)的改進,既可以用於分類也可以用於回歸問題中。

  1、回歸樹與決策樹  

  事實上,分類與回歸是一個型號的東西,只不過分類的結果是離散值,回歸是連續的,本質是一樣的,都是特征(feature)到結果/標簽(label)之間的映射。說說決策樹和回歸樹,在上面決策樹的講解中相信決策樹分類已經很好理解了。

  分類樹的樣本輸出(即響應值)是類的形式,如判斷蘑菇是有毒還是無毒,周末去看電影還是不去。而回歸樹的樣本輸出是數值的形式,比如給某人發放房屋貸款的數額就是具體的數值,可以是0到120萬元之間的任意值。

  那么,這時候你就沒法用上述的信息增益、信息增益率、基尼系數來判定樹的節點分裂了,你就會采用新的方式,預測誤差,常用的有均方誤差、對數誤差等。而且節點不再是類別,是數值(預測值),那么怎么確定呢,有的是節點內樣本均值,有的是最優化算出來的比如Xgboost。

  2、boosting集成學習

  boosting集成學習,由多個相關聯的決策樹聯合決策,什么叫相關聯,舉個例子,有一個樣本[數據->標簽]是[(2,4,5)-> 4],第一棵決策樹用這個樣本訓練得預測為3.3,那么第二棵決策樹訓練時的輸入,這個樣本就變成了[(2,4,5)-> 0.7],也就是說,下一棵決策樹輸入樣本會與前面決策樹的訓練和預測相關。

  與之對比的是random foreast(隨機森林)算法,各個決策樹是獨立的、每個決策樹在樣本堆里隨機選一批樣本,隨機選一批特征進行獨立訓練,各個決策樹之間沒有啥毛線關系。

  所以首先Xgboost首先是一個boosting的集成學習,這樣應該很通俗了

  3、這個時候大家就能感覺到一個回歸樹形成的關鍵點:(1)分裂點依據什么來划分(如前面說的均方誤差最小,loss);(2)分類后的節點預測值是多少(如前面說,有一種是將葉子節點下各樣本實際值得均值作為葉子節點預測誤差,或者計算所得)

 

二、集成思想

  在學習XGBoost之前,我們得需要先明白集成思想。集成學習方法是指將多個學習模型組合,以獲得更好的效果,使組合后的模型具有更強的泛化能力。另外XGBoost是以分類回歸樹(CART樹)進行組合。故在此之前,我們先看下CART樹(CART樹具體原理請自行復習,或者可以留言)。如下,通過輸入用戶年齡、性別進行判斷用戶是否喜歡玩游戲的得分值。由此得到一顆CART樹模型。

        

  我們知道對於單個的決策樹模型容易出現過擬合,並且不能在實際中有效應用。所以出現了集成學習方法。如下圖,通過兩棵樹組合進行玩游戲得分值預測。其中tree1中對小男生的預測分值為2,tree2對小男生的預測分值為0.9。則該小男生的最后得分值為2.9。

        

  將上面集成學習方法推廣到一般情況,可知其預測模型為:

                        

  

  其中為樹的總個數,表示第顆樹,表示樣本的預測結果。

  損失函數為:                 

       

三、分析XGboost思路

  首先明確下我們的目標,希望建立K個回歸樹,使得樹群的預測值盡量接近真實值(准確率)而且有盡量大的泛化能力(更為本質的東西),從數學角度看這是一個泛函最優化,多目標,看下目標函數: 

                

  其中i表示第i個樣本,表示第i個樣本的預測誤差,誤差越小越好,不然你算得上預測么?后面表示樹的復雜度的函數,越小復雜度越低,泛化能力越強,這意味着啥不用我多說。表達式為                    

                

  T表示葉子節點的個數,w表示節點的數值(這是回歸樹的東西,分類樹對應的是類別)

  直觀上看,目標要求預測誤差盡量小,葉子節點盡量少,節點數值盡量不極端(這個怎么看,如果某個樣本label數值為4,那么第一個回歸樹預測3,第二個預測為1;另外一組回歸樹,一個預測2,一個預測2,那么傾向后一種,為什么呢?前一種情況,第一棵樹學的太多,太接近4,也就意味着有較大的過擬合的風險)

  ok,聽起來很美好,可是怎么實現呢,上面這個目標函數跟實際的參數怎么聯系起來,記得我們說過,回歸樹的參數:(1)選取哪個feature分裂節點呢;(2)節點的預測值(總不能靠取平均值這么粗暴不講道理的方式吧,好歹高級一點)。上述形而上的公式並沒有“直接”解決這兩個,那么是如何間接解決的呢?

  先說答案:貪心策略+最優化(二次最優化)

  通俗解釋貪心策略:就是決策時刻按照當前目標最優化決定,說白了就是眼前利益最大化決定,“目光短淺”策略,他的優缺點細節大家自己去了解,經典背包問題等等。

  這里是怎么用貪心策略的呢,剛開始你有一群樣本,放在第一個節點,這時候T=1T=1,ww多少呢,不知道,是求出來的,這時候所有樣本的預測值都是ww(這個地方自己好好理解,決策樹的節點表示類別,回歸樹的節點表示預測值),帶入樣本的label數值,此時loss function變為 

              

  如果這里的l(w−yi)誤差表示用的是平方誤差,那么上述函數就是一個關於w的二次函數求最小值,取最小值的點就是這個節點的預測值,最小的函數值為最小損失函數。

  這里處理的就是二次函數最優化! 
  要是損失函數不是二次函數咋辦,哦,泰勒展開式會否?,不是二次的想辦法近似為二次。

  接着來,接下來要選個feature分裂成兩個節點,變成一棵弱小的樹苗,那么需要:(1)確定分裂用的feature,how?最簡單的是粗暴的枚舉,選擇loss function效果最好的那個(關於粗暴枚舉,Xgboost的改良並行方式咱們后面看);(2)如何確立節點的ww以及最小的loss function,大聲告訴我怎么做?對,二次函數的求最值(細節的會注意到,計算二次最值是不是有固定套路,導數=0的點,ok)

  那么節奏是,選擇一個feature分裂,計算loss function最小值,然后再選一個feature分裂,又得到一個loss function最小值…你枚舉完,找一個效果最好的,把樹給分裂,就得到了小樹苗。在分裂的時候,你可以注意到,每次節點分裂,loss function被影響的只有這個節點的樣本,因而每次分裂,計算分裂的增益(loss function的降低量)只需要關注打算分裂的那個節點的樣本。

  接下來,繼續分裂,按照上述的方式,形成一棵樹,再形成一棵樹,每次在上一次的預測基礎上取最優進一步分裂/建樹,是不是貪心策略?!

  凡是這種循環迭代的方式必定有停止條件,什么時候停止呢: 
  (1)當引入的分裂帶來的增益小於一個閥值的時候,我們可以剪掉這個分裂,所以並不是每一次分裂loss function整體都會增加的,有點預剪枝的意思,閾值參數為 γ 正則項里葉子節點數 T 的系數; 
  (2)當樹達到最大深度時則停止建立決策樹,設置一個超參數max_depth,這個好理解吧,樹太深很容易出現的情況學習局部樣本,過擬合; 
  (3)當樣本權重和小於設定閾值時則停止建樹,這個解釋一下,涉及到一個超參數-最小的樣本權重和min_child_weight,和GBM的 min_child_leaf 參數類似,但不完全一樣,大意就是一個葉子節點樣本太少了,也終止同樣是過擬合; 
  (4)貌似看到過有樹的最大數量的…這個不確定 
  那節點分裂的時候是按照哪個順序來的,比如第一次分裂后有兩個葉子節點,先裂哪一個?答:同一層級的(多機)並行,確立如何分裂或者不分裂成為葉子節點 

 

四、原理推導

  上面一部分我們知道了集成學習方法的預測模型,因為XGBoost也是集成學習方法的一種。對於XGBoost的預測模型同樣可以表示為:

                        

  其中為樹的總個數,表示第顆樹,表示樣本的預測結果。

  其中損失函數也同樣表示為:

                      

  其中為樣本的訓練誤差,表示第棵樹的正則項。

  看到了這里,我們可能會想到,現在知道了模型預測函數和損失函數,那我們是不是直接就能求出其預測模型了呢?答案肯定不是,我們首先需要明確知道優化和求解的參數是什么呢?由上面的預測模型中,我們可以看到對於每棵樹的預測值是如何計算的?想到這里,你就已經知道了需要做的事了,我需要求解和優化的就是每個葉子節點的得分值,也就是的值。另外我們知道XGBoost是以CART樹中的回歸樹作為基分類器,在給定訓練數據后,其單個樹的結構(葉子節點個數、樹深度等等)基本可以確定了。但XGBoost並不是簡單重復的將幾個CART樹進行組合。它是一種加法模型,將模型上次預測(由t-1棵樹組合而成的模型)產生的誤差作為參考進行下一棵樹(第t棵樹)的建立。以此,每加入一棵樹,將其損失函數不斷降低。如下圖就為加法模型案例,它將模型預測值與實際值殘差作為下一顆樹的輸入數據。

          

  對於加法策略可以表示如下:

  初始化(模型中沒有樹時,其預測結果為0):

  往模型中加入第一棵樹:

  往模型中加入第二棵樹:

                  …

  往模型中加入第t棵樹:

  其中表示第棵樹,表示組合棵樹模型對樣本的預測結果。

  我們知道,每次往模型中加入一棵樹,其損失函數便會發生變化。另外在加入第t棵樹時,則前面第t-1棵樹已經訓練完成,此時前面t-1棵樹的正則項和訓練誤差都成已知常數項。對於每棵樹的正則項部分,我們將在后面再細說。

                        

  如果損失函數采用均方誤差時,其目標損失函數變為:

                           

  另外對於目標損失函數中的正則項(復雜度)部分,我們從單一的樹來考慮。對於其中每一棵回歸樹,其模型可以寫成:

            

  其中為葉子節點的得分值,表示樣本對應的葉子節點。為該樹的葉子節點個數。

  因此,在這里。我們將該樹的復雜度寫成:

            

  復雜度計算例子如下:

            

  此時,對於XGBoost的目標函數我們可以寫為:

                

  現在我們只需要找到f(t)來優化上式目標。

            

  在推導之前,我們先介紹下泰勒展開式:

                  

  這里我們用泰勒展開式來近似原來的目標函數,將看作。則原目標函數可以寫成:

            

  令,同時對於第t棵樹時,為常數。同時去除所有常數項。故目標損失函數可以寫成:

            

  由上面介紹書的復雜度時,我們知道:,同時我們將目標函數全部轉換成在第t棵樹葉子節點的形式。因為目前對於可以看做是每個樣本在第t棵樹的葉子節點得分值相關函數的結果之和,所以我們也能從第t棵樹的葉子節點上來表示。

            

  上式中,前兩行 i=1~n 求和為在樣本中遍歷,后兩行 j = 1~T求和為在葉子節點上遍歷,其中為第t棵樹中總葉子節點的個數,表示在第個葉子節點上的樣本,為第個葉子節點的得分值。

  在這里,令

  則:

            

  對求偏導,並使其導函數等於0,則有:

            

  求解得:

  其目標函數可以為:

  根據目標函數,如何分裂樣本數據呢

      

      

 五、總結

  1、Xgboost的一些重點

  • w是最優化求出來的,不是啥平均值或規則指定的,這個算是一個思路上的新穎吧;
  • 正則化防止過擬合的技術,上述看到了,直接loss function里面就有;
  • 支持自定義loss function,只要能泰勒展開(能求一階導和二階導)就行;
  • 支持並行化,這個地方有必要說明下,因為這是xgboost的閃光點,直接的效果是訓練速度快,boosting技術中下一棵樹依賴上述樹的訓練和預測,所以樹與樹之間應該是只能串行!那么大家想想,哪里可以並行?! 沒錯,在選擇最佳分裂點,進行枚舉的時候並行!(據說恰好這個也是樹形成最耗時的階段)

    Attention:同層級節點可並行。具體的對於某個節點,節點內選擇最佳分裂點,候選分裂點計算增益用多線程並行。—–

    較少的離散值作為分割點倒是很簡單,比如“是否是單身”來分裂節點計算增益是很easy,但是“月收入”這種feature,取值很多,從5k~50k都有,總不可能每個分割點都來試一下計算分裂增益吧?(比如月收入feature有1000個取值,難道你把這1000個用作分割候選?缺點1:計算量,缺點2:出現葉子節點樣本過少,過擬合)我們常用的習慣就是划分區間,那么問題來了,這個區間分割點如何確定(難道平均分割),作者是這么做的:

    方法名字:Weighted Quantile Sketch 

    大家還記得每個樣本在節點(將要分裂的節點)處的loss function一階導數gi和二階導數hi,衡量預測值變化帶來的loss function變化,舉例來說,將樣本“月收入”進行升序排列,5k、5.2k、5.3k、…、52k,分割線為“收入1”、“收入2”、…、“收入j”,滿足(每個間隔的樣本的hi之和/總樣本的hi之和)為某個百分比ϵ(我這個是近似的說法),那么可以一共分成大約1/ϵ個分裂點。 

  • XGBoost還特別設計了針對稀疏數據的算法 

  假設樣本的第i個特征缺失時,無法利用該特征對樣本進行划分,這里的做法是將該樣本默認地分到指定的子節點,至於具體地分到哪個節點還需要某算法來計算,

  算法的主要思想是,分別假設特征缺失的樣本屬於右子樹和左子樹,而且只在不缺失的樣本上迭代,分別計算缺失樣本屬於右子樹和左子樹的增益,選擇增益最大的方向為缺失數據的默認方向(咋一看如果缺失情況為3個樣本,那么划分的組合方式豈不是有8種?指數級可能性啊,仔細一看,應該是在不缺失樣本情況下分裂后,把第一個缺失樣本放左邊計算下loss function和放右邊進行比較,同樣對付第二個、第三個…缺失樣本,這么看來又是可以並行的??)(答:論文中“枚舉”指的不是枚舉每個缺失樣本在左邊還是在右邊,而是枚舉缺失樣本整體在左邊,還是在右邊兩種情況。 分裂點還是只評估特征不缺失的樣本。);

  • 可實現后剪枝
  • 交叉驗證,方便選擇最好的參數,early stop,比如你發現30棵樹預測已經很好了,不用進一步學習殘差了,那么停止建樹。
  • 行采樣、列采樣,隨機森林的套路(防止過擬合)
  • Shrinkage,你可以是幾個回歸樹的葉子節點之和為預測值,也可以是加權,比如第一棵樹預測值為3.3,label為4.0,第二棵樹才學0.7,….再后面的樹還學個鬼,所以給他打個折扣,比如3折,那么第二棵樹訓練的殘差為4.0-3.3*0.3=3.01,這就可以發揮了啦,以此類推,作用是啥,防止過擬合,如果對於“偽殘差”學習,那更像梯度下降里面的學習率;
  • xgboost還支持設置樣本權重,這個權重體現在梯度g和二階梯度h上,是不是有點adaboost的意思,重點關注某些樣本

  2、與GDBT、深度學習對比下 

  Xgboost第一感覺就是防止過擬合+各種支持分布式/並行,所以一般傳言這種大殺器效果好(集成學習的高配)+訓練效率高(分布式),與深度學習相比,對樣本量和特征數據類型要求沒那么苛刻,適用范圍廣。

  說下GBDT:有兩種描述版本,把GBDT說成一個迭代殘差樹,認為每一棵迭代樹都在學習前N-1棵樹的殘差;把GBDT說成一個梯度迭代樹,使用梯度迭代下降法求解,認為每一棵迭代樹都在學習前N-1棵樹的梯度下降值。有說法說前者是后者在loss function為平方誤差下的特殊情況。這里說下我的理解,仍然舉個例子:第一棵樹形成之后,有預測值ŷ iy^i,真實值(label)為yiyi,前者版本表示下一棵回歸樹根據樣本(xi,yiŷ i)(xi,yi−y^i)進行學習,后者的意思是計算loss function在第一棵樹預測值附近的梯度負值作為新的label,也就是對應xgboost中的gi−gi

  Xgboost和深度學習的關系,陳天奇在Quora上的解答如下: 
  不同的機器學習模型適用於不同類型的任務。深度神經網絡通過對時空位置建模,能夠很好地捕獲圖像、語音、文本等高維數據。而基於樹模型的XGBoost則能很好地處理表格數據,同時還擁有一些深度神經網絡所沒有的特性(如:模型的可解釋性、輸入數據的不變性、更易於調參等)。 
這兩類模型都很重要,並廣泛用於數據科學競賽和工業界。舉例來說,幾乎所有采用機器學習技術的公司都在使用tree boosting,同時XGBoost已經給業界帶來了很大的影響。

 

六、XGboost參數解析

  XGBoost 參數

  在運行XGBoost程序之前,必須設置三種類型的參數:通用類型參數(general parameters)、booster參數和學習任務參數(task parameters)。 
  一般類型參數general parameters –參數決定在提升的過程中用哪種booster,常見的booster有樹模型和線性模型。 
  Booster參數-該參數的設置依賴於我們選擇哪一種booster模型。 
  學習任務參數task parameters-參數的設置決定着哪一種學習場景,例如,回歸任務會使用不同的參數來控制着排序任務。 
  命令行參數-一般和xgboost的CL版本相關。

  Booster參數: 
  1. eta[默認是0.3]  和GBM中的learning rate參數類似。通過減少每一步的權重,可以提高模型的魯棒性。典型值0.01-0.2 
  2. min_child_weight[默認是1]  決定最小葉子節點樣本權重和。當它的值較大時,可以避免模型學習到局部的特殊樣本。但如果這個值過高,會導致欠擬合。這個參數需要用cv來調整 
  3. max_depth [默認是6]  樹的最大深度,這個值也是用來避免過擬合的3-10 
  4. max_leaf_nodes  樹上最大的節點或葉子的數量,可以代替max_depth的作用,應為如果生成的是二叉樹,一個深度為n的樹最多生成2n個葉子,如果定義了這個參數max_depth會被忽略 
  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]  用來控制的每一級的每一次分裂,對列數的采樣的占比。 
  10. lambda[默認是1]  權重的L2正則化項 
  11. alpha[默認是1]  權重的L1正則化項 
  12. scale_pos_weight[默認是1]  各類樣本十分不平衡時,把這個參數設置為一個正數,可以使算法更快收斂。

  通用參數: 
  1. booster[默認是gbtree] 
  選擇每次迭代的模型,有兩種選擇:gbtree基於樹的模型、gbliner線性模型 
  2. silent[默認是0] 
  當這個參數值為1的時候,靜默模式開啟,不會輸出任何信息。一般這個參數保持默認的0,這樣可以幫我們更好的理解模型。 
  3. nthread[默認值為最大可能的線程數] 
  這個參數用來進行多線程控制,應當輸入系統的核數,如果你希望使用cpu全部的核,就不要輸入這個參數,算法會自動檢測。

  學習目標參數: 
  1. objective[默認是reg:linear] 
  這個參數定義需要被最小化的損失函數。最常用的值有:binary:logistic二分類的邏輯回歸,返回預測的概率非類別。multi:softmax使用softmax的多分類器,返回預測的類別。在這種情況下,你還要多設置一個參數:num_class類別數目。 
  2. eval_metric[默認值取決於objective參數的取之] 
  對於有效數據的度量方法。對於回歸問題,默認值是rmse,對於分類問題,默認是error。典型值有:rmse均方根誤差;mae平均絕對誤差;logloss負對數似然函數值;error二分類錯誤率;merror多分類錯誤率;mlogloss多分類損失函數;auc曲線下面積。 
  3. seed[默認是0] 
隨機數的種子,設置它可以復現隨機數據的結果,也可以用於調整參數。

 

文章參考:

  1、https://blog.csdn.net/huibeng7187/article/details/77588001

  2、https://blog.csdn.net/github_38414650/article/details/76061893


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM