本题解析来源于July的优快云博客《通俗理解kaggle比赛大杀器xgboost》,特原封不动的刊载于此。
0 前言
xgboost一直在竞赛江湖里被传为神器,比如时不时某个kaggle/天池比赛中,某人用xgboost于千军万马中斩获冠军。
而我们的机器学习课程里也必讲xgboost,如寒所说:“RF和GBDT是工业界大爱的模型,Xgboost 是大杀器包裹,Kaggle各种Top排行榜曾一度呈现Xgboost一统江湖的局面,另外某次滴滴比赛第一名的改进也少不了Xgboost的功劳”。
此外,公司七月在线从2016年上半年起,就开始组织学员参加各种比赛,以在实际竞赛项目中成长(毕竟,搞AI不可能没实战,而参加比赛历经数据处理、特征选择、模型调优、代码调参,是一个极好的真刀真枪的实战机会,对能力的提升和找/换工作的帮助都非常大)。
AI大潮之下,今年特别多从传统IT转行转岗转型AI的朋友,很多朋友都咨询如何转行AI,我一般都会着重强调学习AI或找/换AI的四大金刚:课程 + 题库 + OJ + kaggle/天池。包括集训营的毕业考核更会融合kaggle或天池比赛。
考虑到kaggle/天池比赛对搞数学科学的重要性,特写此文介绍xgboost,助力大家快速入门xgboost以及在比赛中获得优异成绩。
1 决策树
举个例子,集训营某一期有100多名学员,假定给你一个任务,要你统计男生女生各多少人,当一个一个学员依次上台站到你面前时,你会怎么区分谁是男谁是女呢?
很快,你考虑到男生的头发一般很短,女生的头发一般比较长,所以你通过头发的长短将这个班的所有学员分为两拨,长发的为“女”,短发为“男”。
相当于你依靠一个指标“头发长短”将整个班的人进行了划分,于是形成了一个简单的决策树,而划分的依据是头发长短。
这时,有的人可能有不同意见了:为什么要用“头发长短”划分呀,我可不可以用“穿的鞋子是否是高跟鞋”,“有没有喉结”等等这些来划分呢,答案当然是可以的。
但究竟根据哪个指标划分更好呢?很直接的判断是哪个分类效果更好则优先用哪个。所以,这时就需要一个评价标准来量化分类效果了。
怎么判断“头发长短”或者“是否有喉结”是最好的划分方式,效果怎么量化呢?直观上来说,如果根据某个标准分类人群后,纯度越高效果越好,比如说你分为两群,“女”那一群都是女的,“男”那一群全是男的,那这个效果是最好的。但有时实际的分类情况不是那么理想,所以只能说越接近这种情况,我们则认为效果越好。
量化分类效果的方式有很多,比如信息增益(ID3)、信息增益率(C4.5)、基尼系数(CART)等等。
信息增益的度量标准:熵
ID3算法的核心思想就是以信息增益度量属性选择,选择分裂后信息增益最大的属性进行分裂。
什么是信息增益呢?为了精确地定义信息增益,我们先定义信息论中广泛使用的一个度量标准,称为熵(entropy),它刻画了任意样例集的纯度(purity)。给定包含关于某个目标概念的正反样例的样例集S,那么S相对这个布尔型分类的熵为:
上述公式中,p+代表正样例,比如在本文开头第二个例子中p+则意味着去打羽毛球,而p-则代表反样例,不去打球(在有关熵的所有计算中我们定义0log0为0)。
举例来说,假设S是一个关于布尔概念的有14个样例的集合,它包括9个正例和5个反例(我们采用记号[9+,5-]来概括这样的数据样例),那么S相对于这个布尔样例的熵为:
Entropy([9+,5-])=-(9/14)log2(9/14)-(5/14)log2(5/14)=0.940。
So,根据上述这个公式,我们可以得到:
如果S的所有成员属于同一类,则Entropy(S)=0;
如果S的正反样例数量相等,则Entropy(S)=1;
如果S的正反样例数量不等,则熵介于0,1之间
如下图所示:
看到没,通过Entropy的值,你就能评估当前分类树的分类效果好坏了。
更多细节如剪枝、过拟合、优缺点、可以参考此文《决策树学习》。
所以,现在决策树的灵魂已经有了,即依靠某种指标进行树的分裂达到分类/回归的目的,总是希望纯度越高越好。
2.回归树与集成学习
如果用一句话定义xgboost,很简单:Xgboost就是由很多CART树集成。但,什么是CART树?
数据挖掘或机器学习中使用的决策树有两种主要类型:
- 分类树分析是指预测结果是数据所属的类(比如某个电影去看还是不看)
- 回归树分析是指预测结果可以被认为是实数(例如房屋的价格,或患者在医院中的逗留时间)
而术语分类回归树(CART,Classification And Regression Tree)分析是用于指代上述两种树的总称,由Breiman等人首先提出。
2.1 回归树
事实上,分类与回归是两个很接近的问题,分类的目标是根据已知样本的某些特征,判断一个新的样本属于哪种已知的样本类,它的结果是离散值。而回归的结果是连续的值。当然,本质是一样的,都是特征(feature)到结果/标签(label)之间的映射。
理清了什么是分类和回归之后,理解分类树和回归树就不难了。
分类树的样本输出(即响应值)是类的形式,比如判断这个救命药是真的还是假的,周末去看电影《风语咒》还是不去。而回归树的样本输出是数值的形式,比如给某人发放房屋贷款的数额就是具体的数值,可以是0到300万元之间的任意值。
所以,对于回归树,你没法再用分类树那套信息增益、信息增益率、基尼系数来判定树的节点分裂了,你需要采取新的方式评估效果,包括预测误差(常用的有均方误差、对数误差等)。而且节点不再是类别,是数值(预测值),那么怎么确定呢?有的是节点内样本均值,有的是最优化算出来的比如Xgboost。
CART回归树是假设树为二叉树,通过不断将特征进行分裂。比如当前树结点是基于第j个特征值进行分裂的,设该特征值小于s的样本划分为左子树,大于s的样本划分为右子树。
而CART回归树实质上就是在该特征维度对样本空间进行划分,而这种空间划分的优化是一种NP难问题,因此,在决策树模型中是使用启发式方法解决。典型CART回归树产生的目标函数为:
因此,当我们为了求解最优的切分特征j和最优的切分点s,就转化为求解这么一个目标函数:
所以我们只要遍历所有特征的的所有切分点,就能找到最优的切分特征和切分点。最终得到一棵回归树.
2.2 boosting集成学习
所谓集成学习,是指构建多个分类器(弱分类器)对数据集进行预测,然后用某种策略将多个分类器预测的结果集成起来,作为最终预测结果。通俗比喻就是“三个臭皮匠赛过诸葛亮”,或一个公司董事会上的各董事投票决策,它要求每个弱分类器具备一定的“准确性”,分类器之间具备“差异性”。
集成学习根据各个弱分类器之间有无依赖关系,分为Boosting和Bagging两大流派:
- Boosting流派,各分类器之间有依赖关系,必须串行,比如Adaboost、GBDT(Gradient Boosting Decision Tree)、Xgboost
- Bagging流派,各分类器之间没有依赖关系,可各自并行,比如随机森林(Random Forest)
而著名的Adaboost作为boosting流派中最具代表性的一种方法,本博客曾详细介绍它。
AdaBoost,是英文"Adaptive Boosting"(自适应增强)的缩写,由Yoav Freund和Robert Schapire在1995年提出。它的自适应在于:前一个基本分类器分错的样本会得到加强,加权后的全体样本再次被用来训练下一个基本分类器。同时,在每一轮中加入一个新的弱分类器,直到达到某个预定的足够小的错误率或达到预先指定的最大迭代次数。
具体说来,整个Adaboost 迭代算法就3步:
- 初始化训练数据的权值分布。如果有N个样本,则每一个训练样本最开始时都被赋予相同的权值:1/N
- 训练弱分类器。具体训练过程中,如果某个样本点已经被准确地分类,那么在构造下一个训练集中,它的权值就被降低;相反,如果某个样本点没有被准确地分类,那么它的权值就得到提高。然后,权值更新过的样本集被用于训练下一个分类器,整个训练过程如此迭代地进行下去。
- 将各个训练得到的弱分类器组合成强分类器。各个弱分类器的训练过程结束后,加大分类误差率小的弱分类器的权重,使其在最终的分类函数中起着较大的决定作用,而降低分类误差率大的弱分类器的权重,使其在最终的分类函数中起着较小的决定作用。换言之,误差率低的弱分类器在最终分类器中占的权重较大,否则较小。
而另一种boosting方法GBDT(Gradient Boost Decision Tree),则与AdaBoost不同,GBDT每一次的计算是都为了减少上一次的残差,进而在残差减少(负梯度)的方向上建立一个新的模型。
boosting集成学习由多个相关联的决策树联合决策,什么叫相关联?举个例子
- 有一个样本[数据->标签]是:[(2,4,5)-> 4]
- 第一棵决策树用这个样本训练的预测为3.3
- 那么第二棵决策树训练时的输入,这个样本就变成了:[(2,4,5)-> 0.7]
- 也就是说,下一棵决策树输入样本会与前面决策树的训练和预测相关
很快你会意识到,Xgboost为何也是一个boosting的集成学习了。
而一个回归树形成的关键点在于:
- 分裂点依据什么来划分(如前面说的均方误差最小,loss);
- 分类后的节点预测值是多少(如前面说,有一种是将叶子节点下各样本实际值得均值作为叶子节点预测误差,或者计算所得)
至于另一类集成学习方法,比如Random Forest(随机森林)算法,各个决策树是独立的、每个决策树在样本堆里随机选一批样本,随机选一批特征进行独立训练,各个决策树之间没有啥关系。本文暂不展开介绍。
3.GBDT
说到Xgboost,不得不先从GBDT(Gradient Boosting Decision Tree)说起。因为xgboost本质上还是一个GBDT,但是力争把速度和效率发挥到极致,所以叫X (Extreme) GBoosted。包括前面说过,两者都是boosting方法。
GBDT的原理很简单,就是所有弱分类器的结果相加等于预测值,然后下一个弱分类器去拟合误差函数对预测值的梯度/残差(这个梯度/残差就是预测值与真实值之间的误差)。当然了,它里面的弱分类器的表现形式就是各棵树。如图所示:Y = Y1 + Y2 + Y3。
举一个非常简单的例子,比如我今年30岁了,但计算机或者模型GBDT并不知道我今年多少岁,那GBDT咋办呢?
- 它会在第一个弱分类器(或第一棵树中)随便用一个年龄比如20岁来拟合,然后发现误差有10岁;
- 接下来在第二棵树中,用6岁去拟合剩下的损失,发现差距还有4岁;
- 接着在第三棵树中用3岁拟合剩下的差距,发现差距只有1岁了;
- 最后在第四课树中用1岁拟合剩下的残差,完美。
最终,四棵树的结论加起来,就是真实年龄30岁。实际工程中,gbdt是计算负梯度,用负梯度近似残差。
注意,为何gbdt可以用用负梯度近似残差呢?
回归任务下,GBDT 在每一轮的迭代时对每个样本都会有一个预测值,此时的损失函数为均方差损失函数,
那此时的负梯度是这样计算的
所以,当损失函数选用均方损失函数是时,每一次拟合的值就是(真实值 - 当前模型预测的值),即残差。此时的变量是,即“当前预测模型的值”,也就是对它求负梯度。
另外,这里还得再啰嗦一下,上面预测年龄的第一个步骤中的“随便”二字看似随便,其实深入思考一下一点都不随便,你会发现大部分做预测的模型,基本都是这么个常规套路,先随便用一个值去预测,然后对比预测值与真实值的差距,最后不断调整 缩小差距。所以会出来一系列目标函数