Adaboost/Xgboost学习及实践

前言

博主最近因为一些杂事,最近忙于看CVPR17的相关进展,所以没有怎么进入深入的学习。近期准备写一下目前比较火的Xgboost算法。


学习Xgboost算法之前,先普及一下数据挖掘的小知识作为参考。国际权威的学术组织the IEEE International Conference on Data Mining (ICDM) 2006年12月评选出了数据挖掘领域的十大经典算法:C4.5, k-Means, SVM, Apriori, EM, PageRank, AdaBoost, kNN, Naive Bayes, and CART[1]。这些算法可以广泛的应用在模式识别,人工智能,大数据,数据统计,机器学习方面,而且都很经典。其实不止是选中的十大算法,其实参加评选的18种算法,随便拿出一种来都可以称得上是经典算法,它们在数据挖掘领域都产生了极为深远的影响。

集成学习介绍

这次介绍的Xgboost算法和被评选的AdaBoost都属于Boosting算法,而Boosting算法属于集成学习的一种方法。集成学习(ensemble learning)是目前非常火的机器学习方法[2,3]。它本身不是一个单独的机器学习算法,而是通过构建并结合多个机器学习器来完成学习任务。也就是我们常说的“博采众长”。集成学习可以用于分类问题集成,回归问题集成,特征选取集成,异常点检测集成等等,可以说所有的机器学习领域都可以看到集成学习的身影。集成学习中,同一类型的个体学习器集成是“同质”的,同质集成的个体学习器也叫基学习器(base learner)。集成包含不同类型的个体学习器,例如包含神经网络和决策树等,这样的集成就是“异质”的。异质集成的个体学习器由不同的学习算法生成,这时就不再有基学习算法;个体学习器也被称为“组件学习器”或直接叫个体学习器。
目前集成学习分为两大类,一类是个体学习器间存在强依赖关系、必须串行生成的序列化方法,以及个体学习器间不存在强依赖关系、可同时生成的并行化方法;前者的代表就是Boosting,后者的代表是Bagging和“随机森林”(Random Forest)。
 Adaboost/Xgboost学习及实践_第1张图片
集成学习示意图

Boosting简介

Boosting是一族可将弱学习器提升为强学习器的算法。这族算法的工作机制类似:先从初始训练集训练出一个集学习器,再根据基学习器的表现对训练样本分布进行调整,使得先前基学习器做错的训练样本在后续受到更多关注(权值更大),然后基于调整后的样本分布来训练下一个基学习器;如此重复进行,直至基学习器数目达到制定的值T,最终将T个基学习器进行加权结合。目前有很多种类,如AdaBoost、Generalized Boosted Models、XGBoost等。我们可以利用这样一个事实:损失函数可以表示为一个合适的形式进行优化(由于阶段性的可加性)。这就产生了一类广义Boosting算法,简称广义Boosting模型(Generalized Boosted Models,GBM)。
GBM的一个例子是梯度提升树(Gradient Boosted Tree,GBT),它使用决策树作为估计,采用负梯度下降的方法来进行迭代。它可以采用不同的损失函数解决不同的问题(回归,分类,风险建模等),评估它的梯度,并近似它与一个简单的树(分阶段地,最大限度地减少整体误差)。
以Boosting族算法最注明的代表AdaBoost(Adaptive Boosing)为例(PS:好多机器学习岗位都会有熟悉AdaBoost优先的描述,这是博主看了好多岗位之后发现的,当然顶会论文优先肯定是最重要的。),AdaBoost是一种特殊的情况下,使用指数损失函数的GBT。描述如下图所示:
 Adaboost/Xgboost学习及实践_第2张图片
具体的公式推导可参考周志华老师的机器学习这本书,很基础。这里面的需要强调的是Boosting算法要求基学习器对特定的数据分布进行学习,可以通过“重赋权法”(re-weighting)实施(上图所示的就是该方法)。而对于无法接受带权样本的基学习器算法,可以通过“重采样法”(re-sampling)来处理,即在每一轮的学习中,根据样本分布对训练集进行采样,再用重采样而得到的样本集对基学习器进行训练。一般两种方法没有显著的优劣差别。但是Boosting算法在训练每一轮都要对当前生成的基学习器进行检查是否满足基本条件(是否比随机猜测好),一旦条件不满足,该基学习器就会抛弃,学习过程停止,最终导致集成只包含很少的基学习器而性能不佳。若采用“重采样法”,可获得重启动的机会避免训练过早停止,即根据当前分布重新对训练样本进行采样,再基于新的采样结果进行训练。

简单Adaboost学习

然后接下来我们根据Python3.6(博主小本本用的Python3.6的,另外一个游戏本是2.7+3.6,但是家里没地方同时用)的具体程序,来学习一下基于单层决策树的AdaBoost训练过程。
新建adaboost.py脚本,先import numpy里的所有功能函数。
from numpy import *
构建Adaboost函数stumpClassify、buildStump。
Adaboost/Xgboost学习及实践_第3张图片

stumpClassify()函数是通过阈值比较对数据进行分类的,有4个参数值。所有的阈值一边的数据都会分到类别-1,另外一边的数据分到类别+1。该函数通过数组过滤来实现,首先将返回数组的第一维数据的长度值(也就是行数)设置为1,然后将所有满足不等式要求的设置为-1,不等式可以任意切换。该函数用于测试是否有某个值小于或者大于我们正在测试的阈值。

Adaboost/Xgboost学习及实践_第4张图片

buildStump()函数将会遍历stumpClassify()函数所有的可能输入值,并找到数据集上最佳的单层决策树。这里的“最佳”是根据参数D来定义的,在下一个函数中会有说明,是数据集的权重向量。该函数构建一个bestStump的空字典,这个字典储存给定权重向量D时所得到的最佳单层决策树的相关信息。变量numSteps用于在特征的所有可能值上进行遍历。变量minError一开始初始化为无穷大,之后用于寻找可能的最小错误率。
三层嵌套的for循环是程序最主要的部分。第一层for循环在数据集的所有特征上遍历。考虑到数值型的特征,我们就可以通过计算最小值和最大值来了解应该需要多大的步长。然后,第二层for循环再在这些值上遍历。甚至将阑值设置为整个取值范围之外也是可以的。因此,在取值范围之外还应该有两个额外的步骤。最后一个for循环则是在大于和小于之间切换不等式。
在嵌套的三层for循环之内,我们在数据集及三个循环变量上调用。stumpClassify()函数。基于这些循环变量,该函数将会返回分类预测结果。接下来构建一个列向量errArr,如果predictedVals中的值不等于labelMat中的真正类别标签值,那么errArr的相应位置为1。将错误向量errArr和权重向量D的相应元素相乘并求和,就得到了数值weightedError。这就是AdaBoost和分类器交互的地方。这里,我们是基于权重向量D而不是其他错误计算指标来评价分类器的。如果需要使用其他分类器的话,就需要考虑D上最佳分类器所定义的计算过程。
程序接下来输出所有的值。虽然这一行后面可以注释掉,但是它对理解函数的运行还是很有帮助的。最后,将当前的错误率与已有的最小错误率进行对比,如果当前的值较小,那么就在词典bestStump中保存该单层决策树。字典、错误率和类别估计值都会返回给AdaBoost算法。
Adaboost/Xgboost学习及实践_第5张图片
运行了简单的一个test,结果如上。

完整Adaboost算法实现

对上述的adaboost.py增加新的功能函数adaBoostTrainDS。
 Adaboost/Xgboost学习及实践_第6张图片
AdaBoost算法的输人参数包括数据集、类别标签以及迭代次数numIt,其中numIt是在整个AdaBoost算法中唯一需要用户指定的参数。我们假定迭代次数设为9,如果算法在第三次迭代之后错误率为0。那么就会退出迭代过程,因此,此时就不需要执行所有的9次迭代过程。每次迭代的中间结果都会通过print语句进行输出。
函数名称尾部的DS代表的就是单层决策树(decision stump ),它是AdaBoost中最流行的弱分类器,当然并非唯一可用的弱分类器。上述函数确实是建立于单层决策树之上的,但是我们也可以很容易对此进行修改以引人其他基分类器。实际上,任意分类器都可以作为基分类器,前面讲到的任何一个机器学习算法都行。上述算法会输出一个单层决策树的数组,因此首先需要建立一个新的Python表来对其进行存储。然后,得到数据集中的数据点的数目m,并建立一个列向量D。
向量D非常重要,它包含了每个数据点的权重。一开始,这些权重都赋予了相等的值。在后续的迭代中,AdaBoost算法会在增加错分数据的权重的同时,降低正确分类数据的权重。D是一个概率分布向量,因此其所有的元素之和为1。0。为了满足此要求,一开始的所有元素都会被初始化成1/m。同时,程序还会建立另一个列向量aggClassEst,记录每个数据点的类别估计累计值。
AdaBoost算法的核心在于for循环,该循环运行numIt次或者直到训练错误率为0为止。循环中的第一件事就是利用前面介绍的buildStump()函数建立一个单层决策树。该函数的输人为权重向量D,返回的则是利用D而得到的具有最小错误率的单层决策树,同时返回的还有最小的错误率以及估计的类别向量。
接下来,需要计算的则是alpha。该值会告诉总分类器本次单层决策树输出结果的权重。其中的语句max(error, 1e-16)用于确保在没有错误时不会发生除零溢出。而后,alpha值加入到bestStump字典中,该字典又添加到列表中。该字典包括了分类所需要的所有信息。
接下来的三行则用于计算下一次迭代中的新权重向量D。在训练错误率为。时,就要提前结束for循环。此时程序是通过aggClassEst变量保持一个运行时的类别估计值来实现的。该值只是一个浮点数,为了得到二值分类结果还需要调用sign()函数。如果总错误率为0,则由break语句中止for循环。
整个程序和Adaboost算法的描述图(最上面)一致。里面的基学习器可以随意替换。
运行的简单的test,结果如下(将buildStump的print注释了,可以更简单清晰)。
 Adaboost/Xgboost学习及实践_第7张图片

1.3 Bagging和随机森林(random forest)

Bagging是并行式集成学习方法最著名的代表。从名字即可看出,它是直接基于自助采样法((bootstrap sampling)的。给定包含m个样本的数据集,我们先随机取出一个样本放入采样集中,再把该样本放回初始数据集,使得下次采样时该样本仍有可能被选中,这样,经过m次随机采样操作,我们得到含。个样本的采样集,初始训练集中有的样本在采样集里多次出现,有的则从未出现。由下式可知
 
初始训练集中约有63。2%的样本出现在采样集中。
照这样,我们可采样出T个含m个训练样本的采样集,然后基于每个采样集训练出一个基学习器,再将这些基学习器进行结合。这就是Bagging的基本流程。在对预测输出进行结合时,Bagging通常对分类任务使用简单投票法,对回归任务使用简单平均法。若分类预测时出现两个类收到同样票数的情形,则最简单的做法是随机选择一个,也可进一步考察学习器投票的置信度来确定最终胜者。Bagging的算法描述如下图所示。
 Adaboost/Xgboost学习及实践_第8张图片
随机森林(random forest)是Bagging的一个扩展变体,这里就不多叙述了。周志华老师前一段还出了一个paper,Towards An Alternative to Deep Neural Networks[4],是采用的deep learning加random forest的做法,还是挺有新颖性的,有兴趣的可以自己看看。

1.4 Boosting基本方法对比

现在让我们来看看如何在实践中快速的应用该类方法。上节内容介绍的是简单的函数程序,这次我们直接采用现有的包解决实际问题。

本节内容中采用scikit- learn包提供的所有包。首先导入所有需要的库(本节运行在linux的notebooks)。

Adaboost/Xgboost学习及实践_第9张图片

准备数据

在本节所有的例子中,我们将讨论二分类问题作为测试。生成20维人工数据集,包含1000个样本,其中8个特征包含信息,3个冗余,2个重复。


然后我们采用split将数据分割成训练/测试部分,这对于所有方法的验证是有必要的。


在深入研究算法之前,让我们执行一个目标变量分布的检查以确保数据的完整性。

Adaboost/Xgboost学习及实践_第10张图片

(1)我们首先采用决策树方法来进行预测,首先创建一个决策树。使用训练数据进行学习,并使用测试样本对结果进行评估。

Adaboost/Xgboost学习及实践_第11张图片

我们可以看到两个明显的结果:

1、Loss值有些偏高(因为决策树的叶子输出为0或1,这在预测错误时会有严重的惩罚。但是accuracy分数相当不错,)

我们来检查一下前几个预测的输出,可以看到5个分类中只有2个实例被正确分类。

Adaboost/Xgboost学习及实践_第12张图片


2、树是复杂的(有大量节点),我们通过image来显示一下决策树图

Adaboost/Xgboost学习及实践_第13张图片

(2)我们采用Adaboost来对该实例进行预测,我们创建一个运行在1000次迭代上的AdaBoost分类器(创建1000棵树)。我们采用最流行的单层决策树(也被称为decision stump),跟上节用的一样,每颗树根据单一特征来进行分类。我们也将使用SAMME算法来处理离散数据(base_estimator的输出为0或1)。

Adaboost/Xgboost学习及实践_第14张图片

Loss值远低于单一决策树(主要是因为我们获得的是概率输出)。精度是相同的,但是注意到树的结构要简单得多。因为我们创建了1000个单层决策树。

此外,我们还可以快速查看一下预测值,在5个实例的测试中有4个是正确分类的。

Adaboost/Xgboost学习及实践_第15张图片

顺便来查看一下第一棵树图。

Adaboost/Xgboost学习及实践_第16张图片

在最后的计算中,该树的错误值和重要值(即决策树权重向量D中的权值)如下,该树的重要性比较高:


(3)我们采用GBT方法来计算一次,我们构建一个1000棵树组成的一个梯度提升树,这1000棵树中每棵连续的树都是通过梯度优化来创建的。同样,我们将把大多数参数留给它们的默认值,只指定树的最大深度为1(同样为单层决策树),并为更智能的计算设置warm_start = True。

Adaboost/Xgboost学习及实践_第17张图片

得到的结果显然是所提出的算法中最优的。我们已经得到了最精确的算法,给出了关于分类概率的更合理的预测。

Adaboost/Xgboost学习及实践_第18张图片

不同的是,GBC(Gradient Boosting Classifier)使用的是以均值-平方误差作为标准值的决策树分类器。这个结果与树的输出略有不同——现在叶子包含的是一个预测值。

Adaboost/Xgboost学习及实践_第19张图片

1.5 XGBoost

Xgboost近几年比较火,在Kaggle比赛中结构化数据(简单来说就是数据库。结构化数据也称作行数据,是由二维表结构来逻辑表达和实现的数据,严格地遵循数据格式与长度规范,主要通过关系型数据库进行存储和管理。与结构化数据相对的是不适于由数据库二维表来表现的非结构化数据,包括所有格式的办公文档、XML、HTML、各类报表、图片和咅频、视频信息等。)的竞赛项目中取得了非凡的成绩,在机器学习领域取得的成绩要远超过其余机器学习的方法(SVM、logistic regression. etc)

在以决策树为基函数的Boosting方法为BoostingTree方法,此类方法的大多数树包的问题是,他们不会非常重视正规化问题-他们允许生成许多非常相似的树木,该类树有时还会很茂密,这都会导致过拟合问题。

而在GBT中则尝试加入一些正则化参数的方法这个问题。我们可以:

控制树结构(最大深度,每叶的最小样本),

控制学习率,

通过引入随机性降低方差(stochastic gradient boosting-使用随机的实例和特征样本)等方法。

而我们可以通过使用XGBoosting更加进一步改善正规化问题。

1.5.1 XGBoost理论

XGBoost(极端梯度)是一个更正规化版本的梯度提高树。这是陈天奇用C++开发的,也为Python做了接口,R, Julia用于监督学习问题在Kaggle的许多比赛中获胜。该方法的主要优势:
良好的偏差(简单预测)权衡“出箱”,
计算速度快,
包是不断改进的(作者愿意接受从社区的许多性能要求)。
XGBoost的目标函数是通过特定损失函数在所有预测的评估值总和加上所有预测变量的正则化项的总和(以K个树为例)。公式中的意味着预测值来自于第k个树。 


损失函数取决于正在执行的任务(分类,回归等),正则化项如下方程:

 
第一部分是负责控制创建叶片的总数,第二部分监视每一个叶片的分数。算法通过使用梯度下降法来进行优化目标,这也产生了如何寻找一个最佳结构的连续树的问题。

1.5.2 Xgboost实践

(1)标准接口实践

我们首先要下载相应的库文件numpy和xgboost。


加载数据。我们将使用捆绑的Agaricus数据集,下载地址:
https://github.com/dmlc/xgboost/tree/master/demo/data。
这个数据集记录了不同蘑菇种类的生物属性,目标是预测它是否有毒。这个数据集包括了在Agaricus和Lepiota家族中有23种蘑菇的假设样本的描述。每个物种都被认定为绝对食用,绝对有毒,或不为人知,不推荐。后者与有毒的一种结合在一起。该指南明确指出,没有简单的规则来确定蘑菇的可食性;它由8124个实例组成,具有22个属性(数字和分类)。目标分类要么是0,要么是1,这意味着是一个二分类问题。
重要提示:XGBoost只处理数字变量。
所有的数据都已经为我们准备好了。分类变量已经被编码,所有的实例被分成训练和测试数据集。数据需要存储在DMatrix对象中,用于处理稀疏数据集。它可以用一下几种方式填充:
使用libsvm格式txt文件,
使用Numpy 2D数组(最流行),
使用XGBoost二进制缓冲文件
在这种情况下,我们将使用第一种选择。
Libsvm文件只存储格式中的非零元素,任何缺失的特征都表明它的对应值为0。如下表示:


我们查看一下数据集情况


训练数据集包含6513行和127列
测试数据集包含1611行和127列

训练labels如下所示,为二分类问题。

Adaboost/Xgboost学习及实践_第20张图片

我们设定好训练参数,让我们假设算法参数如下:

Adaboost/Xgboost学习及实践_第21张图片

为了训练分类器,我们简单地传递给它一个训练数据集,参数列表和关于迭代次数的信息。


我们还可以使用watchlist观察测试数据集的性能

Adaboost/Xgboost学习及实践_第22张图片

作出预测


通过简单的准确率计算以验证结果。当然,正常过程我们应该对数据的验证集执行验证,但在这种情况下,准确性是足够的。

Adaboost/Xgboost学习及实践_第23张图片

(2)使用Scikit-learn接口

需要下载如下所需要的库

Adaboost/Xgboost学习及实践_第24张图片

使用数据集,和(1)使用的相同的数据集。

scikit- learn包提供了一个方便的函数load_svmlight,可以同时读取许多libsvm文件,并将它们存储为Scipy的稀疏矩阵。


检查load的数据集

Adaboost/Xgboost学习及实践_第25张图片

指定训练参数,所有的参数跟前面的示例相同设置:

Adaboost/Xgboost学习及实践_第26张图片

开始训练分类器


开始预测


计算error值

Adaboost/Xgboost学习及实践_第27张图片

两种不同接口的Xgboost方法介绍完毕,接下来章节将介绍更深入的学习过程。

1.6 深入学习XGBoost

1、本节内容主要介绍如何区分数据集中的特性的相对重要性。我们可以找出是什么驱动了树的分割,以及我们可以在特性工程上做出的一些改进。

装载相关库xgboost、seaborn、pandas

Adaboost/Xgboost学习及实践_第28张图片

装载数据,和上节所用的数据集相同


我们指定训练参数-使用5个单层决策树以及平均学习率。

Adaboost/Xgboost学习及实践_第29张图片

开始训练模型,我们同样采用watchlist查看测试性能

Adaboost/Xgboost学习及实践_第30张图片

在构建树的过程中被多次地划分(我们的例子中只有一次)—这个操作称为split。为了完成split,算法必须计算出哪个是最好的特征然后去使用。

在那之后,在我们的底部,我们得到树叶的观察。

在最终的模型中,这些树叶对于每棵树来说应该尽可能的纯净,每一个叶子都应该由一个标签类组成。

并不是所有的split都同样重要。基本上,树的第一个split会对纯度产生更大的影响。直观上,我们理解第一个split做了大部分工作,接下来的split集中在数据集被第一棵树错误地分类的那一部分,这部分工作比较少。

同样,在Boosting中,我们试图优化每一轮的错误分类(它被称为损失)。所以第一棵树将会做大的工作,下面的树将会集中在剩下的工作上,这部分工作在之前的树上没有正确的学习。

每一次split操作带来的提升都可以衡量,这就是收获。

-引用自Kaggle 陈天奇的Kaggle notebook。

让我们来研究一下树的样子:

Adaboost/Xgboost学习及实践_第31张图片

对于每一个split,我们得到以下细节:
1、这个特征被用来split,
2、可能的选择去生成(分支)
3、gain是通过特征得到的真实提升值。之前的想法是,在特征X上添加一个新的split到有一些有错误分类的分支上,通过增加split到这个特征后,将会有两个新的分支,这些每一个分支都会更准确。
4、cover测量与该特征相关的观测的相对数量
可视化
希望有更好的方法来弄清楚哪些特征才是真正重要的。我们可以使用内置函数plot_importance,它将创建一个根据标准而呈现最重要特性的绘图。我们将分析每个特征对所有splits和所有树的影响,并可视化结果。
查看哪些特征提供了最多的增益:

Adaboost/Xgboost学习及实践_第32张图片

我们可以通过引入f–score使得结果更显而易见。F-score表示了每个特征上执行的split的次数。

Adaboost/Xgboost学习及实践_第33张图片

偏差(bias error)和方差(varianceerror)的权衡

接下来我们展示如何处理偏差/方差权衡的可视化,这是常见的机器学习问题。

分类器有两种常见的误差——偏差和方差误差。

偏差是是预测值(估计值)的期望与真实值之间的差异程度,偏差越大,越偏离真实数据。

方差是是预测值的变化范围,离散程度,也就是离其期望值的距离,方差越大,数据的分布越分散。

我们所期望的状态是两个错误都尽可能低。从 ScottFortmann-Roe's blog 的博客上的图形可以很好地将这个问题可视化。假设目标的中心是完美的模型。我们重复我们的实验,重创建模型并在相同的数据点上使用它。

Adaboost/Xgboost学习及实践_第34张图片

欠拟合和过拟合

了解了偏差和方差引入的错误,我们可以着手处理这些与训练模型有关的问题。我们将使用从scikit-学习文档中获取的图来帮助我们可视化那些欠拟合和过拟合的问题。

2、为了量化描述的效果,我们将训练模型几次,以选择不同的参数值。让我们考虑一下,我们想要找到一个最优的树数——我们不希望模型非常简单,但目前我们也不想让模型过于复杂。

我们将会:

生成复杂的二分类数据集,

使用Scikit-learn包,

使用10次交叉循环验证对树的不同值进行建模(n_estimators)训练

绘图训练/测试误差

从加载所需的库开始,设置随机的种子数

Adaboost/Xgboost学习及实践_第35张图片

然后生成人工数据集

我们将分为10折交叉验证 (相同的标签平均分布在每个交叉集中)进行测试

让我们来看看树的数量如何影响预测的准确性:

Adaboost/Xgboost学习及实践_第36张图片

显示验证曲线图:

Adaboost/Xgboost学习及实践_第37张图片

Adaboost/Xgboost学习及实践_第38张图片

看看这个图,我们可以得出以下结论:

在增加新树的同时,训练分数也在不断增加,但从某种程度上来说,交叉验证的分数是固定的

方差是最低的,低于25棵树的偏差很高,

从大约25棵树中,方差越来越大,而交叉验证值偏倚保持稳定(没有必要增加额外的树/复杂度)

我们可以看到,模型在增加复杂度时保持了稳定的方差

我们可以假设在n_estimators = 50中实现模型的稳定。但是模型的方差仍然很大。

我们可以通过那些方式来进行优化这些问题呢?

(1)处理高方差

如果模型太过于复杂,我们可以尝试:

用更少的功能(即,特征选择),

使用更多的训练样本(即,人工生成的),

增加规则化(增加惩罚对额外的复杂性)

在XGBoost中,我们可以尝试:

降低每棵树的深度(max_depth)

增加min_child_weight参数,

增加γ(gamma)参数,

使用subsample,colsample_bytree参数添加更多的随机性,

增加lambda和alpha正则化参数

(2)处理高偏差

如果模型太简单的话:

添加更多的功能(即,更好的功能工程),

更复杂的模型

减少正规化

在XGBoost中,你可以这样做:

增加每棵树的深度(max_depth)

减少min_child_weight参数,

减少γ参数,

减少lambda和alpha正则化参数

让我们稍微调整一下参数。我们将增加一些随机性——我们将使用70%随机选择的样本和60%随机选择的特征。这应该有助于减少方差。为了减少偏差(更大的准确性),尝试为每棵树增加一个额外的等级。

Adaboost/Xgboost学习及实践_第39张图片

Adaboost/Xgboost学习及实践_第40张图片


我们得到了一个更小的方差模型,偏差也有所减小。

3、超参数调优

我们学习机器学习的都知道,模型优化,调参都是一门技巧活(好多时候也是瞎蒙凭感觉),有很多的可调参数。每一个参数都有可能导致不同的输出。问题是哪种组合结果最好呢。

下面的notebook将向您展示如何使用Scikit-learn模块为您的模型找出最佳的参数。

首先import 相关库

Adaboost/Xgboost学习及实践_第41张图片

生成人工数据集以及定义交叉验证参数

(1)传统网格搜索

在网格搜索中,我们首先定义一个包含我们想要测试的参数值的字典。所有的组合都将被评估。

Adaboost/Xgboost学习及实践_第42张图片

为固定参数添加字典。

Adaboost/Xgboost学习及实践_第43张图片

创建一个GridSearchCV 评估器。我们通过该函数寻找准确最高的组合。

Adaboost/Xgboost学习及实践_第44张图片
在运行计算之前,我们应该知道我们将创建有3 * 4 * 3 * 10 = 360 个模型来测试所有组合。我们应该对将要的计算有大致的估计。
Adaboost/Xgboost学习及实践_第45张图片
现在,我们可以查看所有获得的分数,并手动查看什么是重要的,什么是不重要的。快速浏览一下,就会发现更多的n_estimator的准确性更高。
Adaboost/Xgboost学习及实践_第46张图片

如果有很多结果,我们可以手动过滤它们以获得最好的组合。

Adaboost/Xgboost学习及实践_第47张图片

寻找最佳参数是一个迭代过程。我们应该从粗粒度的开始进行优化,然后转向更详细的参数进行优化。

(2)随机网格搜索

当参数的数量和它们的值越来越大时,传统的网格搜索方法很快就变得无效了。一个可能的解决方案可能是随机从它们的分布中选取某些参数。虽然这不是一个完美的解决方案,但值得一试。

创建一个参数分布字典:

Adaboost/Xgboost学习及实践_第48张图片

初始化RandomizedSearchCV,随机选取10个参数组合。通过这种方法,我们可以轻松地控制已测试模型的数量。

Adaboost/Xgboost学习及实践_第49张图片

生成分类器

Adaboost/Xgboost学习及实践_第50张图片

再次看一下选择的参数和它们的准确性分数:

Adaboost/Xgboost学习及实践_第51张图片

最佳的评估器、参数值和得分


4.结果评估

在本节notebook中,我们将学习如何度量算法的性能。

开始准备相关的库文件

Adaboost/Xgboost学习及实践_第52张图片

加载agaricus数据集:


设置训练参数——我们将使用平均学习率的5个决策树。

Adaboost/Xgboost学习及实践_第53张图片

在训练这个模型之前,我们还可以指定watchlist数组来观察它在两个数据集上的性能。


使用预定义的评估指标

哪些指标是直接可用的呢?

已经有一些预定义的评估标准。您可以在训练模型时使用它们作为eval_metric参数的输入。

rmse -均方根误差,

mae-平均绝对误差,

logloss——负对数损失函数

error-二分类错误率。它采用(错误的情况)/(所有情况)来计算的。

merror -多类分类错误率。计算的方式为(错误的情况)/ (所有情况),

auc –曲线下面积

ncg -归一化的贴现累计收益,

map-平均平均精度

默认情况下将使用error度量。

Adaboost/Xgboost学习及实践_第54张图片

如果需要修改评估标准的话,只需将eval_metric参数指定到params字典。

Adaboost/Xgboost学习及实践_第55张图片

当然也可以同时使用多个评估标准

Adaboost/Xgboost学习及实践_第56张图片

创建自定义评价标准值

为了创建我们自己的评估指标,唯一需要做的是创建一个方法,采用两个参数——预测概率和DMatrix对象持有的数据。

在下面的实例中,我们的分类度量将简单地计算错误分类示例的数量,默认的概率p>0.5的类是积极性的。如果我们想要的概率值作为阈值,那就可以改变这个参数。

当错误分类的例子越来越少的时候,算法就会变得越来越好。记住在训练时也要设置参数maximize= False

Adaboost/Xgboost学习及实践_第57张图片

我们可以发现,即使params字典持有eval_metric的key值,这些值也被feval忽略和覆盖。

提取评价结果

我们可以通过声明保存值的字典,并将其作为eval_result参数的参数传递来获得评估分数。

Adaboost/Xgboost学习及实践_第58张图片

我们可以重新用这么参数来进行后续操作,比如print、plot等


早期停止

在选择合适的树数量时,有一个很好的优化技巧。

我们可以训练该模型直到某个验证分数时停止继续优化。验证时需要减少每个early_stopping_rounds来继续训练。这种方法的结果更简单,因为树的最低数量将被找到(简单性)。

在下面的实例中,将创建总数为1500棵树,但是如果验证分数在最近的10次迭代中没有改善,我们就告诉它停止。

Adaboost/Xgboost学习及实践_第59张图片

当使用early_stopping_rounds参数时,模型将会产生有3个额外的字段- bst.best_score,bst。best_iteration bst.best_ntree_limit。

Adaboost/Xgboost学习及实践_第60张图片

交叉验证结果

自带的包提供了一个用于交叉验证结果的选项(但不像Sklearn包那样复杂)。下一个输入将显示基本的执行方法。注意,我们只传递一个DMatrix参数,而我们可以将训练集和测试集合并到一个对象中,以获得更多的训练样本将是有利的。

Adaboost/Xgboost学习及实践_第61张图片

注意:

默认情况下,我们得到一个pandas数据帧对象(可以用as_pandas参数来改变),

通过作为参数传递指标(允许使用多值),

我们可以使用自己的评估指标(参数中的feval和maximize),

我们可以使用早期停止特性(参数early_stopping_rounds)

5、处理缺失值

下面的notebook展示了XGBoost对缺失值的处理。两种方法——原包接口和Sklearn包针对缺少的数据集进行测试。

缺失值经常在真实的数据集中出现。处理丢失值上,没有规则能够适用于所有的情况,因为缺少值的原因有很多种。

首先import所有的库

Adaboost/Xgboost学习及实践_第62张图片

让我们准备一个没有缺失值的有效数据集。有10个样本,每一个样本将包含5个随机生成的特征,每个样本根据5个特征划进行二分类问题。

Adaboost/Xgboost学习及实践_第63张图片

我们增加一些缺失值

Adaboost/Xgboost学习及实践_第64张图片

生成目标变量,随机生成0/1的目标label

Adaboost/Xgboost学习及实践_第65张图片

(1)原包接口

在本例中,我们将检查原包接口如何处理丢失的数据。从专门的默认参数开始。

Adaboost/Xgboost学习及实践_第66张图片

在第一个实例中,我们将创建一个有效的DMatrix(带有所有值),看看它是否可行,然后再重复这个过程。


交叉验证结果

Adaboost/Xgboost学习及实践_第67张图片

输出显然没有任何意义,因为数据完全是随机的。

当创建DMatrix时,我们必须明确表示它丢失了什么。有时可能是0,999或者是其他。在我们的例子中是Numpy 格式下的NAN来表示的。增加missing参数为DMatrix构造函数来处理它。


然后进行交叉验证

Adaboost/Xgboost学习及实践_第68张图片

虽然因为随机的数据导致这个结果跟之前一样,但是这个方法是适用于缺失值处理的。

在XGBoost包中,选择的是软方法来处理缺失值。

当使用带有缺失值的特性来进行拆分时,XGBoost将为缺失值分配一个方向,而不是数值。

具体地说,XGBoost将所有的带有缺失值的数据点分别指向左方和右方,然后在关系到目标时选择更高增益的方向。

(2)Sklearn

下面的部分展示了如何使用Sklearn接口验证相同的内容。

首先定义参数并创建一个估计对象。

Adaboost/Xgboost学习及实践_第69张图片

用完整的数据集交叉验证结果。因为我们只有10个样品,所以我们只需要做2折的交叉验证。


我们得到了一些分数,我们不会深入研究它的解释。

看看目标是否也有缺失的值

这两种方法都适用于缺少的数据集。缺失情况下,Sklearn包处理带有np.nan作为缺失数据。(如果使用不同的缺失值标记,就需要额外的预处理)。

6、处理不平衡数据集

处理不平衡数据集

在现实世界的问题中,有很多例子处理不平衡的目标类别。想象一下医疗数据,在成千上万个阴性(正常)的例子中,只有少数阳性的例子。另一个例子可能是分析欺诈交易,在这种交易中,实际的欺诈只占所有可用数据的一小部分。

不平衡数据指的是分类问题,其中的类不是均匀分布的。

一般建议:

当接近不平衡的数据集时,这些都是常用的策略:

收集更多的数据,

使用更好的评估指标(error、AUC、F1、Kappa,…)

尝试过抽样少数类别或低抽样多数类别,

生成少数群体的人工样本(SMOTE算法)

在XGBoost中,我们可以尝试如下方法:

确保参数min_child_weight很小(因为叶节点可以有较小的大小组),默认设置为min_child_weight = 1,

对DMatrix进行调整时为特定的样本分配更多的权重,

使用set_pos_weight参数控制正负权重的平衡,

使用AUC评价

实践部分,首先装载必要的库

Adaboost/Xgboost学习及实践_第70张图片

我们将使用一个函数来生成二进制分类的数据集。为了保证它不平衡使用权重参数。在这种情况下,将会有200个样本,每个样本有5个特征,但只有10%(大约20个样本)是阳性的。这让问题变得更加棘手。

Adaboost/Xgboost学习及实践_第71张图片

将创建的数据划分为训练集和测试集。记住,这两个数据集在分布上都应该是相似的。

Adaboost/Xgboost学习及实践_第72张图片

基准模型

在这种方法中,试着完全忽略分类是不平衡的事实,看看它是如何执行的。为训练和测试数据创建DMatrix


假设我们将创建15个单层决策树,解决二分类问题,每个决策树将会非常积极地进行训练。
这些参数也将在连续的例子中使用。

Adaboost/Xgboost学习及实践_第73张图片

训练booster并做出预测

生成结果

Adaboost/Xgboost学习及实践_第74张图片

我们还可以使用3个不同的评估指标来展示模型: 

Adaboost/Xgboost学习及实践_第75张图片

自定义权重

让我们指定正例样本有5x的权重,并在创建DMatrix时添加这些信息。

Adaboost/Xgboost学习及实践_第76张图片

训练分类器并进行预测


生成结果

Adaboost/Xgboost学习及实践_第77张图片

我们在这里做了一个指标上的权衡。我们现在可以更好地对少数群体进行分类,但整体的准确性和精度却降低了。我们可以测试多种权重组合,看看哪个最有效。

使用scale_pos_weight参数

我们可以通过计算负性和正例之间的比例,并将其设置为scale_pos_weight参数,来实现手动分配权重的过程。

初始化数据集


计算两个类之间的比率,并将其赋值给一个参数。


生成结果

Adaboost/Xgboost学习及实践_第78张图片

我们可以看到,在本例中使用scale_pos_weight参数手动来增减权重,这样做的效果更好。我们现在可以完美地分类所有的posivie类(这也是我们需要做的真正的问题)。另一方面,分类器有时会错误地将负面情况分类为正(产生所谓的假阳性)。

 


后记:其实目前Deep learning很火热,现在采用的一些tricks大部分都是机器学习中的小理论,但非常有实用价值。博主一个跨专业来学习此行业的学生党,自学之路也算是很艰辛了,对比其他平台的学生,有很好的资源(硬件、师资、交流平台等等),每每看到群里的人讨论一些tricks和最新的paper,博主都暗骂自己不努力。风物长宜放眼亮,未来如何没有人能够说得准,所有走过的路也未必都是弯路,努力总会有收获的。


参考文献
[1]Wu X, Kumar V, Ross Quinlan J, et al. Top 10 algorithms in data mining[J]. Knowledge & Information Systems, 2007, 14(1):1-37.
[2]http://www.cnblogs.com/pinard/p/6131423.html
[3]周志华,机器学习,清华大学出版社。2016
[4]Zhou Z H, Feng J. Deep Forest: Towards An Alternative to Deep Neural Networks[J]. 2017.

你可能感兴趣的:(XgBoost)