前言
集成學習介紹
Boosting簡介
GBM的一個例子是梯度提升樹(Gradient Boosted Tree,GBT),它使用決策樹作爲估計,採用負梯度下降的方法來進行迭代。它可以採用不同的損失函數解決不同的問題(迴歸,分類,風險建模等),評估它的梯度,並近似它與一個簡單的樹(分階段地,最大限度地減少整體誤差)。
以Boosting族算法最註明的代表AdaBoost(Adaptive Boosing)爲例(PS:好多機器學習崗位都會有熟悉AdaBoost優先的描述,這是博主看了好多崗位之後發現的,當然頂會論文優先肯定是最重要的。),AdaBoost是一種特殊的情況下,使用指數損失函數的GBT。描述如下圖所示:
簡單Adaboost學習
stumpClassify()函數是通過閾值比較對數據進行分類的,有4個參數值。所有的閾值一邊的數據都會分到類別-1,另外一邊的數據分到類別+1。該函數通過數組過濾來實現,首先將返回數組的第一維數據的長度值(也就是行數)設置爲1,然後將所有滿足不等式要求的設置爲-1,不等式可以任意切換。該函數用於測試是否有某個值小於或者大於我們正在測試的閾值。
完整Adaboost算法實現
1.3 Bagging和隨機森林(random forest)
1.4 Boosting基本方法對比
現在讓我們來看看如何在實踐中快速的應用該類方法。上節內容介紹的是簡單的函數程序,這次我們直接採用現有的包解決實際問題。
本節內容中採用scikit- learn包提供的所有包。首先導入所有需要的庫(本節運行在linux的notebooks)。
準備數據
在本節所有的例子中,我們將討論二分類問題作爲測試。生成20維人工數據集,包含1000個樣本,其中8個特徵包含信息,3個冗餘,2個重複。
然後我們採用split將數據分割成訓練/測試部分,這對於所有方法的驗證是有必要的。
在深入研究算法之前,讓我們執行一個目標變量分佈的檢查以確保數據的完整性。
(1)我們首先採用決策樹方法來進行預測,首先創建一個決策樹。使用訓練數據進行學習,並使用測試樣本對結果進行評估。
我們可以看到兩個明顯的結果:
1、Loss值有些偏高(因爲決策樹的葉子輸出爲0或1,這在預測錯誤時會有嚴重的懲罰。但是accuracy分數相當不錯,)
我們來檢查一下前幾個預測的輸出,可以看到5個分類中只有2個實例被正確分類。
(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 評估器。我們通過該函數尋找準確最高的組合。
如果有很多結果,我們可以手動過濾它們以獲得最好的組合。
尋找最佳參數是一個迭代過程。我們應該從粗粒度的開始進行優化,然後轉向更詳細的參數進行優化。
(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類(這也是我們需要做的真正的問題)。另一方面,分類器有時會錯誤地將負面情況分類爲正(產生所謂的假陽性)。