XGBoost Plotting API以及GBDT组合特征实践
XGBoost Plotting API以及GBDT組合特征實踐
寫在前面:
最近在深入學習一些樹模型相關知識點,打算整理一下。剛好昨晚看到余音大神在Github上分享了一波 MachineLearningTrick,趕緊上車學習一波!大神這波節奏分享了xgboost相關的干貨,還有一些內容未分享….總之值得關注!我主要看了:Xgboost的葉子節點位置生成新特征封裝的函數。之前就看過相關博文,比如Byran大神的這篇:http://blog.csdn.net/bryan__/article/details/51769118,但是自己從未實踐過。本文是基于bryan大神博客以及余音大神的代碼對GBDT組合特征實踐的理解和拓展,此外探索了一下XGBoost的Plotting API,學習為主!
官方API介紹:?
http://xgboost.readthedocs.io/en/latest/python/python_api.html#module-xgboost.sklearn
1.利用GBDT構造組合特征原理介紹
從byran大神的博客以及這篇利用GBDT模型構造新特征中,可以比較好的理解GBDT組合特征:
論文的思想很簡單,就是先用已有特征訓練GBDT模型,然后利用GBDT模型學習到的樹來構造新特征,最后把這些新特征加入原有特征一起訓練模型。構造的新特征向量是取值0/1的,向量的每個元素對應于GBDT模型中樹的葉子結點。當一個樣本點通過某棵樹最終落在這棵樹的一個葉子結點上,那么在新特征向量中這個葉子結點對應的元素值為1,而這棵樹的其他葉子結點對應的元素值為0。新特征向量的長度等于GBDT模型里所有樹包含的葉子結點數之和。
舉例說明。下面的圖中的兩棵樹是GBDT學習到的,第一棵樹有3個葉子結點,而第二棵樹有2個葉子節點。對于一個輸入樣本點x,如果它在第一棵樹最后落在其中的第二個葉子結點,而在第二棵樹里最后落在其中的第一個葉子結點。那么通過GBDT獲得的新特征向量為[0, 1, 0, 1, 0],其中向量中的前三位對應第一棵樹的3個葉子結點,后兩位對應第二棵樹的2個葉子結點。?
在實踐中的關鍵點是如何獲得每個樣本在訓練后樹模型每棵樹的哪個葉子結點上。之前知乎上看到過可以設置pre_leaf=True獲得每個樣本在每顆樹上的leaf_Index,打開XGBoost官方文檔查閱一下API:
原來這個參數是在predict里面,在對原始特征進行簡單調參訓練后,對原始數據以及測試數據進行new_feature= bst.predict(d_test, pred_leaf=True)即可得到一個(nsample, ntrees) 的結果矩陣,即每個樣本在每個樹上的index。了解這個方法之后,我仔細學習了余音大神的代碼,發現他并沒有用到這個,如下:
可以看到他用的是apply()方法,這里就有點疑惑了,在XGBoost官方API并沒有看到這個方法,于是我去SKlearn GBDT API看了下,果然有apply()方法可以獲得leaf indices:?
因為XGBoost有自帶接口和Scikit-Learn接口,所以代碼上有所差異。至此,基本了解了利用GBDT(XGBoost)構造組合特征的實現方法,接下去按兩種接口實踐一波。
2.利用GBDT構造組合特征實踐
發車發車~
(1).包導入以及數據準備
from sklearn.model_selection import train_test_split from pandas import DataFrame from sklearn import metrics from sklearn.datasets import make_hastie_10_2 from xgboost.sklearn import XGBClassifier import xgboost as xgb#準備數據,y本來是[-1:1],xgboost自帶接口邀請標簽是[0:1],把-1的轉成1了。 X, y = make_hastie_10_2(random_state=0) X = DataFrame(X) y = DataFrame(y) y.columns={"label"} label={-1:0,1:1} y.label=y.label.map(label) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)#劃分數據集 y_train.head()- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
| 1 |
| 0 |
| 1 |
| 1 |
| 1 |
(2).XGBoost兩種接口定義
#XGBoost自帶接口 params={'eta': 0.3,'max_depth':3, 'min_child_weight':1,'gamma':0.3, 'subsample':0.8,'colsample_bytree':0.8,'booster':'gbtree','objective': 'binary:logistic','nthread':12,'scale_pos_weight': 1,'lambda':1, 'seed':27,'silent':0 ,'eval_metric': 'auc' } d_train = xgb.DMatrix(X_train, label=y_train) d_valid = xgb.DMatrix(X_test, label=y_test) d_test = xgb.DMatrix(X_test) watchlist = [(d_train, 'train'), (d_valid, 'valid')]#sklearn接口 clf = XGBClassifier(n_estimators=30,#三十棵樹learning_rate =0.3,max_depth=3,min_child_weight=1,gamma=0.3,subsample=0.8,colsample_bytree=0.8,objective= 'binary:logistic',nthread=12,scale_pos_weight=1,reg_lambda=1,seed=27)model_bst = xgb.train(params, d_train, 30, watchlist, early_stopping_rounds=500, verbose_eval=10) model_sklearn=clf.fit(X_train, y_train)y_bst= model_bst.predict(d_test) y_sklearn= clf.predict_proba(X_test)[:,1]- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 1
- 2
- 1
- 2
(3).生成兩組新特征
print("原始train大小:",X_train.shape) print("原始test大小:",X_test.shape)##XGBoost自帶接口生成的新特征 train_new_feature= model_bst.predict(d_train, pred_leaf=True) test_new_feature= model_bst.predict(d_test, pred_leaf=True) train_new_feature1 = DataFrame(train_new_feature) test_new_feature1 = DataFrame(test_new_feature) print("新的特征集(自帶接口):",train_new_feature1.shape) print("新的測試集(自帶接口):",test_new_feature1.shape)#sklearn接口生成的新特征 train_new_feature= clf.apply(X_train)#每個樣本在每顆樹葉子節點的索引值 test_new_feature= clf.apply(X_test) train_new_feature2 = DataFrame(train_new_feature) test_new_feature2 = DataFrame(test_new_feature)- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 1
- 2
train_new_feature1.head()
- 1
- 1
| 8 | 11 | 9 | 9 | 10 | 8 | 11 | 12 | 9 | 9 | … | 10 | 8 | 10 | 11 | 9 | 10 | 10 | 8 | 11 | 12 |
| 10 | 11 | 9 | 11 | 11 | 9 | 11 | 12 | 9 | 9 | … | 10 | 9 | 11 | 11 | 9 | 10 | 10 | 8 | 11 | 13 |
| 10 | 11 | 9 | 12 | 10 | 9 | 11 | 12 | 9 | 9 | … | 10 | 9 | 14 | 11 | 10 | 13 | 10 | 8 | 11 | 13 |
| 10 | 11 | 9 | 10 | 10 | 9 | 11 | 14 | 9 | 9 | … | 8 | 9 | 11 | 12 | 9 | 10 | 10 | 8 | 13 | 12 |
| 12 | 11 | 9 | 9 | 10 | 7 | 11 | 12 | 9 | 10 | … | 10 | 8 | 13 | 11 | 9 | 10 | 10 | 8 | 12 | 12 |
5 rows × 30 columns
(4).基于新特征訓練、預測
#用兩組新的特征分別訓練,預測#用XGBoost自帶接口生成的新特征訓練 new_feature1=clf.fit(train_new_feature1, y_train) y_new_feature1= clf.predict_proba(test_new_feature1)[:,1] #用XGBoost自帶接口生成的新特征訓練 new_feature2=clf.fit(train_new_feature2, y_train) y_new_feature2= clf.predict_proba(test_new_feature2)[:,1]print("XGBoost自帶接口生成的新特征預測結果 AUC Score : %f" % metrics.roc_auc_score(y_test, y_new_feature1)) print("XGBoost自帶接口生成的新特征預測結果 AUC Score : %f" % metrics.roc_auc_score(y_test, y_new_feature2))- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
3.Plotting API畫圖
因為獲得的新特征是每棵樹的葉子結點的Index,可以看下每棵樹的結構。XGBoost Plotting API可以實現:
(1).安裝導入相關包:?XGBoost Plotting API需要用到graphviz 和pydot,我是Win10 環境+Anaconda3,pydot直接?pip install pydot?或者conda install pydot即可。graphviz 稍微麻煩點,直接pip(conda)安裝了以后導入沒有問題,但是畫圖的時候就會報錯,類似路徑環境變量的問題。?
網上找了一些解決方法,各種試不行,最后在stackoverflow上找到了解決方案:?
http://stackoverflow.com/questions/35064304/runtimeerror-make-sure-the-graphviz-executables-are-on-your-systems-path-aft
http://stackoverflow.com/questions/18334805/graphviz-windows-path-not-set-with-new-installer-issue-when-calling-from-r
需要先下載一個windows下的graphviz 安裝包,安裝完成后將安裝路徑和bin文件夾路徑添加到系統環境變量,然后重啟系統。重新pip(conda) install graphviz ,打開jupyter notebook(本次代碼都在notebook中測試完成)或者Python環境運行以下代碼:
from xgboost import plot_tree from xgboost import plot_importance import matplotlib.pyplot as plt from graphviz import Digraph import pydot#安裝說明: #pip install pydot #http://www.graphviz.org/Download_windows.php #先安裝上面下載的graphviz.msi,安裝,然后把路徑添加到環境變量,重啟下 #然后pip3 install graphviz...竟然就可以了...- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
(2).兩種接口的model畫圖:?上面兩種接口的模型分別保存下來,自帶接口的參數設置更方便一些。沒有深入研究功能,畫出來的圖效果還不是很好。
#model_bst = xgb.train(params, d_train, 30, watchlist, early_stopping_rounds=500, verbose_eval=10) #model_sklearn=clf.fit(X_train, y_train)#model_bst plot_tree(model_bst, num_trees=0) plot_importance(model_bst) plt.show()#model_sklearn: plot_tree(model_sklearn) plot_importance(model_sklearn) plt.show()- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
4.完
余音大神已經把它的代碼封裝好了,可以直接下載調用,點贊。
在實踐中可以根據自己的需求實現特征構造,也不是很麻煩,主要就是保存每個樣本在每棵樹的葉子索引。然后可以根據情況適當調整參數,得到的新特征再融合到原始特征中,最終是否有提升還是要看場景吧,下次比賽打算嘗試一下!
此外,XGBboost Plotting API 之前沒用過,感覺很nice,把每個樹的樣子畫出來可以非常直觀的觀察模型的學習過程,不過本文中的代碼畫出的圖并不是很清晰,還需進一步實踐!
參考資料:文中已列出,這里再次感謝!
http://blog.csdn.net/bryan__/article/details/51769118
https://breezedeus.github.io/2014/11/19/breezedeus-feature-mining-gbdt.html#fn:fbgbdt
https://github.com/lytforgood/MachineLearningTrick
http://xgboost.readthedocs.io/en/latest/python/python_api.html#module-xgboost.core
總結
以上是生活随笔為你收集整理的XGBoost Plotting API以及GBDT组合特征实践的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: gbdt和xgboost区别
- 下一篇: Blending and Bagging