xgboost的predict接口輸出問題以及相關參數的探究(evals、evals_result、verbose_eval、pred_leaf、pred_contribs)、利用gbdt進行特征組合問題(gbdt+lr)


一、一直對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.]]
'''


免責聲明!

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



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