前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >机器学习算法之XGBoost及其自动调参(算法+数据+代码)

机器学习算法之XGBoost及其自动调参(算法+数据+代码)

作者头像
Minerva
修改2021-01-11 17:00:22
33.9K1
修改2021-01-11 17:00:22
举报

机器学习算法之XGBoost及其自动调参

(算法+数据+代码)

本文将利用一个excel数据对常见机器学习算法(XGBoost、Random Forest随机森林、ET极度随机树、Naïve Bayes高斯朴素贝叶斯、KNN K近邻、Logistic Regression逻辑回归、Decision Tree 决策树)的使用过程进行简单的介绍,并对XGBoost算法的自动调参方法进行详解,机器学习算法的详细讲解在机器学习专辑里都有介绍。

机器学习专辑

代码链接:https://github.com/Minerva-J/MachineLearning

一、 算法介绍 在之前的文章中我们介绍过机器学习中的集成学习算法Bagging方法和Boosting方法,通过将多个弱学习器集成起来形成一个强学习器。XGBoost(eXtreme Gradient Boosting)是Boosting算法中的一种,是一种提升树模型,将很多树的模型集成起来。其以正则化提升(Regularized Boosting)技术而闻名,通过代价函数里加入正则项,控制模型的复杂度,防止过拟合。可以实现并行处理,相比GBM有了很大的速度提升。

二、 模型详解 XGBoost在Linux的Python环境下可以直接用pip install xgboost安装。 XGBoost可以接受多种数据格式的输入,包括libsvm格式的文本数据、Numpy的二维数组、二进制的缓存文件。 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
    'eta':0.007,  # 如同学习率
    'seed':1000,
    'nthread':7,  #CPU线程数
    #'eval_metric':'auc'
}

模型参数分为三类:通用参数、Booster参数、目标函数参数。

通用参数是模型的宏观参数,通常不用刻意去设置。 1、booster参数是迭代的模型,包括gbtree(基于树的模型)和gblinear(基于线性模型),默认选择是gbtree。 2、silent 参数决定是否输出信息,默认是0。 3、nthread 参数是多线程控制,默认为最大线程,就是使用CPU的全部核。 4、num_feature 参数是特征维数,不需要手动设置,模型会自动设置。 Booster参数通常就是tree booster的参数,因为linear booster的表现通常不如tree booster,因此很少使用。 1、eta(默认0.3),模型在更新时计算新的权重,通过减少每一步的权重,使模型更加保守,来防止过拟合。 2、gama(默认0),给定了损失函数的最低值,大于该值时节点才会分裂,该值越大模型越保守。 3、max_depth(默认6), 代表树的最大深度,该值越大模型对数据的拟合程度越高,适当控制最大深度可以防止模型过拟合,可以通过交叉验证cv函数来调参学习,通常取值范围在3-10之间。 4、min_child_weight(默认1),代表树模型的最小叶子节点样本的权重和,如果叶子节点的样本权重和小于该值,则拆分过程结束,该参数值较大时可以避免模型学习到局部的特殊样本防止模型过拟合,但该参数值过大会导致模型欠拟合,可以通过交叉验证cv函数来调参学习。 5、subsample(默认1),代表每棵树随机采样的比例,该参数值较小可以避免过拟合,但过小会导致模型欠拟合。 6、colsample_bytree(默认1),代表每棵树随机采样的列数占比,每一列是一个特征。 7、scale_pos_weight(默认0),在样本类别不平衡时,该参数值取大于0的值可以帮助模型更快收敛。 8、lambda(默认1),模型权重的L2正则化惩罚系数,平时很少使用,但可以用来降低过拟合。 9、alpha(默认0),模型权重的L1正则化惩罚系数,适用于数据维度很高时,算法速度更快。 目标参数用来控制理想的优化目标和每一步输出结果的度量方法。 1、objective(默认reg:linear),代表学习任务需要最小化的损失函数,可选的目标函数有: “reg:linear” :线性回归。 “reg:logistic” :逻辑回归。 “binary:logistic” :二分类的逻辑回归问题,输出为概率。 “binary:logitraw” :二分类的逻辑回归问题,输出的结果为wTx。 “count:poisson” :计数问题的poisson回归,输出结果为poisson分布。 在poisson回归中,max_delta_step的缺省值为0.7。(used to safeguard optimization) “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

2、base_score(默认0.5),所有样本的初始预测值,一般不需要设置。

3、eval_metric(默认值取决于前面objective参数的取值),代表模型校验数据所需要的评价指标,不同的目标函数对应不同的默认评价指标(rmse for regression, and error for classification, mean average precision for ranking),用户也可以自己添加多种评价指标。 常用的评价指标: “rmse”: root mean square error均方误差 “mae”:mean absolute error 平均绝对误差 “logloss”: negative log-likelihood负对数似然 “error”: Binary classification error rate 二分类错误率,阈值为0.5 “merror”: Multiclass classification error rate多分类错误率 “mlogloss”: Multiclass logloss多分类对数损失 “auc”: Area under the curve for ranking evaluation ROC曲线下面积 4、seed(默认0),随机数的种子,设置该参数可以复现随机数据的结果,固定该值可以得到相同的随机划分。

三、 Python实战 首先是我们的数据展示,第一列是我们样本的ID,中间的列是我们的特征feature,最后一列是每个样本对应的标签label,取值为0或1。

1、首先导入必要的包:

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
import pandas as pd
import numpy as np
import warnings
from xgboost.sklearn import XGBClassifier
from sklearn import metrics

2、导入我们的数据并划分训练集和测试集:

feature_file = pd.read_excel("data.xlsx")

x = []# 特征数据
y = []# 标签
for index in feature_file.index.values:
    # print('index', index)
    # print(feature_file.ix[index].values) 
    x.append(feature_file.ix[index].values[1: -1]) # 每一行都是ID+特征+Label
    y.append(feature_file.ix[index].values[-1] - 1) #
x, y = np.array(x), np.array(y)
print('x,y shape', np.array(x).shape, np.array(y).shape)
print('样本数', len(feature_file.index.values))
# 分训练集和测试集
X_train,X_test,y_train,y_test = train_test_split(x,y,test_size=0.2,random_state=12343)
print('训练集和测试集 shape', X_train.shape, y_train.shape, X_test.shape, y_test.shape)
# 共有218个样本,每个样本106个特征和1个标签,训练集174个样本,验证集44个样本

3、 采用交叉验证方法对数据进行训练和验证:

# xgboost
from xgboost import XGBClassifier
xgbc_model=XGBClassifier()

# 随机森林
from sklearn.ensemble import RandomForestClassifier
rfc_model=RandomForestClassifier()

# ET
from sklearn.ensemble import ExtraTreesClassifier
et_model=ExtraTreesClassifier()

# 朴素贝叶斯
from sklearn.naive_bayes import GaussianNB
gnb_model=GaussianNB()

#K最近邻
from sklearn.neighbors import KNeighborsClassifier
knn_model=KNeighborsClassifier()

#逻辑回归
from sklearn.linear_model import LogisticRegression
lr_model=LogisticRegression()

#决策树
from sklearn.tree import DecisionTreeClassifier
dt_model=DecisionTreeClassifier()

#支持向量机
from sklearn.svm import SVC
svc_model=SVC()

# xgboost
xgbc_model.fit(x,y)

# 随机森林
rfc_model.fit(x,y)

# ET
et_model.fit(x,y)

# 朴素贝叶斯
gnb_model.fit(x,y)

# K最近邻
knn_model.fit(x,y)

# 逻辑回归
lr_model.fit(x,y)

# 决策树
dt_model.fit(x,y)

# 支持向量机
svc_model.fit(x,y)

from sklearn.cross_validation import cross_val_score
print("\n使用5折交叉验证方法得随机森林模型的准确率(每次迭代的准确率的均值):")
print("\tXGBoost模型:",cross_val_score(xgbc_model,x,y,cv=5).mean())
print("\t随机森林模型:",cross_val_score(rfc_model,x,y,cv=5).mean())
print("\tET模型:",cross_val_score(et_model,x,y,cv=5).mean())
print("\t高斯朴素贝叶斯模型:",cross_val_score(gnb_model,x,y,cv=5).mean())
print("\tK最近邻模型:",cross_val_score(knn_model,x,y,cv=5).mean())
print("\t逻辑回归:",cross_val_score(lr_model,x,y,cv=5).mean())
print("\t决策树:",cross_val_score(dt_model,x,y,cv=5).mean())
print("\t支持向量机:",cross_val_score(svc_model,x,y,cv=5).mean())

可以得到XGBoost、Random Forest随机森林、ET极度随机树、Naïve Bayes高斯朴素贝叶斯、KNN K近邻、Logistic Regression逻辑回归、Decision Tree 决策树等模型的5折交叉验证方法准确率。可以说没有调参的XGBoost已经优于其他机器学习算法了。

4、 对模型进行性能评估

# 性能评估以XGboost为例
xgb = xgb.XGBClassifier()
# 对训练集训练模型
xgb.fit(X_train,y_train)
# 对测试集进行预测
y_pred = xgb.predict(X_test)
print("\n模型的平均准确率(mean accuracy = (TP+TN)/(P+N) )")
print("\tXgboost:",xgb.score(X_test,y_test))
# print('(y_test,y_pred)', y_test,y_pred)    print("\n性能评价:")
print("\t预测结果评价报表:\n", metrics.classification_report(y_test,y_pred))
print("\t混淆矩阵:\n", metrics.confusion_matrix(y_test,y_pred))

我们用XGBoost算法对训练集进行训练后,对测试集测试后进行性能评估,得到测试准确率、Precision、Recall、F1-score和混淆矩阵。

四、 XGBoost模型参数调优 Xgboost参数调优的一般步骤:   1、学习速率(learning rate)。在0.05~0.3之间波动,通常首先设置为0.1。   2、进行决策树特定参数调优(max_depth , min_child_weight , gamma , subsample,colsample_bytree)在确定一棵树的过程中,我们可以选择不同的参数。   3、正则化参数的调优。(lambda , alpha)。这些参数可以降低模型的复杂度,从而提高模型的表现。   4、降低学习速率,确定理想参数。 1、max_depth和min_child_weight 首先设置固定的学习速率 learning rate,对max_depth、min_child_weight两个参数进行调优。

#max_depth和min_child_weight参数调优
# max_depth和min_child_weight参数对最终结果有很大的影响。max_depth通常在3-10之间,min_child_weight。采用栅格搜索(grid search),我们先大范围地粗略参数,然后再小范围的微调。
# 网格搜索scoring = 'roc_auc' 只支持二分类,多分类需要修改scoring(默认支持多分类)

param_test1 = {
'max_depth':[i for i in range(3,10,2)],
'min_child_weight':[i for i in range(1,6,2)]
}
from sklearn import svm, grid_search, datasets
from sklearn import grid_search
gsearch = grid_search.GridSearchCV(
estimator = XGBClassifier(
learning_rate =0.1,
n_estimators=140, max_depth=5,
min_child_weight=1,
gamma=0,
subsample=0.8,
colsample_bytree=0.8,
objective= 'binary:logistic',
nthread=4,
scale_pos_weight=1,
seed=27),
param_grid = param_test1,
scoring='roc_auc',
n_jobs=4,
iid=False,
cv=5)
gsearch.fit(X_train,y_train)
print('max_depth_min_child_weight')
print('gsearch1.grid_scores_', gsearch.grid_scores_)
print('gsearch1.best_params_', gsearch.best_params_)
print('gsearch1.best_score_', gsearch.best_score_)

gsearch1.grid_scores_ [mean: 0.89440, std: 0.03817, params: {'max_depth': 4, 'min_child_weight': 4}, mean: 0.89630, std: 0.03958, params: {'max_depth': 4, 'min_child_weight': 5}, mean: 0.88518, std: 0.05002, params: {'max_depth': 4, 'min_child_weight': 6}, mean: 0.89440, std: 0.03817, params: {'max_depth': 5, 'min_child_weight': 4}, mean: 0.89630, std: 0.03958, params: {'max_depth': 5, 'min_child_weight': 5}, mean: 0.88518, std: 0.05002, params: {'max_depth': 5, 'min_child_weight': 6}, mean: 0.89440, std: 0.03817, params: {'max_depth': 6, 'min_child_weight': 4}, mean: 0.89630, std: 0.03958, params: {'max_depth': 6, 'min_child_weight': 5}, mean: 0.88518, std: 0.05002, params: {'max_depth': 6, 'min_child_weight': 6}] gsearch1.best_params_ {'max_depth': 4, 'min_child_weight': 5} gsearch1.best_score_ 0.8962955796353629

我们得到max_depth的理想取值为4,min_child_weight的理想取值为5。同时,我们的得分有了小小一点提高(0.8864到0.8963)。 2、gamma

# gamma参数调优
#   在已经调整好其他参数的基础上,我们可以进行gamma参数的调优了。Gamma参数取值范围很大,这里我们设置为5,其实你也可以取更精确的gamma值。

from sklearn import svm, grid_search, datasets
from sklearn import grid_search
param_test3 = {
 'gamma':[i/10.0 for i in range(0,5)]
}
gsearch = grid_search.GridSearchCV(
estimator = XGBClassifier(
learning_rate =0.1,
n_estimators=140,
max_depth=4,
min_child_weight=5,
gamma=0,
subsample=0.8,
colsample_bytree=0.8,
objective= 'binary:logistic',
nthread=4,
scale_pos_weight=1,
seed=27),
param_grid = param_test3,
scoring='roc_auc',
n_jobs=4,
iid=False,
cv=5)
gsearch.fit(X_train,y_train)
print('gamma')
print('gsearch1.grid_scores_', gsearch.grid_scores_)
print('gsearch1.best_params_', gsearch.best_params_)
print('gsearch1.best_score_', gsearch.best_score_)

gsearch1.grid_scores_ [mean: 0.89630, std: 0.03958, params: {'gamma': 0.0}, mean: 0.89630, std: 0.03958, params: {'gamma': 0.1}, mean: 0.89630, std: 0.03958, params: {'gamma': 0.2}, mean: 0.89885, std: 0.04064, params: {'gamma': 0.3}, mean: 0.89282, std: 0.04636, params: {'gamma': 0.4}] gsearch1.best_params_ {'gamma': 0.3} gsearch1.best_score_ 0.8988476092191263

我们得到gamma的理想取值为0.4。同时,我们的得分又有了小小一点提高(0.8963到0.8988)。 3、subsample_colsample_bytree

#调整subsample 和 colsample_bytree参数
#   尝试不同的subsample 和 colsample_bytree 参数。我们分两个阶段来进行这个步骤。这两个步骤都取0.6,0.7,0.8,0.9作为起始值。
#取0.6,0.7,0.8,0.9作为起始值
from sklearn import svm, grid_search, datasets
from sklearn import grid_search
param_test4 = {
 'subsample':[i/10.0 for i in range(6,10)],
 'colsample_bytree':[i/10.0 for i in range(6,10)]
}

gsearch = grid_search.GridSearchCV(
estimator = XGBClassifier(
learning_rate =0.1,
n_estimators=177,
max_depth=4,
min_child_weight=5,
gamma=0.4,
subsample=0.8,
colsample_bytree=0.8,
objective= 'binary:logistic',
nthread=4,
scale_pos_weight=1,
seed=27),
param_grid = param_test4,
scoring='roc_auc',
n_jobs=4,
iid=False,
cv=5)
gsearch.fit(X_train,y_train)
print('subsample_colsample_bytree------------------')
print('gsearch1.grid_scores_', gsearch.grid_scores_)
print('gsearch1.best_params_', gsearch.best_params_)
print('gsearch1.best_score_', gsearch.best_score_)

subsample_colsample_bytree------------------ gsearch1.grid_scores_ [mean: 0.88900, std: 0.03849, params: {'colsample_bytree': 0.6, 'subsample': 0.6}, mean: 0.88783, std: 0.03607, params: {'colsample_bytree': 0.6, 'subsample': 0.7}, mean: 0.89162, std: 0.03423, params: {'colsample_bytree': 0.6, 'subsample': 0.8}, mean: 0.89827, std: 0.03363, params: {'colsample_bytree': 0.6, 'subsample': 0.9}, mean: 0.88919, std: 0.03723, params: {'colsample_bytree': 0.7, 'subsample': 0.6}, mean: 0.89715, std: 0.03549, params: {'colsample_bytree': 0.7, 'subsample': 0.7}, mean: 0.88918, std: 0.03390, params: {'colsample_bytree': 0.7, 'subsample': 0.8}, mean: 0.89838, std: 0.03134, params: {'colsample_bytree': 0.7, 'subsample': 0.9}, mean: 0.89807, std: 0.03173, params: {'colsample_bytree': 0.8, 'subsample': 0.6}, mean: 0.89174, std: 0.03980, params: {'colsample_bytree': 0.8, 'subsample': 0.7}, mean: 0.89615, std: 0.04389, params: {'colsample_bytree': 0.8, 'subsample': 0.8}, mean: 0.90298, std: 0.03024, params: {'colsample_bytree': 0.8, 'subsample': 0.9}, mean: 0.88920, std: 0.04164, params: {'colsample_bytree': 0.9, 'subsample': 0.6}, mean: 0.89951, std: 0.04025, params: {'colsample_bytree': 0.9, 'subsample': 0.7}, mean: 0.89765, std: 0.03318, params: {'colsample_bytree': 0.9, 'subsample': 0.8}, mean: 0.89922, std: 0.02492, params: {'colsample_bytree': 0.9, 'subsample': 0.9}] gsearch1.best_params_ {'colsample_bytree': 0.8, 'subsample': 0.9} gsearch1.best_score_ 0.9029777261781906

我们得到subsample的理想取值为0.9, colsample_bytree的理想值为0.8。同时,我们的得分又有了小小一点提高(0. 8988到0.9030)。 4、reg_alpha

#正则化参数调优reg_alpha
#   由于gamma函数提供了一种更加有效的降低过拟合的方法,大部分人很少会用到这个参数,但是我们可以尝试用一下这个参数。
from sklearn import svm, grid_search, datasets
from sklearn import grid_search
param_test6 = {
 'reg_alpha':[1e-5, 1e-2, 0.1, 1, 100]
}

gsearch = grid_search.GridSearchCV(
estimator = XGBClassifier(
learning_rate =0.1,
n_estimators=177,
max_depth=4,
min_child_weight=5,
gamma=0.4,
subsample=0.9,
colsample_bytree=0.8,
objective= 'binary:logistic',
nthread=4,
scale_pos_weight=1,
seed=27),
param_grid = param_test6,
scoring='roc_auc',
n_jobs=4,
iid=False,
cv=5)
gsearch.fit(X_train,y_train)
print('reg_alpha------------------')
print('gsearch1.grid_scores_', gsearch.grid_scores_)
print('gsearch1.best_params_', gsearch.best_params_)
print('gsearch1.best_score_', gsearch.best_score_)

reg_alpha------------------ gsearch1.grid_scores_ [mean: 0.90298, std: 0.03024, params: {'reg_alpha': 1e-05}, mean: 0.89911, std: 0.03017, params: {'reg_alpha': 0.01}, mean: 0.89911, std: 0.03198, params: {'reg_alpha': 0.1}, mean: 0.89181, std: 0.03346, params: {'reg_alpha': 1}, mean: 0.50000, std: 0.00000, params: {'reg_alpha': 100}] gsearch1.best_params_ {'reg_alpha': 1e-05} gsearch1.best_score_ 0.9029777261781906

我们得到reg_alpha的理想取值为1e-05。同时,我们的得分没变(0.9030)。 6、 reg_lambda

#正则化参数调优reg_lambda
#   由于gamma函数提供了一种更加有效的降低过拟合的方法,大部分人很少会用到这个参数,但是我们可以尝试用一下这个参数。
from sklearn import svm, grid_search, datasets
from sklearn import grid_search
param_test7 = {
 'reg_lambda':[1e-5, 1e-2, 0.1, 1, 100]
}
gsearch = grid_search.GridSearchCV(
estimator = XGBClassifier(
learning_rate =0.1,
n_estimators=177,
max_depth=4,
min_child_weight=5,
gamma=0.4,
subsample=0.9,
colsample_bytree=0.8,
objective= 'binary:logistic',
nthread=4,
scale_pos_weight=1,
seed=27),
param_grid = param_test7,
scoring='roc_auc',
n_jobs=4,
iid=False,
cv=5)
gsearch.fit(X_train,y_train)
print('reg_lambda------------------')
print('gsearch1.grid_scores_', gsearch.grid_scores_)
print('gsearch1.best_params_', gsearch.best_params_)
print('gsearch1.best_score_', gsearch.best_score_)

reg_lambda------------------ gsearch1.grid_scores_ [mean: 0.90298, std: 0.02792, params: {'reg_lambda': 1e-05}, mean: 0.89980, std: 0.02628, params: {'reg_lambda': 0.01}, mean: 0.89896, std: 0.03491, params: {'reg_lambda': 0.1}, mean: 0.90298, std: 0.03024, params: {'reg_lambda': 1}, mean: 0.87028, std: 0.04746, params: {'reg_lambda': 100}] gsearch1.best_params_ {'reg_lambda': 1} gsearch1.best_score_ 0.9029777261781906 我们得到reg_lambda'的理想取值为1。同时,我们的得分没变(0.9030)。

至此,我们的XGBoost就调参结束了,要想让模型有更好的表现,可以依靠其他手段,如特征工程(feature egineering) ,模型组合(ensemble of model),以及堆叠(stacking)等,有机会之后再介绍。

Reference: https://www.cnblogs.com/wj-1314/p/9402324.html

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-07-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python编程和深度学习 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
腾讯云 BI
腾讯云 BI(Business Intelligence,BI)提供从数据源接入、数据建模到数据可视化分析全流程的BI能力,帮助经营者快速获取决策数据依据。系统采用敏捷自助式设计,使用者仅需通过简单拖拽即可完成原本复杂的报表开发过程,并支持报表的分享、推送等企业协作场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档