1.算法原理介绍
1.1Xgboost简介
xgboost是Boosting算法的其中一种,Boosting算法的思想是许多弱分类器集成在一起,形成一个强分类器。以为xgboost是一种提升树模型,所以他是将许多树模型集成在一起,形成一个很强的分类器。而所用到的树模型则是cart回归树模型。
- xgboost是在GBDT的基础上进行改进,使得更加强大,使用范围更大
- xgboost一般和sklearn一起使用,但是由于sklearn中没有集成Xgboost,所以需要单独安装
- 在安装的时候要注意安装多线程版本
1.2.xgboost的优点
xgboost算法可以给预测模型带来能力的提升。当我们对其表现有很多了解的时候,我们会发现他们有如下优势:
1.2.1正则化
实际上,xgboost是以“正则化提升技术”而闻名。xgboost在代价函数里加入了正则化项,用于控制模型的复杂度。
正则化项里包含了:
- 树的叶子节点个数
- 每个叶子节点上输出的score的L2模的平方和。
- 从Bias-variance tradeoff角度来看,正则化项降低了模型的variance,使得学习出来的模型更加的简单,防止过拟合,这也是xgboost优于传统GBDT的一个特征
1.2.2并行处理
xgboost工具支持并行。众所周知,Boosting算法是串行结构的处理方式,也就是说按照这种顺序的处理是没有办法实现并行处理的。这里要格外的注意xgboost的并行处理,并不是并行的建树。xgboost也是一次迭代完才能进行下一次迭代的(第t次迭代的代价函数里包含)。xgboost的并行是在特征粒度,也就是说每一棵树的构造依然是依赖于前一棵树
决策树的整个建树过程,最耗时耗资源的一个步骤就是对特征值得排序(因为要确定最佳分割点),xgboost的并行处理过程如下:
- 1.预先对数据(特征值)进行排序。
- 2.将排好序的结构保存为block块,在后面的迭代建树过程重复的使用这个结构,可以大大减少计算,这个block结构也使得并行成为了可能。
- 3.进行节点分裂时,并行的计算每个特征的增益,最终选择增益最大的特征去分裂
1.2.3灵活性
xgboost支持用户自定义目标函数和评估函数,只要目标函数二阶可导就行了。它对模型增加了一个全新的维度,所以我们的处理不会受到任何限制。
1.2.4泰勒二阶展开
在工程实际问题的优化设计中,所列的目标函数往往很复杂,为了使问题简化,常常将目标函数在某点邻域展开成泰勒多项式来逼近原函数。
实际上,xgboost使用泰勒二阶展开的目的是,为了自定义Loss,如果按照最小二乘法的损失函数直接推导,同样能够得到陈大佬最终的推导式子:
二阶泰勒展开实际上不是最小二乘法,平方损失函数的二阶泰勒展开 = 最小二乘,但是陈大佬之所以使用泰勒展开,就是为了xgboost库的可扩展性,因为任何Loss函数只要二阶可导,就可以重复使用,关于最小二乘法的任何推导,而且泰勒展开的本质就是尽量去模仿一个函数,而二阶泰勒展开已经足够去近似大量的Loss函数了,最经典还有基于分类的对数似然Loss函数,这样的话,同样的一套代码就可以完成分类或回归了,而不至于每次都要重新推导一遍。
1.2.5Xgboost寻找特征
- xgboost在训练过程中,给出各个特征的评分,从而表明每个特征对模型的重要性
- xgboost是利用梯度优化算法,样本是不放回的,如果一个样本被连续重复抽出,梯度来回踏步,不利于收敛。
- xgboost支持自采样,也就是说每轮计算可以不使用全部的样本。
1.2.6缺失值处理
对于特征值有缺失的样本,xgboost可以自动学习出他的分裂方向。xgboost内置处理缺失值的规则。用户需要提供一个和其他样本不同的值,然后把它作为一个参数传入,以此来作为缺失值的取值。xgboost在不同节点遇到缺失值时采用不同的处理方式,并且会学习未来遇到缺失值时的处理方法。
1.2.7剪枝技术
xgboost先从顶到底建立所有可以建立的子树,再从底到顶的反向机芯剪枝,比起lightGBM,这样不容易陷入局部最优解。【后剪枝技术:去掉某个子树或用叶子节点代替某个子树时,对模型整体的能力影响很小】
1.2.8内置交叉验证
xgboost允许在每一轮Boosting迭代中使用交叉验证,因此可以方便的获得最优Boosting迭代次数,而GBDT使用网格搜索,只能检测有限个值。
2.xgboost模型详解
2.1安装
安装有两种方式:
- 离线安装:可以去选择适合自己的版本
- 在线安装:可以直接在终端使用pip命令进行安装
pip install xgboost-0.81-cp37-cp37m-win_amd64.whl
注意:多线程版本安装比较复杂,可以参考一些专业教程进行安装
2.2xgboost加载的数据格式解析
xgboost可以加载多种数据格式的训练数据
名称 | 说明 |
---|---|
libsvm | 格式的文本数据 |
Numpy | 二维数组 |
xgboost | 算法自带的二进制的缓存文件。剪枝的数据存储在对象DMatrix中。 |
2.2.1下面会对各种格式进行演示
- 加载libsvm格式的数据
dtrain1 = xgb.DMatrix('train.svm.txt')
- 加载二进制的缓存文件
dtrain2 = xgb.DMatrix('train.svm.buffer')
- 加载numpy的数组
data = np.random.rand(5,10) # 5行10列数据集
label = np.random.randint(2,size=5) # 二分类目标值
dtrain = xgb.DMatrix(data,label=label) # 组成训练集
- 将scipy.sparse格式的数据转化为Dmatrix格式
csr = scipy.sparse.csr_matrix((dat,(row,col)))
dtrain = xgb.DMatrix( csr )
- 将Dmatrix格式的数据保存为xgboost的二进制格式,在下次加载时可以提高加载速度,使用方法如下:
dtrain = xgb.DMatrix('train.svm.txt')
dtrain.save_binary("train.buffer")
- 可以使用如下方式处理Dmatrix中的缺失值:
dtrain = xgb.DMatrix( data, label=label, missing = -999.0)
- 当需要给样本设置权重时,可以用如下方式:
w = np.random.rand(5,1)
dtrain = xgb.DMatrix( data, label=label, missing = -999.0, weight=w)
2.3 xgboost的模型参数
xgboost使用<key,value>字典的方式存储参数
# xgboost模型
params = {
'booster':'gbtree',
'objective':'multi:softmax', # 多分类问题
'num_class':10, # 类别数,与multi softmax并用
'gamma':0.1, # 用于控制是否后剪枝的参数,越大越保守,一般0.1 0.2的样子
'max_depth':12, # 构建树的深度,越大越容易过拟合
'lambda':2, # 控制模型复杂度的权重值的L2 正则化项参数,参数越大,模型越不容易过拟合
'subsample':0.7, # 随机采样训练样本
'colsample_bytree':3,# 这个参数默认为1,是每个叶子里面h的和至少是多少
# 对于正负样本不均衡时的0-1分类而言,假设h在0.01附近,min_child_weight为1
#意味着叶子节点中最少需要包含100个样本。这个参数非常影响结果,
# 控制叶子节点中二阶导的和的最小值,该参数值越小,越容易过拟合
'silent':0, # 设置成1 则没有运行信息输入,最好是设置成0
'scale_pos_weight':1 # 正负样本比例
'eta':0.007, # 如同学习率
'seed':1000,
'nthread':7, #CPU线程数
#'eval_metric':'auc'
}
- 在运行xgboost之前,必须设置三种类型参数:
general parameters
、booster parameters
和task parameters
: - 通用参数(general parameter):该参数控制在提升过冲使用哪种booster,常用的booster有树模型(Tree model)和线性模型(Liner model)
- Booster参数(booster parameter):取决于使用哪种booster
- 学习目标参数(Task parameter):控制学习的场景,例如在回归问题中会使用不同的参数控制排序
2.3.1 通用参数
- booster = gbtree:有两个模型可选,gbtree和gblinear。gbtree使用基于树的模型进行提升计算;gblinear使用线性模型进行提升计算。【默认为树模型:gbtree】
- silent = 0:取0时表示打印出运行时信息,取1时表示已默认方式运行,不打印运行信息。【默认为0】
- verbosity = 1:打印消息的详细程度,有效值为0(静默),1(警告),2(信息),3(调试)。有时xgboost会尝试根据启发式更改配置,启动式显示为警告信息,如果出现意外,请尝试增加详细程度。【默认为1】
- nthread = None:xgboost运行的线程数,缺省时默认当前系统可以获得的最大线程数。【默认为None】
- num_pbuffer:预测缓冲区大小,通常设置为训练实例的数目。缓冲用于保存最后一步提升的预测结果,无需人为设置。
- num_feature:Boosting过程中用到的特征维数,设置为特征个数,xgboost会自动设置,无需人为设置。
- disable_default_eval_metric = 0:标记以禁止默认度量标准,设置为>0以禁止。【默认不禁止】
2.3.2 tree booster参数
- eta = 0.3:为了防止过拟合,更新过程中用到的收缩步长。在每次提升迭代计算之后,算法会直接获得新特征的权重。eta通过缩减特征的权重使得提升计算过程更加保守。取值范围为:[0,1],一般设置为0.01-0.2【默认为0.3】
- gamma = 0:在节点分裂时,只有分裂后损失函数的值下降了,才会分裂这个节点。Gamma指定了节点分裂所需要的最小损失函数下降。这个参数的值越大,算法越保守。这个参数的值和损失函数息息相关,所以是需要调整的。取值范围为:[0,正无穷]
- max_depth = 6:树的最大深度。取值范围为:[1,正无穷],可以使用gradsearch函数来进行调优。一般设置3-10。【默认为6】
- min_child_weight = 1:孩子节点中最小样本权重和。如果一个叶子节点的样本权重和小于min_child_weight则拆分过程结束。在线性回归模型中,这个参数是指建立每个模型所需要的最小样本数。这个参数用于避免过拟合。当他的值较大时,可以避免模型学习到局部的特殊样本;但是如果这个值过高,就会导致欠拟合。这个参数需要使用CV函数来调整。取值范围为:[0,正无穷]。【默认为1】
- max_delta_step = 0:我们允许每棵树的权重被估计的值。如果他的值被设置为0,意味着没有约束;如果它的值被设置为一个正直,它能够是的更新的步骤更加保守。通常这个参数是没有必要的,但是如果在逻辑回归中,类极其不平衡这时候他有可能会起到帮助的作用。把它范围设置为1-10之间也许能控制更新。取值范围为:[0,正无穷]。【默认值为0】
- subsample = 1:用于训练模型的子样本占整个样本集合的比例。如果设置为0.5则意味着xgboost将随机的从整个样本集合中随机的抽取出50%的子样本建立树模型,这样能够防止过拟合。取值范围:(0,1]。【默认为1,不采样】
- colsample_bytree,colsample_bylevel,colsample_bynode = 1:这是对列的子采样参数家族,所有的colsample_by*参数的范围均为(0,1],【默认值为1,不采样】
- colsample_bytree =1:在建树时对特征采样的比例。
- colsample_bylevel = 1:是每个级别的列的子采样比例,对于树中达到的每个新深度级别,子采样都会发生一次,列是从当前树的列集中进行子采样的。
- colsample_bynode =1:是每个节点(拆分)的列的子采样比例,每次评估新的拆分时,都会发生一次子采样。列是从当前级别选择的列集中进行的二次采样的。
2.3.3 Linear Booster参数
- lambda = 1:L2正则化的惩罚系数,增加这个值可以使得模型更加保守
- alpha = 1:L1正则化的惩罚系数,增加这个值可以使得模型更加保守
- lambda_bias:在偏置上的L2正则。(在L1上没有偏置项的正则,因为L1偏置时不需要)【默认值为0】
2.3.4 学习目标参数
这个参数是用来控制理想的优化目标和每一步结果的度量方法
- objective = reg:linear :定义学习任务及相应的学习目标,可选择的目标函数如下:
- “reg:linear”:线性回归
- “reg:logistic”:逻辑回归
- “binary:logistic”:二分类的逻辑回归问题,输出为概率
- “binary:logitraw”:二分类的逻辑回归问题,输出的结果为wTx.
- “count:poisson”:计数问题的poisson回归,输出结果为poisson分布。在poisson回归中,max_delta_step的缺省值为0.7.
- “multi:softmax”:让xgboost采用softmax目标函数处理多分类问题,同事需要设置参数num_class(类别个数)
- “multi:softprob”:和softmax一样,但是输出的是ndata * nclass 的向量,可以将该向量reshape成ndata行nclass列的矩阵。没有行数据表示样本所属于每个类别的概率。
- “rank:pairwise”:set xgboost to do ranking task by minimizing the pairwise loss
- base_score = 0.5:所有实例的初始化预测分数,全局偏置;当有足够的迭代次数是,改变这个值将不会有太大的影响。
- eval_metric :校验数据所需要的评价指标,不同的目标函数将会有缺省的评价指标。
- 可以添加多种评价指标,对于Python用户要以list传递参数给程序,而不是map参数,list参数不会覆盖eval_metric
- 可供的选择如下:
- rmse:均方根误差
- mae:平均绝对误差
- logloss:负对数似然函数损失
- error:二分类错误率,阈值为0.5
- merror:多分类错误率
- mlogloss:多分类logloss损失函数
- auc:ROC曲线下面积
- seed = 0:随机数的种子,默认为0
2.3.5 xgboost训练时的超参数
xgboost.train(params,
dtrain,
num_boost_round=10,
evals(),
obj=None,
feval=None,
maximize=False,
early_stopping_rounds=None,
evals_result=None,
verbose_eval=True,
learning_rates=None,
xgb_model=None)
参数解析:
- params:这是一个字典,里面包含着训练中的参数关键字和对应的值,形式是
params = {'booster':'gbtree','eta':0.1}
- dtrain:训练数据
- num_boost_round:这是指提升迭代的个数
- evals:这是一个列表,用于对训练过程中进行评估列表中的元素。形式是
evals = [(dtrain,'train'),(dval:'val')]
或者是evals = [(dtrain,'train')]
,对于第一种情况,它使得我们可以在训练过程中观察验证集的效果。 - obj:自定义目标函数
- feval:自定义评估函数
- maximize:是否对评估函数进行最大化
- early_stopping_rounds:早起停止次数。例如,假设为100,验证集的误差迭代到一定程度在100次内不能再继续降低,就停止迭代。这要求evals里至少有一个元素,如果有多个,按照最后一个区执行。返回的是最后的迭代次数(不是最好的)。如果early_stopping_rounds存在,则模型会生成三个属性,
bst.best_score
,bst.best_iteration
和bst.best_ntree_limit
- evals_result:字典,存储在watchilist中的元素的评估结果
- verbose_eval(可以输入布尔型或者数值型):也要求evals里至少有一个元素,如果为True,则对evals中的元素的评估结果会输出在结果中;如果输入的是数字,假设为3,则每个3个迭代输出一次。
- learning_rates:每次提升的学习率的列表
- xgb_model:在训练之前用于加载的xgb_modelfile。可以加载已经训练过的模型,进行继续训练。
2.4模型训练
有了参数列表和数据就可以训练模型了
num_round = 10
bst = xgb.train( plst, dtrain, num_round, evallist )
2.5模型预测
模型已经训练好了,可以利用已经训练好的模型对测试集进行预测
# X_test类型可以是二维List,也可以是numpy的数组
dtest = DMatrix(X_test)
y_pred = model.predict(dtest)
2.6保存模型
模型训练好了,一直在内存中毕竟是不安全的,持久化到磁盘才是王道。并且我们也很好奇模型到底长什么样子
bst.save_model('test.model')
导出模型和特征映射(Map),之后就可以查看.txt文件,来满足自己的好奇心了(查看模型结构和意义)
# 导出模型到文件
bst.dump_model('dump.raw.txt')
# 导出模型和特征映射
bst.dump_model('dump.raw.txt','featmap.txt')
2.7加载模型
保存模型是为了后面可以方便使用,所以加载模型会为我们提供便利
bst = xgb.Booster({'nthread':4}) # init model
bst.load_model("model.bin") # load data
注意:在加载模型的时候需要先初始化一个“空壳”这个类似TensorFlow中的操作
3.xgboost的代码实战
xgboost有俩大类接口:xgboost原生接口和sklearn接口,並且xgboost能夠實現分類回歸兩種任務,下面對4中情況作出解析
3.1原生接口的分類问题
数据使用的sklearn中自带的iris数据集
注意:如果开启多线程,使用MacOS系统,要配置环境变量os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"
,不然系统会不支持调用多线程,在Windows系统使用什么情况不太清楚,有不同的意见可留言讨论!
from sklearn.datasets import load_iris
import xgboost as xgb
from xgboost import plot_importance
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score # 准确率
import os
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"
# 记载样本数据集
iris = load_iris()
X,y = iris.data,iris.target
# 数据集分割
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=22)
# 算法参数
params = {
'booster':'gbtree',
'objective':'multi:softmax',
'num_class':3,
'gamma':0.1,
'silent': 1, # 关闭掉运行时打印信息
'max_depth':6,
'lambda':2,
'subsample':0.7,
'colsample_bytree':0.7,
'min_child_weight':3,
'slient':1,
'eta':0.1,
'seed':1000,
'nthread':4,
}
# 构造参数
plst = params.items()
# 生成数据集格式,xgboost的数据需要转换一下
dtrain = xgb.DMatrix(X_train,y_train)
num_rounds = 500
# xgboost模型训练
model = xgb.train(plst,dtrain,num_rounds,verbose_eval=100)
# 对测试集进行预测
dtest = xgb.DMatrix(X_test)
y_pred = model.predict(dtest)
# 计算准确率
accuracy = accuracy_score(y_test,y_pred)
print('accuarcy:%.2f%%'%(accuracy*100))
# 显示重要特征
plot_importance(model)
plt.show()
经过500次迭代,测试集计算的accuracy = 93.34%,结果算是很高的了
3.2原生接口回归问题
数据集使用的sklearn中的Boston数据集
import xgboost as xgb
from xgboost import plot_importance
from matplotlib import pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_boston
from sklearn.metrics import mean_squared_error
import os
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"
# 加载数据集,此数据集时做回归的
boston = load_boston()
X,y = boston.data,boston.target
# Xgboost训练过程
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=22)
# 算法参数
params = {
'booster':'gbtree',
'objective':'reg:gamma',
'gamma':0.01,
'max_depth':6,
'silent': 1,
'lambda':3,
'subsample':0.8,
'colsample_bytree':0.8,
'min_child_weight':3,
'slient':1,
'eta':0.1,
'seed':1000,
'nthread':4,
}
dtrain = xgb.DMatrix(X_train,y_train)
num_rounds = 800
plst = params.items()
model = xgb.train(plst,dtrain,num_rounds)
# 对测试集进行预测
dtest = xgb.DMatrix(X_test)
y_pred = model.predict(dtest)
# 计算mse
mse= mean_squared_error(y_true=y_test,y_pred=y_pred)
print('mse:',mse)
# 显示重要特征
plot_importance(model)
plt.show()
在没有调参的情况下mse = 9.86左右,效果还是可以的
3.3Xgboost使用sklearn接口的分类(推荐)
先熟悉一下sklearn接口中模型初始化参数都有哪些
from xgboost.sklearn import XGBClassifier
clf = XGBClassifier(
silent=0, # 设置成1则没有运行信息输出,最好是设置为0,是否在运行升级时打印消息
nthread = 4 # CPU 线程数 默认最大
learning_rate=0.3 , # 如同学习率
min_child_weight = 1,
# 这个参数默认为1,是每个叶子里面h的和至少是多少,对正负样本不均衡时的0-1分类而言
# 假设h在0.01附近,min_child_weight为1 意味着叶子节点中最少需要包含100个样本
# 这个参数非常影响结果,控制叶子节点中二阶导的和的最小值,该参数值越小,越容易过拟合
max_depth=6, # 构建树的深度,越大越容易过拟合
gamma = 0,# 树的叶子节点上做进一步分区所需的最小损失减少,越大越保守,一般0.1 0.2这样子
subsample=1, # 随机采样训练样本,训练实例的子采样比
max_delta_step=0, # 最大增量步长,我们允许每个树的权重估计
colsample_bytree=1, # 生成树时进行的列采样
reg_lambda=1, #控制模型复杂度的权重值的L2正则化项参数,参数越大,模型越不容易过拟合
# reg_alpha=0, # L1正则项参数
# scale_pos_weight =1 # 如果取值大于0的话,在类别样本不平衡的情况下有助于快速收敛,平衡正负权重
# objective = 'multi:softmax', # 多分类问题,指定学习任务和响应的学习目标
# num_class = 10, # 类别数,多分类与multisoftmax并用
n_estimators=100, # 树的个数
seed = 1000, # 随机种子
# eval_metric ='auc'
)
下面使用sklearn接口下的xgboost帮助我们处理分类问题
iris数据集算是多分类,注意一下使用的目标函数objective='multi:softmax’
from sklearn.datasets import load_iris
import xgboost as xgb
from xgboost import plot_importance
from matplotlib import pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# 加载样本数据集
iris = load_iris()
X,y = iris.data,iris.target
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=12343)
# 训练模型
model = xgb.XGBClassifier(max_depth=5,learning_rate=0.1,n_estimators=160,silent=True,objective='multi:softmax')
model.fit(X_train,y_train)
# 对测试集进行预测
y_pred = model.predict(X_test)
#计算准确率
accuracy = accuracy_score(y_test,y_pred)
print('accuracy:%2.f%%'%(accuracy*100))
# 显示重要特征
plot_importance(model)
plt.show()
最后输出的accuracy = 93%,效果差不多
3.4基于Scikit-learn接口的回归
依然使用Boston数据集进行回归预测
认真的同学可能发现了,使用sklearn的接口用起来方便一些,目前可以看到的至少不用单独构建数据了,接口已经辅助构造了
import xgboost as xgb
from xgboost import plot_importance
from matplotlib import pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_boston
from sklearn.metrics import mean_squared_error
import os
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"
# 导入数据集
boston = load_boston()
X ,y = boston.data,boston.target
# Xgboost训练过程
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=0)
model = xgb.XGBRegressor(max_depth=5,learning_rate=0.1,n_estimators=160,silent=True,objective='reg:gamma')
model.fit(X_train,y_train)
# 对测试集进行预测
y_pred = model.predict(X_test)
# 计算mse
mse= mean_squared_error(y_true=y_test,y_pred=y_pred)
print('mse:',mse)
# 显示重要特征
plot_importance(model)
plt.show()
mse: 22.61262300770485,默认参数效果
4.xgboost参数调优
4.1参数调优步骤:
- 选择较高的学习率。一般情况下,学习率的值为0.1,但是对于不同的问题,理想的学习率有时候会在0.05-0.3之间波动。选择对应于此学习率的理想决策树数量。xgboost有一个很有用的函数“CV”,这个函数可以在每一次迭代中使用交叉验证,并返回理想的决策树数量。【学习率+树棵树组合调优】
- 对于给定的学习率和决策树数量,进行决策树特定参数调优(max_depth、min_child_weight、gamma、subsample、colsample_bytree)在确定一棵树的过程中,我们可以选择不同的参数。
- xgboost的正则化参数调优,(lambda、alpha)。这些参数可以降低模型的复杂度,从而提高模型的表现。
- 降低学习率,确定理想参数。
下面按照上面顺序,详细说明调优策略
4.2 确定学习率和树的个数
为了确定Boosting参数,我们要先给其他参数一个初始值。咱们先按照如下方法取值:
- 1.max_depth = 5 :这个参数的取值在3-10之间,初始给定5,当然选择6也是没有问题的。
- 2.min_child_weight = 1 :这里选择了一个比较小的值,因为这是一个极不平衡的分类问题。因此,某些叶子节点下的值会比较小。
- 3.gamma = 0 :起始值也可以选择其它比较小的值,在0.1-0.2都是可以的,这个参数后面也会重新调整。
- 4.subsample,colsample = 0.8 :这个是比较常见的初始值了,典型的范围在0.5-0.9之间
- 5.scale_pos_weight = 1 :这个值是因为类别十分不平衡
**注意:上面这些参数的初始值只是一个根据经验给出的,后续需要调优。这里把学习率设置成默认的0.1.然后用xgboost中的CV函数来确定最佳的决策树数量。
4.3 max_depth和min_weight参数调优
我们先对这两个参数调优,是因为他们对最终结果有很大的影响。首先。我们先大范围的粗略设置参数,然后在小范围的调整
注意:在这一个环节我会进行高负荷的网格搜索调参,这个过程会很久,也行十几分钟、几十分钟、甚至更久,具体的情况取决于你的系统性能。
4.4 gamma参数调优
在已经调整好的其他参数的基础上,我们可以进行gamma参数的调优了。Gamma参数取值范围很大,这里简单的设置为5,当然也可取得更加精细些,比如:
# 数据包
from sklearn.model_selection import GridSearchCV
# 设置待测参数
param_test3 = {
'gamma':[i/10.0 for i in range(0,5)]
}
# 初始化CV模型
gsearch = GridSearchCV(estimator = XGBClassifier( learning_rate =0.1,
n_estimators=140,
max_depth=4,
min_child_weight=6,
gamma=0,
subsample=0.8,
colsample_bytree=0.8,
objective= 'binary:logistic',
nthread=4,
scale_pos_weight=1,
seed=22
),
param_grid = param_test3,
scoring='roc_auc',
n_jobs=4,
iid=False,
cv=5)
# 开启CV
gsearch.fit(train[predictors],train[target])
# 找到每个CV分数,最好的参数,最好的分数
gsearch.grid_scores_,
gsearch.best_params_,
gsearch.best_score_
4.5 调整subsample和colsample_bytree参数
尝试不同的subsample和colsample_bytree参数。可以分成两个阶段进行这个步骤。这两个步骤都取0.6、0.7、0.8、0.9作为起始值。
4.6 正则化参数调优
由于gamma函数提供了一种更加有效的降低过拟合的方法,大部分人很少会用到这个参数,但是我们可以尝试调整一下这个参数。
4.7降低学习速率
最后,我使用较低的学习速率,以及使用更多的决策树,我们可以用xgboost中CV函数来进行这一步工作。
4.8 调优总结
**要想模型的表现有大幅度的提升,调整每个参数带来的影响也必须清楚,仅仅靠着参数的调整和模型的小幅度优化,想要让模型的表现有个大幅度提升是不可能的。想要模型的表现有质的飞跃,需要依靠其他的手段。没错的,是【数据】。特征工程、模型融合、模型堆叠也许效果更明显。
5.xgboost特征重要性&特征选择
5.1 梯度提升算法是如何计算特征重要性的
- 使用梯度提升算法的好出是在提升树被创建后,可以相对直接的得到每个属性的重要性得分。一般来说,重要性分数,衡量了特征在模型中的提升决策树构建中的价值。一个属性越多的备用来在模型中构建决策树,他的重要性就相对越高。
- 属性重要性是通过对数据集中的每个属性进行计算,并进行排序得到。在单个决策树中通过每个属性分裂点改进性能度量的量来计算属性重要性。由节点负责加权和记录次数,也就是说一个属性对分裂点改进性能度量越大(越靠近根节点),权值越大;被越多提升树所选择,属性越重要。性能度量可以是选择分裂节点的Gini纯度,也可以是其他的度量函数。
- 最后将一个属性在所有提升树中的结果 进行加权求和然后平均,得到重要性得分。
5.2 绘制特征重要性
- 一个已经训练好的xgboost模型,是可以自动计算特征重要性的,这些重要性得分可以通过成员变量
feature_importances_
得到。如下可以展示在控制台:
print(model.feature_importances_)
- 同样也可以可视化这些分数,以便获得数据集中每个特征的相对重要性的直观显示,例如:
# plot
pyplot.bar(range(len(model.feature_importances_)), model.feature_importances_)
pyplot.show()
- 下面使用iris数据集,训练一个xgboost的分类器,从而计算特征的重要性,并进行可视化
# plot feature importance manually
from numpy import loadtxt
from xgboost import XGBClassifier
from matplotlib import pyplot
from sklearn.datasets import load_iris
# load data
dataset = load_iris()
# split data into X and y
X = dataset.data
y = dataset.target
# fit model no training data
model = XGBClassifier()
model.fit(X, y)
# feature importance
print(model.feature_importances_)
# plot
pyplot.bar(range(len(model.feature_importances_)), model.feature_importances_)
pyplot.show()
"""
[0.17941953 0.11345647 0.41556728 0.29155672]
"""
这种绘图的方式并不是很完美,只是显示了特征重要性而没有排序,可以在进行绘图之前对特征重要性进行排序
下面就通过内置的绘图函数,进行特征重要性得分排序后的绘制,这个函数就是plot_importance(),如下所示:
# plot feature importance manually
from numpy import loadtxt
from xgboost import XGBClassifier
from matplotlib import pyplot
from sklearn.datasets import load_iris
from xgboost import plot_importance
# load data
dataset = load_iris()
# split data into X and y
X = dataset.data
y = dataset.target
# fit model no training data
model = XGBClassifier()
model.fit(X, y)
# feature importance
print(model.feature_importances_)
# plot feature importance
plot_importance(model)
pyplot.show()
"""
[0.17941953 0.11345647 0.41556728 0.29155672]
"""
根据特征在输入数组的索引,特征被自动命名为f0 - f3,在问题描述中手动的将这些索引映射到名称,我们可以看到,f2具有最高的重要性,f1具有最低的重要性。
5.3 根据xgboost特征重要性得分进行特征选择
- 特征重要性得分,可以用于在sklearn中进行特征选择。通过SelectFromModel类实现,该类采用模型并将数据集转换为具有选定特征的子集。这个类可以采取预先训练的模型,例如在真个数据集上训练的模型,然后,他可以通过阈值来决定选择那些特征。
- 当在SelectFromModel实例上调用transform()方法时,该阈值被用于在训练集和测试集上一致性选择相同特征。
- 在下面实例中,我们首先在训练集上训练xgboost模型,然后在测试集上评估。使用从训练数据集计算的特征重要性,然后,将模型封装在一个SelectFromModel实例中,我们使用这个来选择训练集上的特征,用所选择的特征子集训练模型,然后在相同的特征方案下对测试集进行评估。
# 使用阈值进行选择特征
selection = SelectFromModel(model, threshold=thresh, prefit=True)
select_X_train = selection.transform(X_train)
# 训练模型
selection_model = XGBClassifier()
selection_model.fit(select_X_train, y_train)
# 评估模型
select_X_test = selection.transform(X_test)
y_pred = selection_model.predict(select_X_test)
我们可以通过测试多个阈值,来从特征重要性中选择特征。具体而言,每个输入变量的特征重要度,本质上允许我们通过重要性来测试每个特征子集。
下面是完整代码:
# 绘制特征重要性得分
import numpy as np
from xgboost import XGBClassifier
from matplotlib import pyplot
from sklearn.datasets import load_iris
from xgboost import plot_importance
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.feature_selection import SelectFromModel
# 加载数据
dataset = load_iris()
# 切分数据,样本&标签
X = dataset.data
y = dataset.target
# 切分训练集测试集
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.33,random_state=7)
# 训练一个xgboost分类器
model = XGBClassifier()
model.fit(X_train, y_train)
# 获得特征重要性
print(model.feature_importances_)
# 对测试数据做出预测,并进行评估
y_pred = model.predict(X_test)
predictions = [round(value) for value in y_pred]
accuracy = accuracy_score(y_test,predictions)
print("Accuracy:%.2f%%"%(accuracy*100.0))
# 训练模型,使用每个特征重要性作为阈值
# 特征重要性得分排序
thresholds = np.sort(model.feature_importances_)
for thresh in thresholds:
# 遍历所有的特征重要性得分,把每个得分作为阈值进行特征选择
selection = SelectFromModel(model,threshold=thresh,prefit=True )
# 构建新的训练集
select_X_train = selection.transform(X_train)
# 使用选择出的特征作为训练集,重新训练一个模型出来
selection_model = XGBClassifier()
selection_model.fit(select_X_train, y_train)
# 对测试集进行transform()操作
select_X_test = selection.transform(X_test)
# 预测,评估
y_pred = selection_model.predict(select_X_test)
predictions = [round(value) for value in y_pred]
accuracy = accuracy_score(y_test,predictions)
print("Thresh=%.3f, n=%d, Accuracy: %.2f%%" % (thresh, select_X_train.shape[1], accuracy * 100.0))
"""
[0.20993228 0.09029345 0.54176074 0.15801354]
Accuracy:92.00%
Thresh=0.090, n=4, Accuracy: 92.00%
Thresh=0.158, n=3, Accuracy: 92.00%
Thresh=0.210, n=2, Accuracy: 86.00%
Thresh=0.542, n=1, Accuracy: 90.00%
"""
我们可以看到,模型的性能通常随着所选择的特征的数量减少,在这个问题上,可以对测试集准确率和模型复杂度做一个权衡。例如,选择3个特征,接受准确率为92%,这样可能是对这样一个小数据集的清洗,但是对于更大的数据集,使用交叉验证作为模型评估方案可能是更有用的策略。