机器学习(九):Xgboost原理与案例分析
一、简介
Xgboost(extreme Gradient Boosting,极端梯度提升)经常被用在一些比赛中,效果显著。它是大规模并行的boosted tree的工具,是目前最快最好的开源boosted tree工具包。XGBoost所应用的算法就是GBDT(gradient boosting decision tree)的改进,使之更强大,适用于更大的范围,既可以用于分类也可以用于回归问题。Boosting算法的思想是将许多弱分类器集成在一起,形成一个强分类器。因为Xgboost是一种提升树,所以它是将许多树模型集成在一起,形成一个很强的分类器。Xgboost一般和sklearn一起使用,但是由于sklearn中没有集成Xgboost,所以需要单独下载安装。
- 主要创新点
- 设计和构建高度可扩展的端到端提升树系统
- 提出了一个理论上合理的加权分位数略图来计算候选集
- 引入了一种新颖的稀疏感知算法用于并行树学习,令缺失值有默认方向
- 提出了一个有效的用于核外树形学习的缓存感知块结构。用缓存加速寻找排序后被打乱的索引的列数据的过程。
二、原理
1、Xgboost预测
Xgboost算法是和决策树算法联系到一起的,所以我们对不同叶子结点分配不同的权重项。此时我们的预测值,我们的目标函数,最优函数解,集成算法的表示,我们展开来表示一下,
2、树的复杂度
接下来定义树的复杂度,对于的定义做一下细化,把树拆分成结构函数q(输入x输出叶子结点索引)和叶子权重部分w(输入叶子结点索引输出叶子结点分数),结构函数q把输入映射到叶子的索引号上面去,而w给定了每个索引号对应的叶子分数是什么。
如果叶子结点的个数太多,那么过拟合的风险会越大,所以要限制叶子结点的个数,所以在原来目标函数里加上一个正则化惩罚项,我们来看一下如何计算, 此时的目标函数就变成了,
3、泰勒展开求解目标函数
为了求解这个方程式,我们采用泰勒展开近似来定义一个近似的目标函数,
4、定义树的结构
基于目标函数Obj,对结点进行分割,分别对左右子树求目标值,然后再对未分割之前的树结构进行求目标值,最后在所有特征离选择分割后,取Gain最高的那个特征。三、案例分析
使用到的数据集最初来自国家糖尿病/消化/肾脏疾病研究所。数据集的目标是基于数据集中包含的某些诊断测量来诊断性的预测患者是否患有糖尿病。这里的所有患者都是Pima印第安至少21岁的女性,数据集由多个医学预测变量和一个目标变量组成Outcome。预测变量包括患者的怀孕次数、BMI、胰岛素水平、年龄等。
我们先来看一下sklearn包中关于Xgboost的API:
xgboost.XGBClassifier(max_depth=3, learning_rate=0.1, n_estimators=100, verbosity=1, silent=None, objective="binary:logistic", booster='gbtree', n_jobs=1, nthread=None, gamma=0, min_child_weight=1, max_delta_step=0, subsample=1, colsample_bytree=1, colsample_bylevel=1, colsample_bynode=1, reg_alpha=0, reg_lambda=1, scale_pos_weight=1, base_score=0.5, random_state=0, seed=None, missing=None, **kwargs)
- 常规参数
booster
gbtree 树模型做为基分类器(默认)
gbliner 线性模型做为基分类器
silent
silent=0时,输出中间过程(默认)
silent=1时,不输出中间过程
nthread
nthread=-1时,使用全部CPU进行并行运算(默认)
nthread=1时,使用1个CPU进行运算。
scale_pos_weight
正样本的权重,在二分类任务中,当正负样本比例失衡时,设置正样本的权重,模型效果更好。例如,当正负样本比例为1:10时,scale_pos_weight=10。
- 模型参数
n_estimatores
含义:总共迭代的次数,即决策树的个数
调参:
early_stopping_rounds
含义:在验证集上,当连续n次迭代,分数没有提高后,提前终止训练。
调参:防止overfitting。
max_depth
含义:树的深度,默认值为6,典型值3-10。
调参:值越大,越容易过拟合;值越小,越容易欠拟合。
min_child_weight
含义:默认值为1,。
调参:值越大,越容易欠拟合;值越小,越容易过拟合(值较大时,避免模型学习到局部的特殊样本)。
subsample
含义:训练每棵树时,使用的数据占全部训练集的比例。默认值为1,典型值为0.5-1。
调参:防止overfitting。
colsample_bytree
含义:训练每棵树时,使用的特征占全部特征的比例。默认值为1,典型值为0.5-1。
调参:防止overfitting。
- 学习任务参数
learning_rate
含义:学习率,控制每次迭代更新权重时的步长,默认0.3。
调参:值越小,训练越慢。
典型值为0.01-0.2。
objective 目标函数
回归任务
reg:linear (默认)
reg:logistic
二分类
binary:logistic 概率
binary:logitraw 类别
多分类
multi:softmax num_class=n 返回类别
multi:softprob num_class=n 返回概率
rank:pairwise
eval_metric
回归任务(默认rmse)
rmse--均方根误差
mae--平均绝对误差
分类任务(默认error)
auc--roc曲线下面积
error--错误率(二分类)
merror--错误率(多分类)
logloss--负对数似然函数(二分类)
mlogloss--负对数似然函数(多分类)
gamma
惩罚项系数,指定节点分裂所需的最小损失函数下降值。
调参:
alpha
L1正则化系数,默认为1
lambda
L2正则化系数,默认为1
接下来我们开始使用里面的参数进行分类,首先先把需要的包写出来,
from xgboost import XGBClassifier
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from xgboost import plot_importance
import matplotlib.pyplot as plt
from sklearn.model_selection import GridSearchCV,StratifiedKFold
1、首先看一下数据集,并进行简单的处理
def dataset():
"""
获取数据集并进行处理
:return:
"""
# 获取数据集
data = pd.read_csv('../../数据集/机器学习/集成学习/糖尿病患者/PimaIndiansdiabetes.csv')
print(data)
# 将特征值与目标值分开
y = data.iloc[:, 8]
x = data.drop(columns='Outcome', axis=1)
# 分割成训练集与测试集
seed = 7
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.33, random_state=seed)
return x,y,x_train, x_test, y_train, y_test
if __name__ == "__main__":
x,y,x_train, x_test, y_train, y_test = dataset()
2、使用Xgboost进行分类预测
def xgboost(x_train, x_test, y_train, y_test):
"""
利用xgboost对癌症数据进行分类
:return:
"""
#xgboost进行训练
xgb = XGBClassifier()
xgb.fit(x_train,y_train)
y_predict = xgb.predict(x_test)
accuracy = accuracy_score(y_test, y_predict)
print("准确率:%.2f%%" % (accuracy*100))
return None
if __name__ == "__main__":
x,y,x_train, x_test, y_train, y_test = dataset()
xgboost(x_train, x_test, y_train, y_test)
3、将Xgboost损失函数的变化过程输出
def xgboot_steps(x_train, x_test, y_train, y_test):
"""
将xgboost选择树的过程分步展示
:return:
"""
xgb = XGBClassifier()
eval_set = [(x_test,y_test)]
xgb.fit(x_train, y_train,early_stopping_rounds=10,eval_metric="logloss",eval_set=eval_set,verbose=True)
y_predict = xgb.predict(x_test)
accuracy = accuracy_score(y_test, y_predict)
print("准确率:%.2f%%" % (accuracy*100))
if __name__ == "__main__":
x,y,x_train, x_test, y_train, y_test = dataset()
xgboot_steps(x_train, x_test, y_train, y_test)
通过上图我们发现,随着树的增加,损失函数在下降,在32
时达到最低,之后开始上升,说明在32
的时候效果最好。
4、画图观察8个特征的权重
def show_importance(x,y):
"""
画图展示出特征的重要程度
:return:
"""
xgb = XGBClassifier()
xgb.fit(x,y)
plot_importance(xgb)
plt.show()
return None
if __name__ == "__main__":
x,y,x_train, x_test, y_train, y_test = dataset()
show_importance(x,y)
5、使用网格搜索进行调优
def gridsearchCV(x_train, y_train):
"""
使用网格搜索进行超参数调优
:return:
"""
#1、learning rate 学习率
#2、tree(max_depth、min_child_weight、subsample、colsample_bytree、gamma
#3、gamma
#4、正则化参数(lambda、alpha)
learning_rate = [0.0001,0.001,0.01,0.1,0.2,0.3]
param_rate = dict(learning_rate=learning_rate) #必须是字典格式
#StratifiedKFold是一种将数据集中每一类样本数据按均等方式拆分的方法。
kfold = StratifiedKFold(n_splits=10,shuffle=True,random_state=7)
xgb = XGBClassifier()
grid_search = GridSearchCV(xgb,param_grid=param_rate,scoring="neg_log_loss",n_jobs=-1,cv=kfold)
grid_result = grid_search.fit(x_train,y_train)
print("Best:%f using %s" % (grid_result.best_score_,grid_result.best_params_))
means =grid_result.cv_results_['mean_test_score']
params = grid_result.cv_results_['params']
for mean,param in zip(means,params):
print("%f with: %r" % (mean,param))
if __name__ == "__main__":
x,y,x_train, x_test, y_train, y_test = dataset()
gridsearchCV(x_train, y_train)
四、补充:Adaboost算法
1、简介
AdaBoost,是英文"Adaptive Boosting"(自适应增强)的缩写,它的自适应在于:前一个基本分类器分错的样本会得到加强,加权后的全体样本再次被用来训练下一个基本分类器。同时,在每一轮中加入一个新的弱分类器,直到达到某个预定的足够小的错误率或达到预先指定的最大迭代次数。
2、算法流程
给定一个训练数据集其中实例,而实例空间,属于标记集合{-1,1},Adaboost的目的就是从训练数据中学习一系列弱分类器或基本分类器,然后将这些弱分类器组合成一个强分类器。
- 第一步
初始化训练数据的权值分布,如果有N个样本,则每一个训练样本最开始时都被赋予相同的权重:
- 第二步
训练弱分类器。具体训练过程中,如果某个样本点已经被准确地分类,那么在构造下一个训练集中,它的权重就被降低;相反,如果某个样本点没有被准确得分类,那么它的权重就得到提高。然后,权重更新过的样本集被用于训练下一个分类器,整个训练过程如此迭代地进行下去。
用m=1,2,...,M表示迭代的第多少轮- a.使用具有权值分布Dm的训练数据集学习,得到基本分类器:
- b.计算在训练集上的分类误差率
由上述式子可知,在训练数据集上的误差率就是被误分样本的权值之和。 - c.计算的系数,表示在最终分类器中的重要程度(目的:得到基本分类器在最终分类器中所占的权重)
由上述式子可知,时,,且随着的减少而增大,意味着分类误差率越小的基本分类器在最终分类器中的作用越大。 - d.更新训练数据集的权值分布(目的:得到样本的新的权值分布),用于下一轮迭代
使得被基本分类器误分类样本的权值增大,而被正确分类样本的权值减小。就这样通过这样的方式,AdaBoost方法能"聚焦于"那些较难分的样本上。其中,是规范化因子,使得成为一个概率分布:
- a.使用具有权值分布Dm的训练数据集学习,得到基本分类器:
- 第三步
将各个训练得到的弱分类器组合成强分类器。各个分类器的训练过程结束后,加大分类误差率小的弱分类器的权重,使其在最终的分类函数中起着较大的决定作用,而降低分类误差率大的弱分类器的权重,使其在最终的分类函数中起着较小的决定作用。换言之,误差率低的弱分类器在最终分类器中占的权重较大,否则较小。
组合各个弱分类器:从而得到最终分类器,如下:
举个例子,看一下是如何计算的(偷个懒,直接把图贴上来了),
3、案例
我们还是使用上面的数据集,用AdaBoost算法跑一遍看一下准确率,
- 首先我们先用网格搜索确定一下学习率的参数
def gridsearchCV(x_train, y_train):
"""
使用网格搜索进行超参数调优
:return:
"""
#1、learning rate 学习率
#2、tree(max_depth、min_child_weight、subsample、colsample_bytree、gamma
#3、gamma
#4、正则化参数(lambda、alpha)
learning_rate = [0.0001,0.001,0.01,0.1,0.2,0.3]
param_rate = dict(learning_rate=learning_rate) #必须是字典格式
#StratifiedKFold是一种将数据集中每一类样本数据按均等方式拆分的方法。
kfold = StratifiedKFold(n_splits=10,shuffle=True,random_state=7)
xgb = XGBClassifier()
grid_search = GridSearchCV(xgb,param_grid=param_rate,scoring="neg_log_loss",n_jobs=-1,cv=kfold)
grid_result = grid_search.fit(x_train,y_train)
print("Best:%f using %s" % (grid_result.best_score_, grid_result.best_params_))
ada = AdaBoostClassifier()
grid_search_ada = GridSearchCV(ada, param_grid=param_rate, scoring="neg_log_loss", n_jobs=-1, cv=kfold)
grid_result_ada = grid_search_ada.fit(x_train, y_train)
print("Best:%f using %s" % (grid_result_ada.best_score_, grid_result_ada.best_params_))
if __name__ == "__main__":
x,y,x_train, x_test, y_train, y_test = dataset()
gridsearchCV(x_train, y_train)
这是Xgboost和Adaboost算法learning_rate参数的最优值,然后我们分别看一下在最优参数下两个算法的准确率,
- 对比
def adaboost(x_train, x_test, y_train, y_test):
"""
使用adaboost算法进行分类预测
:return:
"""
ada = AdaBoostClassifier(learning_rate=0.01)
ada.fit(x_train,y_train)
y_predict = ada.predict(x_test)
accuracy = accuracy_score(y_test, y_predict)
print("准确率:%.2f%%" % (accuracy * 100))
return None
if __name__ == "__main__":
x,y,x_train, x_test, y_train, y_test = dataset()
xgboost(x_train, x_test, y_train, y_test)
adaboost(x_train, x_test, y_train, y_test)
上面是xgboost的准确率,下面是adaboost的准确率,虽然在这里可以看到adaboost的准确率稍微低一点,但是因为数据集和参数的原因(多个参数调优)结果不一定。有兴趣的同学可以去试一下!Xgboost算法的学习到这里就结束了,有不明白的同学可以在下方留言。