xgboost介绍与实践

参考:
终于把XGBoost总结写出来了!
机器学习算法之XGBoost及其自动调参
参考:xgboost如何处理缺失值

【机器学习基础】XGBoost、LightGBM与CatBoost算法对比与调参

介绍

2016年由华盛顿大学陈天奇老师带领开发的一个可扩展机器学习系统。严格意义上讲XGBoost并不是一种模型,而是一个可供用户轻松解决分类、回归或排序问题的软件包。内部实现了梯度提升树(GBDT)模型,并对模型中的算法进行了诸多优化,在取得高精度的同时又保持了极快的速度。
GBDT:XGBoost的原理、公式推导、Python实现和应用

原理

首先说下GBDT,它是一种基于boosting增强策略的加法模型,训练的时候采用前向贪心算法进行学习,每次迭代都学习一棵CART树来拟合之前 t-1 棵树的预测结果与训练样本真实值之间的残差。XGBoost是在GBDT基础上进行了一系列优化.比如损失函数采用了二阶泰勒展式、目标函数加入正则项、支持并行和缺失值自动处理等,但二者在核心思想上没有大的变化。

XGBOOST以正则化提升(Regularized Boosting)技术而闻名,通过代价函数里加入正则项,控制模型的复杂度,防止过拟合。可以实现并行处理,相比GBM有了很大的速度提升。

XGBOOST目标函数:

在这里插入图片描述
可以很清晰地看到,最终的目标函数只依赖于每个数据点在误差函数上的一阶导数和二阶导数

优势

XGBoost的优势:

  • 正则化:可有效防止模型过拟合

  • 并行处理 :XGBoost并行处理数据的速度要比普通提升树
    算法更快

  • 自动处理缺失数据:不做切分点,但会把缺失值放进左右子树看效果

  • 剪枝策略:普通的提升采用的是贪心算法,只有在不再有
    增益时才会停止分裂

  • 可以在目前树模型上继续迭代:xGBoost可以在训练中使用不同的迭代策略

相对于GBDT模型,XGBoost里面采用了如下的优化:

  • 对目标函数进行了泰勒展示的二阶展开,可以更加高效拟合误差。
  • 提出了一种估计分裂点的算法,加速CART树的构建过程,同时可以处理稀疏数据。
  • 提出了一种树的并行策略加速迭代。
  • 为模型的分布式算法进行了底层优化。

与其他算法对比

GBDT

在这里插入图片描述

随机森林

在这里插入图片描述

其他集成学习算法

XGBoost一方面通过引入正则项和列抽样的方法提高了模型稳健性,另一方面又在每棵树选择分裂点的时候采取并行化策略从而极大提高了模型运行的速度。

参数和调参

重要参数
params = {
    'booster':'gbtree', # gblinear
    '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参数

Booster参数通常就是tree booster的参数,因为linear booster的表现通常不如tree booster,因此很少使用。
1、eta(默认0.3),模型在更新时计算新的权重,通过减少每一步的权重,使模型更加保守,来防止过拟合。
2、gama(默认0),给定了损失函数的最低值,大于该值时节点才会分裂,该值越大模型越保守。
3、max_depth(默认6), 代表树的最大深度,该值越大模型对数据的拟合程度越高,适当控制最大深度可以防止模型过拟合,可以通过交叉验证cv函数来调参学习,通常取值范围在3-10之间。

目标函数参数

目标参数用来控制理想的优化目标和每一步输出结果的度量方法。
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 用于回归, error用于分类, mean average precision用于排序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),随机数的种子,设置该参数可以复现随机数据的结果,固定该值可以得到相同的随机划分。

调参

调优步骤

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

调参方法
网格搜索
c1f = xgb.XGBClassifier()
xgb_params = {'n_estimators': [10,20,30],'max_depth':[2,3,4,5]}
xgb_grid = GridSearchCV(c1f,xgb_params, scoring = 'roc_auc' ,cv = 5)
xgb_grid.fit(x_train, y_train)
print('xgb最佳参数', xgb_grid. best_params_)
 
随机搜索

随机搜索,顾名思义,即在指定的超参数范围或者分布上随机搜索和寻找最优超参数。相较于网格搜索方法,给定超参数分布内并不是所有的超参数都会进行尝试,而是会从给定分布中抽样一个固定数量的参数,实际仅对这些抽样到的超参数进行实验。相较于网格搜索,随机搜索有时候会是一种更高效的调参方法。Sklearn中通过model_selection模块下RandomizedSearchCV方法进行随机搜索。

在这里插入代码片
贝叶斯优化

贝叶斯优化是一种基于高斯过程(gaussian process)和贝叶斯定理的参数优化方法,近年来被广泛用于机器学习模型的超参数调优。 贝叶斯优化其实跟其他优化方法一样,都是为了为了求目标函数取最大值时的参数值。作为一个序列优化问题,贝叶斯优化需要在每一次迭代时选取一个最佳观测值,这是贝叶斯优化的关键问题。而这个关键问题正好被上述的高斯过程完美解决。贝叶斯优化可直接借用现成的第三方库BayesianOptimization来实现。

在执行贝叶斯优化前,我们需要基于XGBoost的交叉验证xgb.cv定义一个待优化的目标函数,获取xgb.cv交叉验证结果,并以测试集AUC为优化时的精度衡量指标。最后将定义好的目标优化函数和超参数搜索范围传入贝叶斯优化函数BayesianOptimization中,给定初始化点和迭代次数,即可执行贝叶斯优化。
方法1:
Hyperopt是一个sklearn的python库,在搜索空间上进行串行和并行优化,搜索空间可以是实值,离散和条件维度。

HyperOpt中文文档

  1. 初始化空间或所需的值范围:

  2. 定义目标函数

  3. 运行hyperopt功能

from hyperopt import hp, Trials,fmin, tpe, space_eval, STATUS_OK
 
space = { 
    'max_depth': hp.quniform('max_depth',3,18,1),
    'gamma': hp.uniform('gamma',1,9),
    'reg_alpha': hp.quniform('reg_a1pha',40,180,1),
    'reg_lambda': hp.uniform('reg_lambda',0,1),
    'colsample_bytree': hp.uniform('colsample_bytree',0.5,1),
    'min_child_weight': hp.quniform( 'min_child_weight',0,10,1),
    'n_estimators': 180
}
 
# Regression :
def hyperparameter_tuning(space) :
    model=xgb.XGBRegressor(
        n_estimators =space['n_estimators'], 
        max_depth = int(space[ 'max_depth']),
        gamma = space['gamma'],
        reg_alpha = int(
            space['reg_alpha'],
#             min_child_weight=space['min_child_weight'],
#             colsample_bytree=space['colsample_bytree']
        )
        ,
        min_child_weight=space['min_child_weight'],
        colsample_bytree=space['colsample_bytree']
    )#'min_child_weight' is an invalid keyword argument for int()
    
    evaluation = [(x_train,y_train),( x_test,y_test)]
    model.fit(
        x_train,y_train,
        eval_set=evaluation,
        eval_metric="rmse",
        early_stopping_rounds=10, 
        verbose=False
    )
    pred = model.predict(x_test)
    mse= mean_squared_error(y_test,pred)
    print ("SCORE: ",mse)
    #change the metric if you 1ike
    return { 'loss':mse, 'status': STATUS_OK,'model' : model}


trials = Trials()
best = fmin(
    fn= hyperparameter_tuning,
    space = space,
    algo = tpe.suggest,
    max_evals =100,
    trials = trials
)
print (best)
# {'colsample_bytree': 0.6517197241483893, 'gamma ': 8.634964326927877, 'max_depth': 7.0, 'min_child_weight': 5.0, 'reg_a1pha ': 44.0, 'reg_lambda': 0.6576218638777885}

方法2(python3.8 pip包下载有问题):

### 基于XGBoost的BayesianOptimization搜索范例
# 导入xgb模块
import xgboost as xgb
# 导入贝叶斯优化模块
from bayes_opt import BayesianOptimization
# 定义目标优化函数
def xgb_evaluate(min_child_weight,
                 colsample_bytree,
                 max_depth,
                 subsample,
                 gamma,
                 alpha):
    # 指定要优化的超参数
    params['min_child_weight'] = int(min_child_weight)
    params['cosample_bytree'] = max(min(colsample_bytree, 1), 0)
    params['max_depth'] = int(max_depth)
    params['subsample'] = max(min(subsample, 1), 0)
    params['gamma'] = max(gamma, 0)
    params['alpha'] = max(alpha, 0)
    # 定义xgb交叉验证结果
    cv_result = xgb.cv(params, dtrain, num_boost_round=num_rounds, nfold=5,
                   seed=random_state,
                   callbacks=[xgb.callback.early_stop(50)])
    return cv_result['test-auc-mean'].values[-1]

# 定义相关参数
num_rounds = 3000
random_state = 2021
num_iter = 25
init_points = 5
params = {
    'eta': 0.1,
    'silent': 1,
    'eval_metric': 'auc',
    'verbose_eval': True,
    'seed': random_state
}
# 创建贝叶斯优化实例
# 并设定参数搜索范围
xgbBO = BayesianOptimization(xgb_evaluate, 
                             {'min_child_weight': (1, 20),
                               'colsample_bytree': (0.1, 1),
                               'max_depth': (5, 15),
                               'subsample': (0.5, 1),
                               'gamma': (0, 10),
                               'alpha': (0, 10),
                                })
# 执行调优过程
xgbBO.maximize(init_points=init_points, n_iter=num_iter)

实践

安装:

pip install xgboost

API:
在XGBoost中其实包含了两套不同的API,虽然都在XGBoost包里,两种不同的API拥有两种不同的传输方式。

一种是将数据转化成XGBoost认识的DMatrix。
第二种兼容了Pthon的接受数据的方式:x_train,y_train。

回归

import xgboost as xgb

df = pd.DataFrame({'x':[1,2,3], 'y':[10,20,30]})
X_train = df.drop('y',axis=1)
Y_train = df['y']
T_train_xgb = xgb.DMatrix(X_train, Y_train)
params = {"objective": "reg:squarederror", "booster":"gblinear"}
gbm = xgb.train(dtrain=T_train_xgb,params=params)
Y_pred = gbm.predict(xgb.DMatrix(pd.DataFrame({'x':[4,5]})))
print(Y_pred)

可手动离散化(如年龄)

分类

标签是类别信息

import pandas
import xgboost
from sklearn import model_selection
from sklearn.metrics import accuracy_score
from sklearn.preprocessing import LabelEncoder
# load data
data = pandas.read_csv('iris.csv', header=None)
dataset = data.values
# split data into X and y
X = dataset[:,0:4]
Y = dataset[:,4]
# encode string class values as integers
label_encoder = LabelEncoder()
label_encoder = label_encoder.fit(Y)
label_encoded_y = label_encoder.transform(Y)
seed = 7
test_size = 0.33
X_train, X_test, y_train, y_test = model_selection.train_test_split(X, label_encoded_y, test_size=test_size, random_state=seed)
# fit model no training data
model = xgboost.XGBClassifier()
model.fit(X_train, y_train)
print(model)
# make predictions for test data
y_pred = model.predict(X_test)
predictions = [round(value) for value in y_pred]
# evaluate predictions
accuracy = accuracy_score(y_test, predictions)
print("Accuracy: %.2f%%" % (accuracy * 100.0))
'''
多分类 objective='multi:softprob'
XGBClassifier(base_score=0.5, colsample_bylevel=1, colsample_bytree=1,
       gamma=0, learning_rate=0.1, max_delta_step=0, max_depth=3,
       min_child_weight=1, missing=None, n_estimators=100, nthread=-1,
       objective='multi:softprob', reg_alpha=0, reg_lambda=1,
       scale_pos_weight=1, seed=0, silent=True, subsample=1)
Accuracy: 92.00%
'''

特征是类别信息,独热编码


encoded_x = None
for i in range(0, X.shape[1]):
	label_encoder = LabelEncoder()
	feature = label_encoder.fit_transform(X[:,i])
	feature = feature.reshape(X.shape[0], 1)
	onehot_encoder = OneHotEncoder(sparse=False, categories='auto')
	feature = onehot_encoder.fit_transform(feature)
	if encoded_x is None:
		encoded_x = feature
	else:
		encoded_x = numpy.concatenate((encoded_x, feature), axis=1)
print("X shape: : ", encoded_x.shape)

评估

分类

# 性能评估以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
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可以接受多种数据格式的输入,包括libsvm格式的文本数据、Numpy的二维数组、二进制的缓存文件。

处理缺失值NULL

xgboost模型却能够处理缺失值,也就是说模型允许缺失值存在。

论文中关于缺失值的处理将其看与稀疏矩阵的处理看作一样。在寻找split point的时候,不会对该特征为missing的样本进行遍历统计,只对该列特征值为non-missing的样本上对应的特征值进行遍历,通过这个技巧来减少了为稀疏离散特征寻找split point的时间开销。

在逻辑实现上,为了保证完备性,会分别处理将missing该特征值的样本分配到左叶子结点和右叶子结点的两种情形,计算增益后选择增益大的方向进行分裂即可。可以为缺失值或者指定的值指定分支的默认方向,这能大大提升算法的效率。如果在训练中没有缺失值而在预测中出现缺失,那么会自动将缺失值的划分方向放到右子树。

在这里插入图片描述

类别处理

XGBoost算法在进行模型训练时要先对分类变量进行数值化预处理,通常是用LabelEncoding或OneHotEncoding方法。

在xgboost模型中,使用了onehot编码后对结果提升不明显,甚至有时还会略为下降。查资料说,决策树模型可以不用onehot编码。独热编码这种操作通常适用于利用向量空间度量的算法,无序型分类变量的独热编码可以避免向量距离计算导致的偏序性。而对于树模型,通常不用独热编码,对分类变量进行标签化就行。

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值