一、一直對xgboost的輸出有些疑惑,這里記錄一下
1.xgboost的predict接口輸出問題(參數pred_leaf、pred_contribs)
2.訓練過程中輸出相關參數的探究(evals、evals_result、verbose_eval)
3.多分類內部原理探究(不涉及源碼)
4.利用gbdt進行特征組合問題(gbdt+lr)
二、導入驗證數據,驗證問題
針對問題1
# 導入數據
import xgboost
from sklearn.datasets import load_iris(多分類), load_breast_cancer(二分類)
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.preprocessing import OneHotEncoder
# 多分類
iris_data = load_iris()
x = iris_data.data
y = iris_data.target # 類別0、1、2
dtrain = xgboost.DMatrix(data=x, label=y, weight=None, missing=None)
params = {
# General Parameters
'booster': 'gbtree'
# Booster Parameters
, 'eta': 0.3
, 'gamma': 0
, 'max_depth': 6
# Task Parameters
, 'objective': 'multi:softmax'
, 'num_class': 3
}
xgb_model = xgboost.train(params=params, dtrain=dtrain, num_boost_round=3)
## 1. 多分類 .predict()接口 直接輸出float32類型的類別實數數組 [0. 0. 0. 0. 1. 2. 2 ]
res = xgb_model.predict(xgboost.DMatrix(data=x[:3]))
print(res)
# [0. 0. 0.]
## 2. 預測接口參數 pred_leaf 輸出每個樣本在所有樹中的葉子節點
res = xgb_model.predict(xgboost.DMatrix(data=x), pred_leaf=True)[:3]
print(res)
# [[1. 1. 3. 1. 1. 3. 1. 1. 3.]
# [1. 1. 3. 1. 1. 3. 1. 1. 3.]
# [1. 1. 3. 1. 1. 3. 1. 1. 3.]]
# 3. 預測接口參數 pred_contribs 輸出每個樣本各個特征的貢獻度
res = xgb_model.predict(xgboost.DMatrix(data=x[0].reshape(1,-1)), pred_contribs=True)
print(res) # 鳶尾花數據集共四個特征,輸出4個特征重要性,外加最后一列bias,為啥輸出3行,問題三解決
'''
[[[ 0. 0. 0.96979856 0. 0.49221304]
[ 0.00316561 0.00255702 -0.7801311 0.19311588 0.4988653 ]
[ 0. 0. -0.31247163 -0.2724296 0.48901463]]]'''
## 4. 導出迭代過程邏輯, xgboost 為每一個類別,建立一組樹,樹的個數等於num_class * num_boost_round
xgb_model.dump_model('model.txt')
'''
booster[0]:
0:[f2<2.45000005] yes=1,no=2,missing=1
1:leaf=0.430622011
2:leaf=-0.220048919
booster[1]:
0:[f2<2.45000005] yes=1,no=2,missing=1
1:leaf=-0.215311036
2:[f3<1.75] yes=3,no=4,missing=3
3:[f2<4.94999981] yes=5,no=6,missing=5
5:[f3<1.54999995] yes=9,no=10,missing=9
9:leaf=0.428571463
10:leaf=0.128571421
6:[f3<1.54999995] yes=11,no=12,missing=11
11:leaf=-0.128571451
12:leaf=0.128571421
4:[f2<4.85000038] yes=7,no=8,missing=7
7:leaf=-7.66345476e-09
8:leaf=-0.213812172
...... 共9棵樹= 類別數*訓練輪數
'''
## 5. xgboost可視化輸出,如下圖
graph = xgboost.to_graphviz(xgb_model, num_trees=0) # 指定第num_tree輸出圖像
graph.format = 'png'
graph.view('./xgb_tree')
針對問題2:
# 二分類問題
breast_cancer_data = load_breast_cancer()
x = breast_cancer_data.data
y = breast_cancer_data.target # 類別 0,1
# 1. xgboost原接口訓練方式
dtrain = xgboost.DMatrix(data=x, label=y, weight=None, missing=None)
validx = xgboost.DMatrix(data=x[:100], label=y[:100], weight=None, missing=None)
params = {
# General Parameters
'booster': 'gbtree'
# Booster Parameters
, 'eta': 0.3
, 'gamma': 0
, 'max_depth': 6
# Task Parameters
, 'objective': 'binary:logistic'
, 'eval_metric': 'logloss'
}
res = {}
xgb_model = xgboost.train(params=params, dtrain=dtrain, num_boost_round=10,
evals=[(dtrain, 'dtrain'), (validx, 'validx')], # 訓練過程中驗證集
evals_result=res, # 保存訓練過程中的驗證集的結果
verbose_eval=2 # 每隔幾輪,窗口打印訓練過程中的
)
## 針對 verbose_eval參數,訓練過程中,打印驗證集的結果,便於調試
# [0] dtrain-logloss:0.46043 validx-logloss:0.47871
# [2] dtrain-logloss:0.24233 validx-logloss:0.26559
# [4] dtrain-logloss:0.14270 validx-logloss:0.16211
# [6] dtrain-logloss:0.08949 validx-logloss:0.10722
# [8] dtrain-logloss:0.06163 validx-logloss:0.07396
# [9] dtrain-logloss:0.05215 validx-logloss:0.06349
## 針對 evals_result參數,保存訓練結果,用於記錄訓練過程
print(f'訓練過程中evals參數中驗證集每輪評估效果:\n{res}')
# 訓練過程中evals參數中驗證集每輪評估效果:
# {'dtrain': OrderedDict([('logloss', [0.460426, 0.327564, 0.24233, 0.18487, 0.142699, 0.11199, 0.089492, 0.074096, 0.061629, 0.052155])]),
# 'validx': OrderedDict([('logloss', [0.47871, 0.345854, 0.265594, 0.208941, 0.16211, 0.133699, 0.107224, 0.089368, 0.073962, 0.063492])])}
## 二分類輸出結果*(不是輸出0、1目標分類,而是輸出類似logisticregressor的幾率或概率)
print(f'predict接口輸出形式:{xgb_model.predict(dtrain)[:3]}')
# predict接口輸出形式:[0.07583217 0.02762461 0.02571429]
#2. xgboost 中sklraen形式的接口
xgb = xgboost.XGBClassifier()
xgb.fit(x, y)
print(f'此時predict接口直接輸出預測類別{xgb.predict(x[:3])}')
print(f'此時predict_proba接口直接輸出預測概率{xgb.predict_proba(x[:3])}')
針對問題三
# 根據問題1,得到的訓練迭代過程model.txt和樣本所在葉子節點,
# 1.對第一個樣本類別為0,葉子節點[[1. 1. 3. 1. 1. 3. 1. 1. 3.],計算每棵樹的結果
'''
[[ 第1棵樹 0.43 第2棵樹 0.215 第3棵樹 -0.219]
[ 第4棵樹 0.29 第5棵樹 0.191 第6棵樹 -0.195]
[ 第7棵樹 0.236 第8棵樹 -0.175 第9棵樹 -0.18 ]]
'''
# 2.針對最后一個樣本類別2,葉子節點[[2. 8. 2. 2. 8. 10. 2. 8. 10.]]]
'''
[[ 第1棵樹 -0.22 第2棵樹 -0.213 第3棵樹 0.402]
[ 第4棵樹 -0.196 第5棵樹 -0.191 第6棵樹 0.297]
[ 第7棵樹 -0.181 第8棵樹 -0.174 第9棵樹 0.237]]
'''
# 3.對類別為0的樣本和類別為2的樣本,對樹表垂直方向上求sum
'''
類別為0的樣本 sum = [0.956 0.231 -0.594] 經過softmax [0.5894, 0.2855, 0.1251] ≈ [1,0,0]
類別為2的樣本 sum = [-0.597 -0.578 0.936] 經過softmax [0.1503, 0.1532, 0.6964] ≈ [0,0,1]
一般原理上經過softmax,實際代碼上直接求取sum里最大值對應的類別
'''
# 4.結論:
'''
xgb針對多分類是采用的多個二分類實現的(本類為1,其他類為0),所以參數num_boost_round=3,卻出現9棵樹,每個類別訓練了一次(源碼我並未驗證)
'''
針對問題四
# 使用xgbt進行特征的非線性組合(+可配合lr使用)
res = xgb_model.predict(xgboost.DMatrix(data=x), pred_leaf=True)
onehot = OneHotEncoder()
res = onehot.fit_transform(res).toarray()
print(res.shape) # (150, 42) 鳶尾花數據集150樣本*9棵樹一共42個葉子節點
'''
[[1. 0. 1. ... 0. 0. 0.]
[1. 0. 1. ... 0. 0. 0.]
[1. 0. 1. ... 0. 0. 0.]
...
[0. 1. 0. ... 0. 0. 1.]
[0. 1. 0. ... 0. 0. 1.]
[0. 1. 0. ... 0. 0. 1.]]
'''