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)。
 
集成学习示意图

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。描述如下图所示:
 
具体的公式推导可参考周志华老师的机器学习这本书,很基础。这里面的需要强调的是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。

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


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算法。
运行了简单的一个test,结果如上。

完整Adaboost算法实现

对上述的adaboost.py增加新的功能函数adaBoostTrainDS。
 
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注释了,可以更简单清晰)。
 

1.3 Bagging和随机森林(random forest)

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

1.4 Boosting基本方法对比

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

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


准备数据

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


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


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


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


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

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

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值