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.]]
'''
posted @ 2022-01-30 10:51  旁人怎会懂  阅读(1369)  评论(0编辑  收藏  举报