Adaboost/Xgboost學習及實踐

前言

博主最近因爲一些雜事,最近忙於看CVPR17的相關進展,所以沒有怎麼進入深入的學習。近期準備寫一下目前比較火的Xgboost算法。


學習Xgboost算法之前,先普及一下數據挖掘的小知識作爲參考。國際權威的學術組織the IEEE International Conference on Data Mining (ICDM) 2006年12月評選出了數據挖掘領域的十大經典算法:C4.5, k-Means, SVM, Apriori, EM, PageRank, AdaBoost, kNN, Naive Bayes, and CART[1]。這些算法可以廣泛的應用在模式識別,人工智能,大數據,數據統計,機器學習方面,而且都很經典。其實不止是選中的十大算法,其實參加評選的18種算法,隨便拿出一種來都可以稱得上是經典算法,它們在數據挖掘領域都產生了極爲深遠的影響。

集成學習介紹

這次介紹的Xgboost算法和被評選的AdaBoost都屬於Boosting算法,而Boosting算法屬於集成學習的一種方法。集成學習(ensemble learning)是目前非常火的機器學習方法[2,3]。它本身不是一個單獨的機器學習算法,而是通過構建並結合多個機器學習器來完成學習任務。也就是我們常說的“博採衆長”。集成學習可以用於分類問題集成,迴歸問題集成,特徵選取集成,異常點檢測集成等等,可以說所有的機器學習領域都可以看到集成學習的身影。集成學習中,同一類型的個體學習器集成是“同質”的,同質集成的個體學習器也叫基學習器(base learner)。集成包含不同類型的個體學習器,例如包含神經網絡和決策樹等,這樣的集成就是“異質”的。異質集成的個體學習器由不同的學習算法生成,這時就不再有基學習算法;個體學習器也被稱爲“組件學習器”或直接叫個體學習器。
目前集成學習分爲兩大類,一類是個體學習器間存在強依賴關係、必須串行生成的序列化方法,以及個體學習器間不存在強依賴關係、可同時生成的並行化方法;前者的代表就是Boosting,後者的代表是Bagging和“隨機森林”(Random Forest)。
 
集成學習示意圖

Boosting簡介

Boosting是一族可將弱學習器提升爲強學習器的算法。這族算法的工作機制類似:先從初始訓練集訓練出一個集學習器,再根據基學習器的表現對訓練樣本分佈進行調整,使得先前基學習器做錯的訓練樣本在後續受到更多關注(權值更大),然後基於調整後的樣本分佈來訓練下一個基學習器;如此重複進行,直至基學習器數目達到制定的值T,最終將T個基學習器進行加權結合。目前有很多種類,如AdaBoost、Generalized Boosted Models、XGBoost等。我們可以利用這樣一個事實:損失函數可以表示爲一個合適的形式進行優化(由於階段性的可加性)。這就產生了一類廣義Boosting算法,簡稱廣義Boosting模型(Generalized Boosted Models,GBM)。
GBM的一個例子是梯度提升樹(Gradient Boosted Tree,GBT),它使用決策樹作爲估計,採用負梯度下降的方法來進行迭代。它可以採用不同的損失函數解決不同的問題(迴歸,分類,風險建模等),評估它的梯度,並近似它與一個簡單的樹(分階段地,最大限度地減少整體誤差)。
以Boosting族算法最註明的代表AdaBoost(Adaptive Boosing)爲例(PS:好多機器學習崗位都會有熟悉AdaBoost優先的描述,這是博主看了好多崗位之後發現的,當然頂會論文優先肯定是最重要的。),AdaBoost是一種特殊的情況下,使用指數損失函數的GBT。描述如下圖所示:
 
具體的公式推導可參考周志華老師的機器學習這本書,很基礎。這裏面的需要強調的是Boosting算法要求基學習器對特定的數據分佈進行學習,可以通過“重賦權法”(re-weighting)實施(上圖所示的就是該方法)。而對於無法接受帶權樣本的基學習器算法,可以通過“重採樣法”(re-sampling)來處理,即在每一輪的學習中,根據樣本分佈對訓練集進行採樣,再用重採樣而得到的樣本集對基學習器進行訓練。一般兩種方法沒有顯著的優劣差別。但是Boosting算法在訓練每一輪都要對當前生成的基學習器進行檢查是否滿足基本條件(是否比隨機猜測好),一旦條件不滿足,該基學習器就會拋棄,學習過程停止,最終導致集成只包含很少的基學習器而性能不佳。若採用“重採樣法”,可獲得重啓動的機會避免訓練過早停止,即根據當前分佈重新對訓練樣本進行採樣,再基於新的採樣結果進行訓練。

簡單Adaboost學習

然後接下來我們根據Python3.6(博主小本本用的Python3.6的,另外一個遊戲本是2.7+3.6,但是家裏沒地方同時用)的具體程序,來學習一下基於單層決策樹的AdaBoost訓練過程。
新建adaboost.py腳本,先import numpy裏的所有功能函數。
from numpy import *
構建Adaboost函數stumpClassify、buildStump。

stumpClassify()函數是通過閾值比較對數據進行分類的,有4個參數值。所有的閾值一邊的數據都會分到類別-1,另外一邊的數據分到類別+1。該函數通過數組過濾來實現,首先將返回數組的第一維數據的長度值(也就是行數)設置爲1,然後將所有滿足不等式要求的設置爲-1,不等式可以任意切換。該函數用於測試是否有某個值小於或者大於我們正在測試的閾值。


buildStump()函數將會遍歷stumpClassify()函數所有的可能輸入值,並找到數據集上最佳的單層決策樹。這裏的“最佳”是根據參數D來定義的,在下一個函數中會有說明,是數據集的權重向量。該函數構建一個bestStump的空字典,這個字典儲存給定權重向量D時所得到的最佳單層決策樹的相關信息。變量numSteps用於在特徵的所有可能值上進行遍歷。變量minError一開始初始化爲無窮大,之後用於尋找可能的最小錯誤率。
三層嵌套的for循環是程序最主要的部分。第一層for循環在數據集的所有特徵上遍歷。考慮到數值型的特徵,我們就可以通過計算最小值和最大值來了解應該需要多大的步長。然後,第二層for循環再在這些值上遍歷。甚至將闌值設置爲整個取值範圍之外也是可以的。因此,在取值範圍之外還應該有兩個額外的步驟。最後一個for循環則是在大於和小於之間切換不等式。
在嵌套的三層for循環之內,我們在數據集及三個循環變量上調用。stumpClassify()函數。基於這些循環變量,該函數將會返回分類預測結果。接下來構建一個列向量errArr,如果predictedVals中的值不等於labelMat中的真正類別標籤值,那麼errArr的相應位置爲1。將錯誤向量errArr和權重向量D的相應元素相乘並求和,就得到了數值weightedError。這就是AdaBoost和分類器交互的地方。這裏,我們是基於權重向量D而不是其他錯誤計算指標來評價分類器的。如果需要使用其他分類器的話,就需要考慮D上最佳分類器所定義的計算過程。
程序接下來輸出所有的值。雖然這一行後面可以註釋掉,但是它對理解函數的運行還是很有幫助的。最後,將當前的錯誤率與已有的最小錯誤率進行對比,如果當前的值較小,那麼就在詞典bestStump中保存該單層決策樹。字典、錯誤率和類別估計值都會返回給AdaBoost算法。
運行了簡單的一個test,結果如上。

完整Adaboost算法實現

對上述的adaboost.py增加新的功能函數adaBoostTrainDS。
 
AdaBoost算法的輸人蔘數包括數據集、類別標籤以及迭代次數numIt,其中numIt是在整個AdaBoost算法中唯一需要用戶指定的參數。我們假定迭代次數設爲9,如果算法在第三次迭代之後錯誤率爲0。那麼就會退出迭代過程,因此,此時就不需要執行所有的9次迭代過程。每次迭代的中間結果都會通過print語句進行輸出。
函數名稱尾部的DS代表的就是單層決策樹(decision stump ),它是AdaBoost中最流行的弱分類器,當然並非唯一可用的弱分類器。上述函數確實是建立於單層決策樹之上的,但是我們也可以很容易對此進行修改以引人其他基分類器。實際上,任意分類器都可以作爲基分類器,前面講到的任何一個機器學習算法都行。上述算法會輸出一個單層決策樹的數組,因此首先需要建立一個新的Python表來對其進行存儲。然後,得到數據集中的數據點的數目m,並建立一個列向量D。
向量D非常重要,它包含了每個數據點的權重。一開始,這些權重都賦予了相等的值。在後續的迭代中,AdaBoost算法會在增加錯分數據的權重的同時,降低正確分類數據的權重。D是一個概率分佈向量,因此其所有的元素之和爲1。0。爲了滿足此要求,一開始的所有元素都會被初始化成1/m。同時,程序還會建立另一個列向量aggClassEst,記錄每個數據點的類別估計累計值。
AdaBoost算法的核心在於for循環,該循環運行numIt次或者直到訓練錯誤率爲0爲止。循環中的第一件事就是利用前面介紹的buildStump()函數建立一個單層決策樹。該函數的輸人爲權重向量D,返回的則是利用D而得到的具有最小錯誤率的單層決策樹,同時返回的還有最小的錯誤率以及估計的類別向量。
接下來,需要計算的則是alpha。該值會告訴總分類器本次單層決策樹輸出結果的權重。其中的語句max(error, 1e-16)用於確保在沒有錯誤時不會發生除零溢出。而後,alpha值加入到bestStump字典中,該字典又添加到列表中。該字典包括了分類所需要的所有信息。
接下來的三行則用於計算下一次迭代中的新權重向量D。在訓練錯誤率爲。時,就要提前結束for循環。此時程序是通過aggClassEst變量保持一個運行時的類別估計值來實現的。該值只是一個浮點數,爲了得到二值分類結果還需要調用sign()函數。如果總錯誤率爲0,則由break語句中止for循環。
整個程序和Adaboost算法的描述圖(最上面)一致。裏面的基學習器可以隨意替換。
運行的簡單的test,結果如下(將buildStump的print註釋了,可以更簡單清晰)。
 

1.3 Bagging和隨機森林(random forest)

Bagging是並行式集成學習方法最著名的代表。從名字即可看出,它是直接基於自助採樣法((bootstrap sampling)的。給定包含m個樣本的數據集,我們先隨機取出一個樣本放入採樣集中,再把該樣本放回初始數據集,使得下次採樣時該樣本仍有可能被選中,這樣,經過m次隨機採樣操作,我們得到含。個樣本的採樣集,初始訓練集中有的樣本在採樣集裏多次出現,有的則從未出現。由下式可知
 
初始訓練集中約有63。2%的樣本出現在採樣集中。
照這樣,我們可採樣出T個含m個訓練樣本的採樣集,然後基於每個採樣集訓練出一個基學習器,再將這些基學習器進行結合。這就是Bagging的基本流程。在對預測輸出進行結合時,Bagging通常對分類任務使用簡單投票法,對迴歸任務使用簡單平均法。若分類預測時出現兩個類收到同樣票數的情形,則最簡單的做法是隨機選擇一個,也可進一步考察學習器投票的置信度來確定最終勝者。Bagging的算法描述如下圖所示。
 
隨機森林(random forest)是Bagging的一個擴展變體,這裏就不多敘述了。周志華老師前一段還出了一個paper,Towards An Alternative to Deep Neural Networks[4],是採用的deep learning加random forest的做法,還是挺有新穎性的,有興趣的可以自己看看。

1.4 Boosting基本方法對比

現在讓我們來看看如何在實踐中快速的應用該類方法。上節內容介紹的是簡單的函數程序,這次我們直接採用現有的包解決實際問題。

本節內容中採用scikit- learn包提供的所有包。首先導入所有需要的庫(本節運行在linux的notebooks)。


準備數據

在本節所有的例子中,我們將討論二分類問題作爲測試。生成20維人工數據集,包含1000個樣本,其中8個特徵包含信息,3個冗餘,2個重複。


然後我們採用split將數據分割成訓練/測試部分,這對於所有方法的驗證是有必要的。


在深入研究算法之前,讓我們執行一個目標變量分佈的檢查以確保數據的完整性。


(1)我們首先採用決策樹方法來進行預測,首先創建一個決策樹。使用訓練數據進行學習,並使用測試樣本對結果進行評估。


我們可以看到兩個明顯的結果:

1、Loss值有些偏高(因爲決策樹的葉子輸出爲0或1,這在預測錯誤時會有嚴重的懲罰。但是accuracy分數相當不錯,)

我們來檢查一下前幾個預測的輸出,可以看到5個分類中只有2個實例被正確分類。



2、樹是複雜的(有大量節點),我們通過image來顯示一下決策樹圖


(2)我們採用Adaboost來對該實例進行預測,我們創建一個運行在1000次迭代上的AdaBoost分類器(創建1000棵樹)。我們採用最流行的單層決策樹(也被稱爲decision stump),跟上節用的一樣,每顆樹根據單一特徵來進行分類。我們也將使用SAMME算法來處理離散數據(base_estimator的輸出爲0或1)。


Loss值遠低於單一決策樹(主要是因爲我們獲得的是概率輸出)。精度是相同的,但是注意到樹的結構要簡單得多。因爲我們創建了1000個單層決策樹。

此外,我們還可以快速查看一下預測值,在5個實例的測試中有4個是正確分類的。


順便來查看一下第一棵樹圖。


在最後的計算中,該樹的錯誤值和重要值(即決策樹權重向量D中的權值)如下,該樹的重要性比較高:


(3)我們採用GBT方法來計算一次,我們構建一個1000棵樹組成的一個梯度提升樹,這1000棵樹中每棵連續的樹都是通過梯度優化來創建的。同樣,我們將把大多數參數留給它們的默認值,只指定樹的最大深度爲1(同樣爲單層決策樹),併爲更智能的計算設置warm_start = True。


得到的結果顯然是所提出的算法中最優的。我們已經得到了最精確的算法,給出了關於分類概率的更合理的預測。


不同的是,GBC(Gradient Boosting Classifier)使用的是以均值-平方誤差作爲標準值的決策樹分類器。這個結果與樹的輸出略有不同——現在葉子包含的是一個預測值。


1.5 XGBoost

Xgboost近幾年比較火,在Kaggle比賽中結構化數據(簡單來說就是數據庫。結構化數據也稱作行數據,是由二維表結構來邏輯表達和實現的數據,嚴格地遵循數據格式與長度規範,主要通過關係型數據庫進行存儲和管理。與結構化數據相對的是不適於由數據庫二維表來表現的非結構化數據,包括所有格式的辦公文檔、XML、HTML、各類報表、圖片和咅頻、視頻信息等。)的競賽項目中取得了非凡的成績,在機器學習領域取得的成績要遠超過其餘機器學習的方法(SVM、logistic regression. etc)

在以決策樹爲基函數的Boosting方法爲BoostingTree方法,此類方法的大多數樹包的問題是,他們不會非常重視正規化問題-他們允許生成許多非常相似的樹木,該類樹有時還會很茂密,這都會導致過擬合問題。

而在GBT中則嘗試加入一些正則化參數的方法這個問題。我們可以:

控制樹結構(最大深度,每葉的最小樣本),

控制學習率,

通過引入隨機性降低方差(stochastic gradient boosting-使用隨機的實例和特徵樣本)等方法。

而我們可以通過使用XGBoosting更加進一步改善正規化問題。

1.5.1 XGBoost理論

XGBoost(極端梯度)是一個更正規化版本的梯度提高樹。這是陳天奇用C++開發的,也爲Python做了接口,R, Julia用於監督學習問題在Kaggle的許多比賽中獲勝。該方法的主要優勢:
良好的偏差(簡單預測)權衡“出箱”,
計算速度快,
包是不斷改進的(作者願意接受從社區的許多性能要求)。
XGBoost的目標函數是通過特定損失函數在所有預測的評估值總和加上所有預測變量的正則化項的總和(以K個樹爲例)。公式中的意味着預測值來自於第k個樹。 


損失函數取決於正在執行的任務(分類,迴歸等),正則化項如下方程:

 
第一部分是負責控制創建葉片的總數,第二部分監視每一個葉片的分數。算法通過使用梯度下降法來進行優化目標,這也產生了如何尋找一個最佳結構的連續樹的問題。

1.5.2 Xgboost實踐

(1)標準接口實踐

我們首先要下載相應的庫文件numpy和xgboost。


加載數據。我們將使用捆綁的Agaricus數據集,下載地址:
https://github.com/dmlc/xgboost/tree/master/demo/data。
這個數據集記錄了不同蘑菇種類的生物屬性,目標是預測它是否有毒。這個數據集包括了在Agaricus和Lepiota家族中有23種蘑菇的假設樣本的描述。每個物種都被認定爲絕對食用,絕對有毒,或不爲人知,不推薦。後者與有毒的一種結合在一起。該指南明確指出,沒有簡單的規則來確定蘑菇的可食性;它由8124個實例組成,具有22個屬性(數字和分類)。目標分類要麼是0,要麼是1,這意味着是一個二分類問題。
重要提示:XGBoost只處理數字變量。
所有的數據都已經爲我們準備好了。分類變量已經被編碼,所有的實例被分成訓練和測試數據集。數據需要存儲在DMatrix對象中,用於處理稀疏數據集。它可以用一下幾種方式填充:
使用libsvm格式txt文件,
使用Numpy 2D數組(最流行),
使用XGBoost二進制緩衝文件
在這種情況下,我們將使用第一種選擇。
Libsvm文件只存儲格式中的非零元素,任何缺失的特徵都表明它的對應值爲0。如下表示:
<label> <feature_a>:<value_a> <feature_c>:<value_c> ...<feature_z>:<value_z>


我們查看一下數據集情況


訓練數據集包含6513行和127列
測試數據集包含1611行和127列

訓練labels如下所示,爲二分類問題。


我們設定好訓練參數,讓我們假設算法參數如下:


爲了訓練分類器,我們簡單地傳遞給它一個訓練數據集,參數列表和關於迭代次數的信息。


我們還可以使用watchlist觀察測試數據集的性能


作出預測


通過簡單的準確率計算以驗證結果。當然,正常過程我們應該對數據的驗證集執行驗證,但在這種情況下,準確性是足夠的。


(2)使用Scikit-learn接口

需要下載如下所需要的庫


使用數據集,和(1)使用的相同的數據集。

scikit- learn包提供了一個方便的函數load_svmlight,可以同時讀取許多libsvm文件,並將它們存儲爲Scipy的稀疏矩陣。


檢查load的數據集


指定訓練參數,所有的參數跟前面的示例相同設置:


開始訓練分類器


開始預測


計算error值


兩種不同接口的Xgboost方法介紹完畢,接下來章節將介紹更深入的學習過程。

1.6 深入學習XGBoost

1、本節內容主要介紹如何區分數據集中的特性的相對重要性。我們可以找出是什麼驅動了樹的分割,以及我們可以在特性工程上做出的一些改進。

裝載相關庫xgboost、seaborn、pandas


裝載數據,和上節所用的數據集相同


我們指定訓練參數-使用5個單層決策樹以及平均學習率。


開始訓練模型,我們同樣採用watchlist查看測試性能


在構建樹的過程中被多次地劃分(我們的例子中只有一次)—這個操作稱爲split。爲了完成split,算法必須計算出哪個是最好的特徵然後去使用。

在那之後,在我們的底部,我們得到樹葉的觀察。

在最終的模型中,這些樹葉對於每棵樹來說應該儘可能的純淨,每一個葉子都應該由一個標籤類組成。

並不是所有的split都同樣重要。基本上,樹的第一個split會對純度產生更大的影響。直觀上,我們理解第一個split做了大部分工作,接下來的split集中在數據集被第一棵樹錯誤地分類的那一部分,這部分工作比較少。

同樣,在Boosting中,我們試圖優化每一輪的錯誤分類(它被稱爲損失)。所以第一棵樹將會做大的工作,下面的樹將會集中在剩下的工作上,這部分工作在之前的樹上沒有正確的學習。

每一次split操作帶來的提升都可以衡量,這就是收穫。

-引用自Kaggle 陳天奇的Kaggle notebook。

讓我們來研究一下樹的樣子:


對於每一個split,我們得到以下細節:
1、這個特徵被用來split,
2、可能的選擇去生成(分支)
3、gain是通過特徵得到的真實提升值。之前的想法是,在特徵X上添加一個新的split到有一些有錯誤分類的分支上,通過增加split到這個特徵後,將會有兩個新的分支,這些每一個分支都會更準確。
4、cover測量與該特徵相關的觀測的相對數量
可視化
希望有更好的方法來弄清楚哪些特徵纔是真正重要的。我們可以使用內置函數plot_importance,它將創建一個根據標準而呈現最重要特性的繪圖。我們將分析每個特徵對所有splits和所有樹的影響,並可視化結果。
查看哪些特徵提供了最多的增益:


我們可以通過引入f–score使得結果更顯而易見。F-score表示了每個特徵上執行的split的次數。


偏差(bias error)和方差(varianceerror)的權衡

接下來我們展示如何處理偏差/方差權衡的可視化,這是常見的機器學習問題。

分類器有兩種常見的誤差——偏差和方差誤差。

偏差是是預測值(估計值)的期望與真實值之間的差異程度,偏差越大,越偏離真實數據。

方差是是預測值的變化範圍,離散程度,也就是離其期望值的距離,方差越大,數據的分佈越分散。

我們所期望的狀態是兩個錯誤都儘可能低。從 ScottFortmann-Roe's blog 的博客上的圖形可以很好地將這個問題可視化。假設目標的中心是完美的模型。我們重複我們的實驗,重創建模型並在相同的數據點上使用它。


欠擬合和過擬合

瞭解了偏差和方差引入的錯誤,我們可以着手處理這些與訓練模型有關的問題。我們將使用從scikit-學習文檔中獲取的圖來幫助我們可視化那些欠擬合和過擬合的問題。

2、爲了量化描述的效果,我們將訓練模型幾次,以選擇不同的參數值。讓我們考慮一下,我們想要找到一個最優的樹數——我們不希望模型非常簡單,但目前我們也不想讓模型過於複雜。

我們將會:

生成複雜的二分類數據集,

使用Scikit-learn包,

使用10次交叉循環驗證對樹的不同值進行建模(n_estimators)訓練

繪圖訓練/測試誤差

從加載所需的庫開始,設置隨機的種子數

然後生成人工數據集

我們將分爲10折交叉驗證 (相同的標籤平均分佈在每個交叉集中)進行測試

讓我們來看看樹的數量如何影響預測的準確性:

顯示驗證曲線圖:



看看這個圖,我們可以得出以下結論:

在增加新樹的同時,訓練分數也在不斷增加,但從某種程度上來說,交叉驗證的分數是固定的

方差是最低的,低於25棵樹的偏差很高,

從大約25棵樹中,方差越來越大,而交叉驗證值偏倚保持穩定(沒有必要增加額外的樹/複雜度)

我們可以看到,模型在增加複雜度時保持了穩定的方差

我們可以假設在n_estimators = 50中實現模型的穩定。但是模型的方差仍然很大。

我們可以通過那些方式來進行優化這些問題呢?

(1)處理高方差

如果模型太過於複雜,我們可以嘗試:

用更少的功能(即,特徵選擇),

使用更多的訓練樣本(即,人工生成的),

增加規則化(增加懲罰對額外的複雜性)

在XGBoost中,我們可以嘗試:

降低每棵樹的深度(max_depth)

增加min_child_weight參數,

增加γ(gamma)參數,

使用subsample,colsample_bytree參數添加更多的隨機性,

增加lambda和alpha正則化參數

(2)處理高偏差

如果模型太簡單的話:

添加更多的功能(即,更好的功能工程),

更復雜的模型

減少正規化

在XGBoost中,你可以這樣做:

增加每棵樹的深度(max_depth)

減少min_child_weight參數,

減少γ參數,

減少lambda和alpha正則化參數

讓我們稍微調整一下參數。我們將增加一些隨機性——我們將使用70%隨機選擇的樣本和60%隨機選擇的特徵。這應該有助於減少方差。爲了減少偏差(更大的準確性),嘗試爲每棵樹增加一個額外的等級。




我們得到了一個更小的方差模型,偏差也有所減小。

3、超參數調優

我們學習機器學習的都知道,模型優化,調參都是一門技巧活(好多時候也是瞎蒙憑感覺),有很多的可調參數。每一個參數都有可能導致不同的輸出。問題是哪種組合結果最好呢。

下面的notebook將向您展示如何使用Scikit-learn模塊爲您的模型找出最佳的參數。

首先import 相關庫

生成人工數據集以及定義交叉驗證參數

(1)傳統網格搜索

在網格搜索中,我們首先定義一個包含我們想要測試的參數值的字典。所有的組合都將被評估。

爲固定參數添加字典。

創建一個GridSearchCV 評估器。我們通過該函數尋找準確最高的組合。

在運行計算之前,我們應該知道我們將創建有3 * 4 * 3 * 10 = 360 個模型來測試所有組合。我們應該對將要的計算有大致的估計。
現在,我們可以查看所有獲得的分數,並手動查看什麼是重要的,什麼是不重要的。快速瀏覽一下,就會發現更多的n_estimator的準確性更高。

如果有很多結果,我們可以手動過濾它們以獲得最好的組合。

尋找最佳參數是一個迭代過程。我們應該從粗粒度的開始進行優化,然後轉向更詳細的參數進行優化。

(2)隨機網格搜索

當參數的數量和它們的值越來越大時,傳統的網格搜索方法很快就變得無效了。一個可能的解決方案可能是隨機從它們的分佈中選取某些參數。雖然這不是一個完美的解決方案,但值得一試。

創建一個參數分佈字典:


初始化RandomizedSearchCV,隨機選取10個參數組合。通過這種方法,我們可以輕鬆地控制已測試模型的數量。


生成分類器


再次看一下選擇的參數和它們的準確性分數:


最佳的評估器、參數值和得分


4.結果評估

在本節notebook中,我們將學習如何度量算法的性能。

開始準備相關的庫文件


加載agaricus數據集:


設置訓練參數——我們將使用平均學習率的5個決策樹。


在訓練這個模型之前,我們還可以指定watchlist數組來觀察它在兩個數據集上的性能。


使用預定義的評估指標

哪些指標是直接可用的呢?

已經有一些預定義的評估標準。您可以在訓練模型時使用它們作爲eval_metric參數的輸入。

rmse -均方根誤差,

mae-平均絕對誤差,

logloss——負對數損失函數

error-二分類錯誤率。它採用(錯誤的情況)/(所有情況)來計算的。

merror -多類分類錯誤率。計算的方式爲(錯誤的情況)/ (所有情況),

auc –曲線下面積

ncg -歸一化的貼現累計收益,

map-平均平均精度

默認情況下將使用error度量。


如果需要修改評估標準的話,只需將eval_metric參數指定到params字典。


當然也可以同時使用多個評估標準


創建自定義評價標準值

爲了創建我們自己的評估指標,唯一需要做的是創建一個方法,採用兩個參數——預測概率和DMatrix對象持有的數據。

在下面的實例中,我們的分類度量將簡單地計算錯誤分類示例的數量,默認的概率p>0.5的類是積極性的。如果我們想要的概率值作爲閾值,那就可以改變這個參數。

當錯誤分類的例子越來越少的時候,算法就會變得越來越好。記住在訓練時也要設置參數maximize= False


我們可以發現,即使params字典持有eval_metric的key值,這些值也被feval忽略和覆蓋。

提取評價結果

我們可以通過聲明保存值的字典,並將其作爲eval_result參數的參數傳遞來獲得評估分數。


我們可以重新用這麼參數來進行後續操作,比如print、plot等


早期停止

在選擇合適的樹數量時,有一個很好的優化技巧。

我們可以訓練該模型直到某個驗證分數時停止繼續優化。驗證時需要減少每個early_stopping_rounds來繼續訓練。這種方法的結果更簡單,因爲樹的最低數量將被找到(簡單性)。

在下面的實例中,將創建總數爲1500棵樹,但是如果驗證分數在最近的10次迭代中沒有改善,我們就告訴它停止。


當使用early_stopping_rounds參數時,模型將會產生有3個額外的字段- bst.best_score,bst。best_iteration bst.best_ntree_limit。


交叉驗證結果

自帶的包提供了一個用於交叉驗證結果的選項(但不像Sklearn包那樣複雜)。下一個輸入將顯示基本的執行方法。注意,我們只傳遞一個DMatrix參數,而我們可以將訓練集和測試集合併到一個對象中,以獲得更多的訓練樣本將是有利的。


注意:

默認情況下,我們得到一個pandas數據幀對象(可以用as_pandas參數來改變),

通過作爲參數傳遞指標(允許使用多值),

我們可以使用自己的評估指標(參數中的feval和maximize),

我們可以使用早期停止特性(參數early_stopping_rounds)

5、處理缺失值

下面的notebook展示了XGBoost對缺失值的處理。兩種方法——原包接口和Sklearn包針對缺少的數據集進行測試。

缺失值經常在真實的數據集中出現。處理丟失值上,沒有規則能夠適用於所有的情況,因爲缺少值的原因有很多種。

首先import所有的庫


讓我們準備一個沒有缺失值的有效數據集。有10個樣本,每一個樣本將包含5個隨機生成的特徵,每個樣本根據5個特徵划進行二分類問題。


我們增加一些缺失值


生成目標變量,隨機生成0/1的目標label


(1)原包接口

在本例中,我們將檢查原包接口如何處理丟失的數據。從專門的默認參數開始。


在第一個實例中,我們將創建一個有效的DMatrix(帶有所有值),看看它是否可行,然後再重複這個過程。


交叉驗證結果


輸出顯然沒有任何意義,因爲數據完全是隨機的。

當創建DMatrix時,我們必須明確表示它丟失了什麼。有時可能是0,999或者是其他。在我們的例子中是Numpy 格式下的NAN來表示的。增加missing參數爲DMatrix構造函數來處理它。


然後進行交叉驗證


雖然因爲隨機的數據導致這個結果跟之前一樣,但是這個方法是適用於缺失值處理的。

在XGBoost包中,選擇的是軟方法來處理缺失值。

當使用帶有缺失值的特性來進行拆分時,XGBoost將爲缺失值分配一個方向,而不是數值。

具體地說,XGBoost將所有的帶有缺失值的數據點分別指向左方和右方,然後在關係到目標時選擇更高增益的方向。

(2)Sklearn

下面的部分展示瞭如何使用Sklearn接口驗證相同的內容。

首先定義參數並創建一個估計對象。


用完整的數據集交叉驗證結果。因爲我們只有10個樣品,所以我們只需要做2折的交叉驗證。


我們得到了一些分數,我們不會深入研究它的解釋。

看看目標是否也有缺失的值

這兩種方法都適用於缺少的數據集。缺失情況下,Sklearn包處理帶有np.nan作爲缺失數據。(如果使用不同的缺失值標記,就需要額外的預處理)。

6、處理不平衡數據集

處理不平衡數據集

在現實世界的問題中,有很多例子處理不平衡的目標類別。想象一下醫療數據,在成千上萬個陰性(正常)的例子中,只有少數陽性的例子。另一個例子可能是分析欺詐交易,在這種交易中,實際的欺詐只佔所有可用數據的一小部分。

不平衡數據指的是分類問題,其中的類不是均勻分佈的。

一般建議:

當接近不平衡的數據集時,這些都是常用的策略:

收集更多的數據,

使用更好的評估指標(error、AUC、F1、Kappa,…)

嘗試過抽樣少數類別或低抽樣多數類別,

生成少數羣體的人工樣本(SMOTE算法)

在XGBoost中,我們可以嘗試如下方法:

確保參數min_child_weight很小(因爲葉節點可以有較小的大小組),默認設置爲min_child_weight = 1,

對DMatrix進行調整時爲特定的樣本分配更多的權重,

使用set_pos_weight參數控制正負權重的平衡,

使用AUC評價

實踐部分,首先裝載必要的庫


我們將使用一個函數來生成二進制分類的數據集。爲了保證它不平衡使用權重參數。在這種情況下,將會有200個樣本,每個樣本有5個特徵,但只有10%(大約20個樣本)是陽性的。這讓問題變得更加棘手。


將創建的數據劃分爲訓練集和測試集。記住,這兩個數據集在分佈上都應該是相似的。


基準模型

在這種方法中,試着完全忽略分類是不平衡的事實,看看它是如何執行的。爲訓練和測試數據創建DMatrix


假設我們將創建15個單層決策樹,解決二分類問題,每個決策樹將會非常積極地進行訓練。
這些參數也將在連續的例子中使用。


訓練booster並做出預測

生成結果


我們還可以使用3個不同的評估指標來展示模型: 


自定義權重

讓我們指定正例樣本有5x的權重,並在創建DMatrix時添加這些信息。


訓練分類器並進行預測


生成結果


我們在這裏做了一個指標上的權衡。我們現在可以更好地對少數羣體進行分類,但整體的準確性和精度卻降低了。我們可以測試多種權重組合,看看哪個最有效。

使用scale_pos_weight參數

我們可以通過計算負性和正例之間的比例,並將其設置爲scale_pos_weight參數,來實現手動分配權重的過程。

初始化數據集


計算兩個類之間的比率,並將其賦值給一個參數。


生成結果


我們可以看到,在本例中使用scale_pos_weight參數手動來增減權重,這樣做的效果更好。我們現在可以完美地分類所有的posivie類(這也是我們需要做的真正的問題)。另一方面,分類器有時會錯誤地將負面情況分類爲正(產生所謂的假陽性)。

 


後記:其實目前Deep learning很火熱,現在採用的一些tricks大部分都是機器學習中的小理論,但非常有實用價值。博主一個跨專業來學習此行業的學生黨,自學之路也算是很艱辛了,對比其他平臺的學生,有很好的資源(硬件、師資、交流平臺等等),每每看到羣裏的人討論一些tricks和最新的paper,博主都暗罵自己不努力。風物長宜放眼亮,未來如何沒有人能夠說得準,所有走過的路也未必都是彎路,努力總會有收穫的。


參考文獻
[1]Wu X, Kumar V, Ross Quinlan J, et al. Top 10 algorithms in data mining[J]. Knowledge & Information Systems, 2007, 14(1):1-37.
[2]http://www.cnblogs.com/pinard/p/6131423.html
[3]周志華,機器學習,清華大學出版社。2016
[4]Zhou Z H, Feng J. Deep Forest: Towards An Alternative to Deep Neural Networks[J]. 2017.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章