导言

深度学习(DL, Deep Learning)是机器学习(ML, Machine Learning)领域中一个新的研究方向,它被引入机器学习使其更接近于最初的目标——人工智能(AI, Artificial Intelligence)。 深度学习是学习样本数据的内在规律和表示层次,这些学习过程中获得的信息对诸如文字,图像和声音等数据的解释有很大的帮助。它的最终目标是让机器能够像人一样具有分析学习能力,能够识别文字、图像和声音等数据。
以往在机器学习用于现实任务时,描述样本的特征通常需由人类专家来设计,这称为“特征工程”(feature engineering)。众所周知,特征的好坏对泛化性能有至关重要的影响,人类专家设计出好特征也并非易事;特征学习则通过机器学习技术自身来产生好特征,这使机器学习向“全自动数据分析”又前进了一步。
深度学习在搜索技术,数据挖掘,机器学习,机器翻译,自然语言处理,多媒体学习,语音,推荐和个性化技术,以及其他相关领域都取得了很多成果。深度学习使机器模仿视听和思考等人类的活动,解决了很多复杂的模式识别难题,使得人工智能相关技术取得了很大进步。

内容

本学习材料主要包括以下几个方面的内容:

  • Boosting,Bagging的介绍
  • Decision Tree & RandomForest的介绍
  • XGBoost原理介绍
  • XGBoost的实战

评论

Boosting,Bagging的介绍

集成学习(ensemble learning)可以说是现在非常火爆的机器学习方法了。它本身不是一个单独的机器学习算法,而是通过构建并结合多个机器学习器来完成学习任务。也就是我们常说的“博采众长”。集成学习可以用于分类问题集成,回归问题集成,特征选取集成,异常点检测集成等等,可以说所有的机器学习领域都可以看到集成学习的身影。本文就对集成学习的原理做一个总结。

1. 集成学习概述

从下图,我们可以对集成学习的思想做一个概括。对于训练集数据,我们通过训练若干个个体学习器,通过一定的结合策略,就可以最终形成一个强学习器,以达到博采众长的目的。

也就是说,集成学习有两个主要的问题需要解决,第一是如何得到若干个个体学习器,第二是如何选择一种结合策略,将这些个体学习器集合成一个强学习器。

评论

2. 集成学习之个体学习器

上一节我们讲到,集成学习的第一个问题就是如何得到若干个个体学习器。这里我们有两种选择。

第一种就是所有的个体学习器都是一个种类的,或者说是同质的。比如都是决策树个体学习器,或者都是神经网络个体学习器。第二种是所有的个体学习器不全是一个种类的,或者说是异质的。比如我们有一个分类问题,对训练集采用支持向量机个体学习器,逻辑回归个体学习器和朴素贝叶斯个体学习器来学习,再通过某种结合策略来确定最终的分类强学习器。

目前来说,同质个体学习器的应用是最广泛的,一般我们常说的集成学习的方法都是指的同质个体学习器。而同质个体学习器使用最多的模型是CART决策树和神经网络。同质个体学习器按照个体学习器之间是否存在依赖关系可以分为两类,第一个是个体学习器之间存在强依赖关系,一系列个体学习器基本都需要串行生成,代表算法是boosting系列算法,第二个是个体学习器之间不存在强依赖关系,一系列个体学习器可以并行生成,代表算法是bagging和随机森林(Random Forest)系列算法。下面就分别对这两类算法做一个概括总结。

3. 集成学习之boosting

boosting的算法原理我们可以用一张图做一个概括如下:

从图中可以看出,Boosting算法的工作机制是首先从训练集用初始权重训练出一个弱学习器1,根据弱学习的学习误差率表现来更新训练样本的权重,使得之前弱学习器1学习误差率高的训练样本点的权重变高,使得这些误差率高的点在后面的弱学习器2中得到更多的重视。然后基于调整权重后的训练集来训练弱学习器2.,如此重复进行,直到弱学习器数达到事先指定的数目T,最终将这T个弱学习器通过集合策略进行整合,得到最终的强学习器。

Boosting系列算法里最著名算法主要有AdaBoost算法和提升树(boosting tree)系列算法。提升树系列算法里面应用最广泛的是梯度提升树(Gradient Boosting Tree)。AdaBoost和提升树算法的原理在后面的文章中会专门来讲。

4. 集成学习之bagging

Bagging的算法原理和 boosting不同,它的弱学习器之间没有依赖关系,可以并行生成,我们可以用一张图做一个概括如下:

从上图可以看出,bagging的个体弱学习器的训练集是通过随机采样得到的。通过T次的随机采样,我们就可以得到T个采样集,对于这T个采样集,我们可以分别独立的训练出T个弱学习器,再对这T个弱学习器通过集合策略来得到最终的强学习器。

对于这里的随机采样有必要做进一步的介绍,这里一般采用的是自助采样法(Bootstrap sampling),即对于m个样本的原始训练集,我们每次先随机采集一个样本放入采样集,接着把该样本放回,也就是说下次采样时该样本仍有可能被采集到,这样采集m次,最终可以得到m个样本的采样集,由于是随机采样,这样每次的采样集是和原始训练集不同的,和其他采样集也是不同的,这样得到多个不同的弱学习器。

随机森林是bagging的一个特化进阶版,所谓的特化是因为随机森林的弱学习器都是决策树。所谓的进阶是随机森林在bagging的样本随机采样基础上,又加上了特征的随机选择,其基本思想没有脱离bagging的范畴。bagging和随机森林算法的原理在后面的文章中会专门来讲。

5. 集成学习之结合策略

在上面几节里面我们主要关注于学习器,提到了学习器的结合策略但没有细讲,本节就对集成学习之结合策略做一个总结。我们假定我得到的T个弱学习器是$\{h_1,h_2,...h_T\}$

5.1 平均法

对于数值类的回归预测问题,通常使用的结合策略是平均法,也就是说,对于若干个弱学习器的输出进行平均得到最终的预测输出。

最简单的平均是算术平均,也就是说最终预测是

H(x) = \frac{1}{T}\sum\limits_{1}^{T}h_i(x)

如果每个个体学习器有一个权重w,则最终预测是

H(x) = \sum\limits_{i=1}^{T}w_ih_i(x)

其中$w_i$是个体学习器$h_i$的权重,通常有

w_i \geq 0 ,\;\;\; \sum\limits_{i=1}^{T}w_i = 1

5.2 投票法

对于分类问题的预测,我们通常使用的是投票法。假设我们的预测类别是$\{c_1,c_2,...c_K\}$,对于任意一个预测样本x,我们的T个弱学习器的预测结果分别是$(h_1(x), h_2(x)...h_T(x))$

最简单的投票法是相对多数投票法,也就是我们常说的少数服从多数,也就是T个弱学习器的对样本x的预测结果中,数量最多的类别ci为最终的分类类别。如果不止一个类别获得最高票,则随机选择一个做最终类别。

稍微复杂的投票法是绝对多数投票法,也就是我们常说的要票过半数。在相对多数投票法的基础上,不光要求获得最高票,还要求票过半数。否则会拒绝预测。

更加复杂的是加权投票法,和加权平均法一样,每个弱学习器的分类票数要乘以一个权重,最终将各个类别的加权票数求和,最大的值对应的类别为最终类别。

5.3 学习法

上两节的方法都是对弱学习器的结果做平均或者投票,相对比较简单,但是可能学习误差较大,于是就有了学习法这种方法,对于学习法,代表方法是stacking,当使用stacking的结合策略时, 我们不是对弱学习器的结果做简单的逻辑处理,而是再加上一层学习器,也就是说,我们将训练集弱学习器的学习结果作为输入,将训练集的输出作为输出,重新训练一个学习器来得到最终结果。

在这种情况下,我们将弱学习器称为初级学习器,将用于结合的学习器称为次级学习器。对于测试集,我们首先用初级学习器预测一次,得到次级学习器的输入样本,再用次级学习器预测一次,得到最终的预测结果。

Decision Tree & RandomForest的介绍

决策树模型

决策树(decision tree)是一种基本的分类与回归方法。决策树模型呈树形结构,在分类问题中,表示基于特征对实例进行分类的过程。它可以认为是if-then规则的集合(互斥并且完备),也可以认为是定义在特征空间与类空间上的条件概率分布。其主要优点是模型具有可读性,分类速度快。学习时,利用训练数据,根据损失函数最小化的原则建立决策树模型。预测时,对新的数据利用决策树模型进行分类。决策树学习通常包括三个步骤:特征选择、决策树的生成和决策树的修剪。

  • 特征选择:从训练数据的特征中选择一个特征作为当前节点的分裂标准(特征选择的标准不同产生了不同的特征决策树算法)。
  • 决策树生成:根据所选特征评估标准,从上至下递归地生成子节点,直到数据集不可分则停止决策树停止声场。
  • 决策树剪枝:决策树容易过拟合,需要剪枝来缩小树的结构和规模(包括预剪枝和后剪枝)。

决策树学习的本质是从训练数据集中归纳出一组分类规则或者说是条件概率模型,与训练数据集不相矛盾的决策树可能有多个或者一个没有,我们需要找到一个与训练数据集矛盾较小的决策树,同时具有很好的泛化能力。换句话说,我们选择的条件概率模型应该不仅对现有的训练数据集有很好的拟合效果,而且能够对未知的数据有很好的预测(泛化能力)。

1.特征选择
特征选择决定用哪个特征来划分空间,即如何选择最优划分属性。在划分的过程中,我们希望决策树的分支结点所包含的样本尽可能属于同一类别,即结点的“纯度”越来越高。
特征选择的准则:信息增益、信息增益比(增益率)、基尼指数
三种特征选择的方法对应着三个不同的算法:ID3,C4.5,CART

信息增益:
以属性“色泽”为例,它有3个可能的取值:{青绿,乌黑,浅白}。若使用该属性对D进行划分,则可得到3个子集,分别记为:

假定当前样本集合D中第k类样本所占的比例为$p_k(k=1,2,...,|y|)$,则D的信息熵的定义为:

Ent(D)=-\sum_{k=1}^{|y|}p_klog_2p_k

信息增益计算公式如下:

Gain(D,a)=Ent(D)-\sum_{v=1}^V\frac{|D^v|}{|D|}Ent(D^v)

选择信息增益最大的属性作为划分属性。

信息增益率:
信息增益准则对可取数目较多的属性有所偏好,为减少这种偏好可能带来的不利影响,C4.5决策树算法不直接使用信息增益,而是使用“增益率”,信息增益率的计算公式如下:

Gain\_ratio(D,a)=\frac{Gain(D,a)}{IV(a)}

其中

IV(a)=-\sum_{v=1}^V\frac{|D^v|}{|D|}log_2\frac{|D^v|}{|D|}

选择信息增益率最大的属性作为划分属性。

基尼指数:
CART决策树使用“基尼指数”来选择划分属性

Gini(D)=\sum_{k=1}^{|y|}\sum_{k'\neq k}p_kp_{k'}

=1-\sum_{k=1}^{|y|}p_k^2

选择基尼指数最小的属性作为划分属性。

2.决策树生成
决策树生成算法:
输入:训练数据集 D,特征集 A,阈值 $\epsilon$(预剪枝用,后剪枝不需要此项);
输出:决策树 T。
(1) 若 D 中所有样本属于同一类 $C_k$,则 T为单结点树,并将 $C_k$ 作为该结点的类标记,返回 T;
(2) 若 $A = \varnothing$,则T为单结点树,并将 D中样本数最多的类 $C_k$作为该结点的类标记,返回 T;
(3) 否则,计算 A 中各个特征对 D的信息增益或者信息增益比,选择信息增益或信息增益比最大的特征 $A_g$
(4) 如果 $A_g$的信息增益或信息增益比小于阈值 $\epsilon$,则 T为单结点树,并将 D中样本数最多的类 $C_k$ 作为该结点的类标记,返回 T;(后剪枝没有这步)
(5) 如果 $A_g$ 的每一种可能值 $a_i$,依 $A_g$ = $a_i$,将 D分割为若干非空子集 $D_i$,将 $D_i$中样本数最多的类作为标记,构建子结点,由结点及其子结点构成树 T,返回 T;
(6)对第i个子结点,以 $D_i$为训练集,以 $A-A_g$为特征集,递归地调用步骤(1)~(5),得到子树 $T_i$,返回$T_i$

更多关于决策树的内容请参见:《机器学习》周志华

说完决策树我们再来说说随机森林,随机森林的基础模型就是CART决策树,在此基础上通过bagging的方法进行集成,可以参考社区的项目:
Bagging与随机森林算法原理小结

1. bagging的原理

在集成学习原理小结中,我们给Bagging画了下面一张原理图。

从上图可以看出,Bagging的弱学习器之间的确没有boosting那样的联系。它的特点在“随机采样”。那么什么是随机采样?

随机采样(bootsrap)就是从我们的训练集里面采集固定个数的样本,但是每采集一个样本后,都将样本放回。也就是说,之前采集到的样本在放回后有可能继续被采集到。对于我们的Bagging算法,一般会随机采集和训练集样本数m一样个数的样本。这样得到的采样集和训练集样本的个数相同,但是样本内容不同。如果我们对有m个样本训练集做T次的随机采样,,则由于随机性,T个采样集各不相同。

注意到这和GBDT的子采样是不同的。GBDT的子采样是无放回采样,而Bagging的子采样是放回采样。

对于一个样本,它在某一次含m个样本的训练集的随机采样中,每次被采集到的概率是$\frac{1}{m}$。不被采集到的概率为$1-\frac{1}{m}$。如果m次采样都没有被采集中的概率是$(1-\frac{1}{m})^m$。当$m \to \infty$时,$(1-\frac{1}{m})^m \to \frac{1}{e} \simeq 0.368$。也就是说,在bagging的每轮随机采样中,训练集中大约有36.8%的数据没有被采样集采集中。

对于这部分大约36.8%的没有被采样到的数据,我们常常称之为袋外数据(Out Of Bag, 简称OOB)。这些数据没有参与训练集模型的拟合,因此可以用来检测模型的泛化能力。

bagging对于弱学习器没有限制,这和Adaboost一样。但是最常用的一般也是决策树和神经网络。

bagging的集合策略也比较简单,对于分类问题,通常使用简单投票法,得到最多票数的类别或者类别之一为最终的模型输出。对于回归问题,通常使用简单平均法,对T个弱学习器得到的回归结果进行算术平均得到最终的模型输出。

由于Bagging算法每次都进行采样来训练模型,因此泛化能力很强,对于降低模型的方差很有作用。当然对于训练集的拟合程度就会差一些,也就是模型的偏倚会大一些。

2. bagging算法流程

上一节我们对bagging算法的原理做了总结,这里就对bagging算法的流程做一个总结。相对于Boosting系列的Adaboost和GBDT,bagging算法要简单的多。

输入为样本集$D=\{(x_,y_1),(x_2,y_2), ...(x_m,y_m)\}$,弱学习器算法, 弱分类器迭代次数T。

输出为最终的强分类器f(x)

1)对于t=1,2...,T:

    a)对训练集进行第t次随机采样,共采集m次,得到包含m个样本的采样集$D_t$

    b)用采样集$D_t$训练第t个弱学习器$G_t(x)$

2) 如果是分类算法预测,则T个弱学习器投出最多票数的类别或者类别之一为最终类别。如果是回归算法,T个弱学习器得到的回归结果进行算术平均得到的值为最终的模型输出。

3. 随机森林算法

理解了bagging算法,随机森林(Random Forest,以下简称RF)就好理解了。它是Bagging算法的进化版,也就是说,它的思想仍然是bagging,但是进行了独有的改进。我们现在就来看看RF算法改进了什么。

首先,RF使用了CART决策树作为弱学习器,这让我们想到了梯度提示树GBDT。第二,在使用决策树的基础上,RF对决策树的建立做了改进,对于普通的决策树,我们会在节点上所有的n个样本特征中选择一个最优的特征来做决策树的左右子树划分,但是RF通过随机选择节点上的一部分样本特征,这个数字小于n,假设为$n_{sub}$,然后在这些随机选择的$n_{sub}$个样本特征中,选择一个最优的特征来做决策树的左右子树划分。这样进一步增强了模型的泛化能力。

如果$n_{sub}=n$,则此时RF的CART决策树和普通的CART决策树没有区别。$n_{sub}$越小,则模型约健壮,当然此时对于训练集的拟合程度会变差。也就是说$n_{sub}$越小,模型的方差会减小,但是偏倚会增大。在实际案例中,一般会通过交叉验证调参获取一个合适的$n_{sub}$的值。

除了上面两点,RF和普通的bagging算法没有什么不同, 下面简单总结下RF的算法。

输入为样本集$D=\{(x_,y_1),(x_2,y_2), ...(x_m,y_m)\}$,弱分类器迭代次数T。

输出为最终的强分类器f(x)

1)对于t=1,2...,T:

    a)对训练集进行第t次随机采样,共采集m次,得到包含m个样本的采样集$D_t$

    b)用采样集$D_t$训练第t个决策树模型$G_t(x)$,在训练决策树模型的节点的时候, 在节点上所有的样本特征中选择一部分样本特征, 在这些随机选择的部分样本特征中选择一个最优的特征来做决策树的左右子树划分

2) 如果是分类算法预测,则T个弱学习器投出最多票数的类别或者类别之一为最终类别。如果是回归算法,T个弱学习器得到的回归结果进行算术平均得到的值为最终的模型输出。

4. 随机森林的推广

由于RF在实际应用中的良好特性,基于RF,有很多变种算法,应用也很广泛,不光可以用于分类回归,还可以用于特征转换,异常点检测等。下面对于这些RF家族的算法中有代表性的做一个总结。

4.1 extra trees

extra trees是RF的一个变种, 原理几乎和RF一模一样,仅有区别有:

1) 对于每个决策树的训练集,RF采用的是随机采样bootstrap来选择采样集作为每个决策树的训练集,而extra trees一般不采用随机采样,即每个决策树采用原始训练集。

2) 在选定了划分特征后,RF的决策树会基于基尼系数,均方差之类的原则,选择一个最优的特征值划分点,这和传统的决策树相同。但是extra trees比较的激进,他会随机的选择一个特征值来划分决策树。

从第二点可以看出,由于随机选择了特征值的划分点位,而不是最优点位,这样会导致生成的决策树的规模一般会大于RF所生成的决策树。也就是说,模型的方差相对于RF进一步减少,但是偏倚相对于RF进一步增大。在某些时候,extra trees的泛化能力比RF更好。

4.2 Totally Random Trees Embedding

Totally Random Trees Embedding(以下简称 TRTE)是一种非监督学习的数据转化方法。它将低维的数据集映射到高维,从而让映射到高维的数据更好的运用于分类回归模型。我们知道,在支持向量机中运用了核方法来将低维的数据集映射到高维,此处TRTE提供了另外一种方法。

TRTE在数据转化的过程也使用了类似于RF的方法,建立T个决策树来拟合数据。当决策树建立完毕以后,数据集里的每个数据在T个决策树中叶子节点的位置也定下来了。比如我们有3颗决策树,每个决策树有5个叶子节点,某个数据特征x划分到第一个决策树的第2个叶子节点,第二个决策树的第3个叶子节点,第三个决策树的第5个叶子节点。则x映射后的特征编码为(0,1,0,0,0, 0,0,1,0,0, 0,0,0,0,1), 有15维的高维特征。这里特征维度之间加上空格是为了强调三颗决策树各自的子编码。

映射到高维特征后,可以继续使用监督学习的各种分类回归算法了。

4.3 Isolation Forest

Isolation Forest(以下简称IForest)是一种异常点检测的方法。它也使用了类似于RF的方法来检测异常点。

对于在T个决策树的样本集,IForest也会对训练集进行随机采样,但是采样个数不需要和RF一样,对于RF,需要采样到采样集样本个数等于训练集个数。但是IForest不需要采样这么多,一般来说,采样个数要远远小于训练集个数?为什么呢?因为我们的目的是异常点检测,只需要部分的样本我们一般就可以将异常点区别出来了。

对于每一个决策树的建立, IForest采用随机选择一个划分特征,对划分特征随机选择一个划分阈值。这点也和RF不同。

另外,IForest一般会选择一个比较小的最大决策树深度max_depth,原因同样本采集,用少量的异常点检测一般不需要这么大规模的决策树。

对于异常点的判断,则是将测试样本点x拟合到T颗决策树。计算在每颗决策树上该样本的叶子节点的深度$h_t(x)$。,从而可以计算出平均高度h(x)。此时我们用下面的公式计算样本点x的异常概率:

s(x,m) = 2^{-\frac{h(x)}{c(m)}}

其中,m为样本个数。c(m)的表达式为:

c(m) =2\ln(m-1) + \xi - 2\frac{m-1}{m},ξ为欧拉常数

s(x,m)的取值范围是[0,1],取值越接近于1,则是异常点的概率也越大。

5. 随机森林小结

RF的算法原理也终于讲完了,作为一个可以高度并行化的算法,RF在大数据时候大有可为。 这里也对常规的随机森林算法的优缺点做一个总结。

RF的主要优点有:

1) 训练可以高度并行化,对于大数据时代的大样本训练速度有优势。个人觉得这是的最主要的优点。

2) 由于可以随机选择决策树节点划分特征,这样在样本特征维度很高的时候,仍然能高效的训练模型。

3) 在训练后,可以给出各个特征对于输出的重要性

4) 由于采用了随机采样,训练出的模型的方差小,泛化能力强。

5) 相对于Boosting系列的Adaboost和GBDT, RF实现比较简单。

6) 对部分特征缺失不敏感。

RF的主要缺点有:

1)在某些噪音比较大的样本集上,RF模型容易陷入过拟合。

2) 取值划分比较多的特征容易对RF的决策产生更大的影响,从而影响拟合的模型的效果。

## 直接导入之前已经处理好的数据
import pandas as pd
import re
mydata=pd.read_csv('/home/mw/input/MLearn9130/训练营.csv')
## 分离训练集和验证集
from sklearn.model_selection import train_test_split

## 原始列名列表
col_names=list(mydata.columns)
col=[]
for i in range(len(col_names)):
    if re.findall(r"\u2028(.+)",col_names[i])!=[]:
        col.append(re.findall(r"\u2028(.+)",col_names[i])[0])
    elif re.findall(r"\n(.+)",col_names[i])!=[]:
        col.append(re.findall(r"\n(.+)",col_names[i])[0])
    else:
        col.append(col_names[i])

## 修改dataframe列名
mydata.columns=col



## 对性别进行编码
def gender(x):
    if x=='M':
        return 0
    else:
        return 1
mydata['性别']=mydata['性别'].apply(gender)
## 对区域进行编码
def district(x):
    if x=='east':
        return 1
    elif x=='south':
        return 2
    elif x=='north':
        return 3
    else:
        return 4
mydata['区域']=mydata['区域'].apply(district)
## 对护理来源进行编码
def care(x):
    if x=='Governament Hospital':
        return 1
    if x=='Never Counsulted':
        return 2
    if x=='Private Hospital' or x==' ':
        return 3
    if x=='clinic':
        return 4
mydata['护理来源']=mydata['护理来源'].apply(care)


## 对于数值型变量的缺失值用中位数进行填充
feature1 = ['最低血压','腰围','最高血压','体重指数','肥胖腰围','身高','体重','好胆固醇','总胆固醇','坏胆固醇']
for i in feature1:
    mydata[i] = mydata[i].fillna(mydata[i].median())
## 对于分类型变量的缺失值用众数进行填充
feature2 = ['收入','未婚','视力不佳','高血压','慢性疲劳','肝炎','教育','糖尿病','家族肝炎','体育活动']
for i in feature2:
    mydata[i] = mydata[i].fillna(mydata[i].mode())
    mydata[i] = mydata[i].fillna(0.0)    ##上面一行插不上,不知道为啥


## 分离X,y
X = mydata.drop('ALF', axis=1) 
y = mydata['ALF'] 
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.3)
## 规范化
import numpy as np
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
X_train_scaled = ss.fit_transform(X_train)
X_test_scaled = ss.transform(X_val)
y_val = np.array(y_val)
## 拟合
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import recall_score
Rf = RandomForestClassifier()
Rf.fit(X_train_scaled, y_train)
print('训练得分='+str(Rf.score(X_train_scaled, y_train)))
## 预测
from sklearn.metrics import accuracy_score
predict_results=Rf.predict(X_val)
print('预测得分='+str(accuracy_score(predict_results, y_val)))

'''
训练得分=0.991156462585034
预测得分=0.7698412698412699
/opt/conda/lib/python3.6/site-packages/sklearn/ensemble/forest.py:245: FutureWarning: The default value of n_estimators will change from 10 in version 0.20 to 100 in 0.22.
  "10 in version 0.20 to 100 in 0.22.", FutureWarning)
'''

XGBoost原理介绍

XGBoost是陈天奇等人开发的一个开源机器学习项目,高效地实现了GBDT算法并进行了算法和工程上的许多改进,被广泛应用在Kaggle竞赛及其他许多机器学习竞赛中并取得了不错的成绩。
在了解XGBoost之前,需要先了解一下GBDT算法,参见社区的项目:梯度提升树(GBDT)原理小结
学习了GBDT之后我们就来介绍一下XGBoost。

XGBoost树的定义

先来举个例子,我们要预测一家人对电子游戏的喜好程度,考虑到年轻和年老相比,年轻更可能喜欢电子游戏,以及男性和女性相比,男性更喜欢电子游戏,故先根据年龄大小区分小孩和大人,然后再通过性别区分开是男是女,逐一给各人在电子游戏喜好程度上打分,如下图所示。

就这样,训练出了2棵树tree1和tree2,类似GBDT的原理,两棵树的结论累加起来便是最终的结论,所以小孩的预测分数就是两棵树中小孩所落到的结点的分数相加:2 + 0.9 = 2.9。爷爷的预测分数同理:-1 + (-0.9)= -1.9。具体如下图所示:

如果不考虑工程实现、解决问题上的一些差异,XGBoost与GBDT比较大的不同就是目标函数的定义。XGBoost的目标函数如下图所示:

其中:

  • 红色箭头所指向的L 即为损失函数(比如平方损失函数:$l(y_i,y^i)=(y_i-y^i)^2$
  • 红色方框所框起来的是正则项(包括L1正则、L2正则)
  • 红色圆圈所圈起来的为常数项
  • 对于f(x),XGBoost利用泰勒展开三项,做一个近似。f(x)表示的是其中一颗回归树。

XGBoost的核心算法思想不难,基本就是:

  • 不断地添加树,不断地进行特征分裂来生长一棵树,每次添加一个树,其实是学习一个新函数f(x),去拟合上次预测的残差。
  • 当我们训练完成得到k棵树,我们要预测一个样本的分数,其实就是根据这个样本的特征,在每棵树中会落到对应的一个叶子节点,每个叶子节点就对应一个分数
  • 最后只需要将每棵树对应的分数加起来就是该样本的预测值。

正则项:树的复杂度

XGBoost对树的复杂度包含了两个部分:
一个是树里面叶子节点的个数T
一个是树上叶子节点的得分w的L2模平方(对w进行L2正则化,相当于针对每个叶结点的得分增加L2平滑,目的是为了避免过拟合)

我们再来看一下XGBoost的目标函数(损失函数揭示训练误差 + 正则化定义复杂度):

L(\phi)=\sum_il(y_i'-y_i)+\sum_k\Omega(f_t)

正则化项$\sum_k\Omega(f_t)$是则表示树的复杂度的函数,值越小复杂度越低,泛化能力越强。

关于XGBoost的介绍可以参考社区项目:XGBoost的使用讲解

XGBoost的实战

## 导入需要的库
import xgboost as xgb
import numpy as np
from sklearn import datasets
from sklearn.metrics import accuracy_score

## 加载数据
xgb_train = xgb.DMatrix(X_train,label=y_train)
xgb_val = xgb.DMatrix(X_val,label=y_val)

## 设置参数
params = {
    "booster":"gbtree",
    "eta":1,
    "max_depth":5
}

## 拟合模型
model = xgb.train(params, xgb_train)

## 在验证集上预测
val_preds = model.predict(xgb_val)
val_preds

'''
/opt/conda/lib/python3.6/site-packages/xgboost/core.py:587: FutureWarning: Series.base is deprecated and will be removed in a future version
  if getattr(data, 'base', None) is not None and \
array([-0.01462084,  0.01802462,  0.5015175 , ...,  0.04674974,
       -0.00260997,  0.02501139], dtype=float32)
'''


## 计算在验证集上预测的正确率
val_predictions = [round(value) for value in val_preds]
val_accuracy = accuracy_score(val_predictions,y_val) #使用sklearn进行比较正确率
print ("Val Accuary: %.2f%%" % (val_accuracy * 100.0))

# Val Accuary: 90.56%


## 显示特征重要性
import matplotlib.pyplot as plt
from xgboost import plot_importance 
fig,ax = plt.subplots(figsize=(15,15))
plot_importance(model,ax=ax)
plt.show()

下面补充说明XGBoost的各项参数:

XGBoost的参数分为三大类:通用参数、Booster参数、学习目标参数

通用参数: 用来控制XGBoost的宏观功能

  1. booster(选择每次迭代的模型)
    • 默认值:gbtree
    • 可能的取值:
      gbtree:基于树的模型
      gbliner:线性模型
  2. silent(静默模式)
    • 默认值:0
    • 可能的取值:
      1:静默模式开启。不输出任何信息
      0:静默模式不开启
  3. nthread(线程数)
    • 默认值:最大可能的线程数

Booster参数: 这里只介绍tree booster

  1. eta(类似learning rate)
    • 默认值:0.3
  2. min_child_weight(最小叶子节点样本权重和)
    • 默认值:1
  3. max_depth(最大深度)
    • 默认值:6
  4. max_leaf_nodes(最大叶子数量)
    • 如果定义了这个参数,会忽略max_depth参数
  5. gamma(节点分裂所需的最小损失函数下降值)
    • 默认值:0
  6. max_delta_step(每棵树权重改变的最大步长)
    • 默认值:0
  7. subsample(控制对于每棵树,随机采样的比例)
    • 默认值:1
  8. colsample_bytree(每棵树随机采样的列数的占比)
    • 默认值:1
  9. colsample_bylevel(树的每一级的每一次分裂,对列数的采样的占比)
    • 默认值:1
  10. lambda(权重的L2正则化项)
    • 默认值:1
  11. alpha(权重的L1正则化项)
    • 默认值:1
  12. scale_pos_weight(在各类别样本十分不平衡时,把这个参数设定为一个正值,可以使算法更快收敛)
    • 默认值:1

学习目标参数: 这个参数用来控制理想的优化目标和每一步结果的度量方法

  1. objective(需要被最小化的损失函数)
    • 默认值:reg:linear
    • 常用值:
      binary:logistic 二分类的逻辑回归,返回预测的概率(不是类别)
      multi:softmax 使用softmax的多分类器,返回预测的类别(不是概率)
      multi:softprob 和multi:softmax参数一样,但是返回的是每个数据属于各个类别的概率
      multi需要多设一个参数:num_class(类别数目)
  2. eval_metric(对于有效数据的度量方法)
    • 默认值:取决于objective参数的取值, 对于回归问题,默认值是rmse,对于分类问题,默认值是error
    • 常用值:
      rmse:均方根误差
      mae:平均绝对误差
      logloss:负对数似然函数值
      error:二分类错误率(阈值为0.5)
      merror:多分类错误率
      mlogloss:多分类logloss损失函数
      auc曲线下面积
  3. seed(随机种子)
    • 默认值:0

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐