python平台下實現xgboost算法及輸出的解釋


python平台下實現xgboost算法及輸出的解釋

1. 問題描述

​ 近來, 在python環境下使用xgboost算法作若干的機器學習任務, 在這個過程中也使用了其內置的函數來可視化樹的結果, 但對leaf value的值一知半解; 同時, 也遇到過使用xgboost 內置的predict 對測試集進行打分預測, 發現若干樣本集的輸出分值是一樣的. 這個問題該怎么解釋呢? 通過翻閱Stack Overflow 上的相關問題, 以及搜索到的github上的issue回答, 應該算初步對這個問題有了一定的理解, 特來分享!

2. 數據集

​ 在這里, 使用經典的鳶尾花的數據來說明. 使用二分類的問題來說明, 故在這里只取前100行的數據.

from sklearn import datasets iris = datasets.load_iris() data = iris.data[:100] print data.shape #(100L, 4L) #一共有100個樣本數據, 維度為4維 label = iris.target[:100] print label #正好選取label為0和1的數據 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]

3. 訓練集與測試集

from sklearn.cross_validation import train_test_split train_x, test_x, train_y, test_y = train_test_split(data, label, random_state=0)

4. Xgboost建模

4.1 模型初始化設置

import xgboost as xgb dtrain=xgb.DMatrix(train_x,label=train_y) dtest=xgb.DMatrix(test_x) params={'booster':'gbtree', 'objective': 'binary:logistic', 'eval_metric': 'auc', 'max_depth':4, 'lambda':10, 'subsample':0.75, 'colsample_bytree':0.75, 'min_child_weight':2, 'eta': 0.025, 'seed':0, 'nthread':8, 'silent':1} watchlist = [(dtrain,'train')]

4.2 建模與預測

bst=xgb.train(params,dtrain,num_boost_round=100,evals=watchlist) ypred=bst.predict(dtest) # 設置閾值, 輸出一些評價指標 y_pred = (ypred >= 0.5)*1 from sklearn import metrics print 'AUC: %.4f' % metrics.roc_auc_score(test_y,ypred) print 'ACC: %.4f' % metrics.accuracy_score(test_y,y_pred) print 'Recall: %.4f' % metrics.recall_score(test_y,y_pred) print 'F1-score: %.4f' %metrics.f1_score(test_y,y_pred) print 'Precesion: %.4f' %metrics.precision_score(test_y,y_pred) metrics.confusion_matrix(test_y,y_pred)

Out[23]:

AUC: 1.0000 ACC: 1.0000 Recall: 1.0000 F1-score: 1.0000 Precesion: 1.0000 array([[13, 0], [ 0, 12]], dtype=int64)

Yeah, 完美的模型, 完美的預測!

4.3 可視化輸出

#對於預測的輸出有三種方式 ?bst.predict Signature: bst.predict(data, output_margin=False, ntree_limit=0, pred_leaf=False, pred_contribs=False, approx_contribs=False) pred_leaf : bool When this option is on, the output will be a matrix of (nsample, ntrees) with each record indicating the predicted leaf index of each sample in each tree. Note that the leaf index of a tree is unique per tree, so you may find leaf 1 in both tree 1 and tree 0. pred_contribs : bool When this option is on, the output will be a matrix of (nsample, nfeats+1) with each record indicating the feature contributions (SHAP values) for that prediction. The sum of all feature contributions is equal to the prediction. Note that the bias is added as the final column, on top of the regular features.

4.3.1 得分

默認的輸出就是得分, 這沒什么好說的, 直接上code.

ypred = bst.predict(dtest)
ypred

Out[32]:

array([ 0.20081411, 0.80391562, 0.20081411, 0.80391562, 0.80391562, 0.80391562, 0.20081411, 0.80391562, 0.80391562, 0.80391562, 0.80391562, 0.80391562, 0.80391562, 0.20081411, 0.20081411, 0.20081411, 0.20081411, 0.20081411, 0.20081411, 0.20081411, 0.20081411, 0.80391562, 0.20081411, 0.80391562, 0.20081411], dtype=float32)

在這里, 就可以觀察到文章最開始遇到的問題: 為什么得分幾乎都是一樣的值? 先不急, 看看另外兩種輸出.

4.3.2 所屬的葉子節點

當設置pred_leaf=True的時候, 這時就會輸出每個樣本在所有樹中的葉子節點

ypred_leaf = bst.predict(dtest, pred_leaf=True) ypred_leaf

Out[33]:

array([[1, 1, 1, ..., 1, 1, 1], [2, 2, 2, ..., 2, 2, 2], [1, 1, 1, ..., 1, 1, 1], ..., [1, 1, 1, ..., 1, 1, 1], [2, 2, 2, ..., 2, 2, 2], [1, 1, 1, ..., 1, 1, 1]])

輸出的維度為[樣本數, 樹的數量], 樹的數量默認是100, 所以ypred_leaf的維度為[100*100].

對於第一行數據的解釋就是, 在xgboost所有的100棵樹里, 預測的葉子節點都是1(相對於每顆樹).

那怎么看每顆樹以及相應的葉子節點的分值呢?這里有兩種方法, 可視化樹或者直接輸出模型.

xgb.to_graphviz(bst, num_trees=0) #可視化第一棵樹的生成情況

#直接輸出模型的迭代工程 bst.dump_model("model.txt")
booster[0]: 0:[f3<0.75] yes=1,no=2,missing=1 1:leaf=-0.019697 2:leaf=0.0214286 booster[1]: 0:[f2<2.35] yes=1,no=2,missing=1 1:leaf=-0.0212184 2:leaf=0.0212 booster[2]: 0:[f2<2.35] yes=1,no=2,missing=1 1:leaf=-0.0197404 2:leaf=0.0197235 booster[3]: ……

通過上述命令就可以輸出模型的迭代過程, 可以看到每顆樹都有兩個葉子節點(樹比較簡單). 然后我們對每顆樹中的葉子節點1的value進行累加求和, 同時進行相應的函數轉換, 就是第一個樣本的預測值.

在這里, 以第一個樣本為例, 可以看到, 該樣本在所有樹中都屬於第一個葉子, 所以累加值, 得到以下值.

同樣, 以第二個樣本為例, 可以看到, 該樣本在所有樹中都屬於第二個葉子, 所以累加值, 得到以下值.

leaf1   -1.381214 leaf2 1.410950

在使用xgboost模型最開始, 模型初始化的時候, 我們就設置了'objective': 'binary:logistic', 因此使用函數將累加的值轉換為實際的打分:

$$f(x) = 1/(1+exp(-x))$$

 

1/float(1+np.exp(1.38121416)) Out[24]: 0.20081407112186503 1/float(1+np.exp(-1.410950)) Out[25]: 0.8039157403338895

這就與ypred = bst.predict(dtest) 的分值相對應上了.

4.3.2 特征重要性

接着, 我們看另一種輸出方式, 輸出的是特征相對於得分的重要性.

ypred_contribs = bst.predict(dtest, pred_contribs=True) ypred_contribs

Out[37]:

array([[ 0. , 0. , -1.01448286, -0.41277751, 0.04604663], [ 0. , 0. , 0.96967536, 0.39522746, 0.04604663], [ 0. , 0. , -1.01448286, -0.41277751, 0.04604663], [ 0. , 0. , 0.96967536, 0.39522746, 0.04604663], [ 0. , 0. , 0.96967536, 0.39522746, 0.04604663], [ 0. , 0. , 0.96967536, 0.39522746, 0.04604663], [ 0. , 0. , -1.01448286, -0.41277751, 0.04604663], [ 0. , 0. , 0.96967536, 0.39522746, 0.04604663], [ 0. , 0. , 0.96967536, 0.39522746, 0.04604663], [ 0. , 0. , 0.96967536, 0.39522746, 0.04604663], [ 0. , 0. , 0.96967536, 0.39522746, 0.04604663], [ 0. , 0. , 0.96967536, 0.39522746, 0.04604663], [ 0. , 0. , 0.96967536, 0.39522746, 0.04604663], [ 0. , 0. , -1.01448286, -0.41277751, 0.04604663], [ 0. , 0. , -1.01448286, -0.41277751, 0.04604663], [ 0. , 0. , -1.01448286, -0.41277751, 0.04604663], [ 0. , 0. , -1.01448286, -0.41277751, 0.04604663], [ 0. , 0. , -1.01448286, -0.41277751, 0.04604663], [ 0. , 0. , -1.01448286, -0.41277751, 0.04604663], [ 0. , 0. , -1.01448286, -0.41277751, 0.04604663], [ 0. , 0. , -1.01448286, -0.41277751, 0.04604663], [ 0. , 0. , 0.96967536, 0.39522746, 0.04604663], [ 0. , 0. , -1.01448286, -0.41277751, 0.04604663], [ 0. , 0. , 0.96967536, 0.39522746, 0.04604663], [ 0. , 0. , -1.01448286, -0.41277751, 0.04604663]], dtype=float32)

輸出的ypred_contribs的維度為[100,5], 通過閱讀前面的文檔注釋就可以知道, 最后一列是bias, 前面的四列分別是每個特征對最后打分的影響因子, 可以看出, 前面兩個特征是不起作用的.

通過這個輸出, 怎么和最后的打分進行關聯呢? 原理也是一樣的, 還是以前兩列為例.

score_a = sum(ypred_contribs[0]) print score_a # -1.38121373579 score_b = sum(ypred_contribs[1]) print score_b # 1.41094945744

相同的分值, 相同的處理情況.

到此, 這期關於在python上關於xgboost算法的簡單實現, 以及在實現的過程中: 得分的輸出、樣本對應到樹的節點、每個樣本中單獨特征對得分的影響, 以及上述三者之間的聯系, 均已介紹完畢, 知識積累完畢:happy:!


免責聲明!

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



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