机器学习python之CART、GB、GBDT、XGBoost

一、 分类回归树Classification And Regression Trees (CART)

CART是一种基于二叉树的机器学习算法,其既能处理回归问题,又能处理分类为题。相比于 ID3 和 C4.5 只能用于离散型数据且只能用于分类任务,CART 决策树的适用面要广得多,既可用于离散型数据,又可以处理连续型数据,并且分类和回归任务都能处理。
在分类任务中 CART 算法使用基尼系数作为特征选择的依据,在回归任务中则以均方误差作为特征选择的依据。

1.1 基尼系数

信息增益准测对可取值数目较多的特征有所偏好, 增益率准则使用大量的对数计算会非常耗费技术资源。于是引进了基尼系数。基尼系数代表了模型的不纯度,基尼系数越小,则不纯度越低,特征越好。
基尼系数定义:在分类问题中,假设有K个类别,第k个类别的概率为 P k P_k Pk, 则基尼系数的表达式为:
G i n i ( p ) = ∑ k = 1 K P k ∗ ( 1 − P k ) Gini(p)=\sum_{k=1}^K P_k*(1-P_k) Gini(p)=k=1KPk(1Pk)
对于个给定的样本D,假设有K个类别, 第k个类别的数量为 C k C_k Ck,则样本D的基尼系数表达式为:
G i n i ( D ) = 1 − ∑ k = 1 K ( ∣ C K ∣ ∣ D ∣ ) 2 Gini(D)=1-\sum_{k=1}^K(\frac{|C_K|}{|D|})^2 Gini(D)=1k=1K(DCK)2
直观的说,Gini(D)反映了从数据集D中随机抽取两个样本,其类别标记不一致的概率。因此,Gini(D)越小,则数据集D的纯度越高。
特别的,对于样本D,如果根据特征A的某个值a,把D分成D1和D2两部分,则在特征A的条件下,D的基尼系数表达式为(特征A的基尼系数):
G i n i ( D , A ) = ∣ D 1 ∣ ∣ D ∣ G i n i ( D 1 ) + ∣ D 2 ∣ ∣ D ∣ G i n i ( D 2 ) Gini(D,A)= \frac{|D_1|}{|D|}Gini(D_1)+\frac{|D_2|}{|D|}Gini(D_2) Gini(D,A)=DD1Gini(D1)+DD2Gini(D2)
于是,我们在候选特征集合 Ω \Omega Ω中,选择那个使得划分后基尼系数最小的特征作为最优划分特征,即 A = a r g m i n A ∈ Ω G i n i ( D , A ) A=argmin_{A\in\Omega}Gini(D,A) A=argminAΩGini(D,A)

1.2 CART分类树

对于CART分类树连续值的处理问题,其思想和C4.5是相同的,都是将连续的特征离散化。唯一的区别在于在选择划分点时的度量方式不同,C4.5使用的是信息增益比,而CART分类树使用的是基尼系数。
具体的思路如下,比如m个样本的连续特征A有m个,从小到大排列为a1,a2,…,am,则CART算法取相邻两样本值的平均数,一共取得m-1个划分点,其中第i个划分点 T i T_i Ti表示为: T i = a i + a i + 1 2 T_i= \frac{a_i+a_{i+1}}{2} Ti=2ai+ai+1。对于这m-1个点,分别计算以该点作为二元分类点时的基尼系数。选择基尼系数最小的点作为该连续特征的二元离散分类点。如取到的基尼系数最小的点为 a t a_t at,则小于 a t a_t at的值为类别0,大于 a t a_t at 的值为类别1,这样我们就做到了连续特征的离散化。
要注意的是,与ID3或者C4.5处理离散属性不同的是,如果当前节点为连续属性,则该属性后面还可以参与子节点的产生选择过程。
对于CART分类树离散值的处理问题,采用的思路是不停的二分离散特征。
回忆下ID3或者C4.5,如果某个特征A被选取建立决策树节点,如果它有A1,A2,A3三种类别,我们会在决策树上建立一个三叉的节点。这样导致决策树是多叉树。但是CART分类树使用的方法不同,他采用的是不停的二分,还是这个例子,CART分类树会考虑把A分成{A1}和{A2,A3}, {A2}和{A1,A3},{A3}和{A1,A2}三种情况,找到基尼系数最小的组合,比如{A2}和{A1,A3},然后建立二叉树节点,一个节点是A2对应的样本,另一个节点是{A1,A3}对应的节点。同时,由于这次没有把特征A的取值完全分开,后面我们还有机会在子节点继续选择到特征A来划分A1和A3。这和ID3或者C4.5不同,在ID3或者C4.5的一棵子树中,离散特征只会参与一次节点的建立。

1.3 CART回归树

这里简单介绍一下CART中的回归树。
假设有n个训练样本,损失函数定义为均方误差(注意,这里的损失指的是树中的criterion,类似信息增益,Gini指数;而不是原问题中的loss,原问题既可以是分类也可以是回归)。这n个样本一开始都在根节点,那么此时进入该节点的样本预测值都为该节点的训练均值,所以此时的损失值为:
L = [ ( y 1 − y ˉ ) 2 + . . . + ( y n − y ˉ ) 2 ] n L=\frac{[(y_1-\bar{y})^2+...+(y_n-\bar{y})^2]}{n} L=n[(y1yˉ)2+...+(ynyˉ)2]
接下来就是遍历每一个特征,然后在特征中寻找一个划分点,让大于和小于该值的样本分别进入左右两个子节点,使得左右两个节点的损失值之和最小。即:
m i n ( L l e f t + L r i g h t ) = m i n [ ∑ x i ∈ l e f t ( y i − y ˉ l e f t ) 2 + ∑ x i ∈ r i g h r ( y i − y ˉ r i g h t ) 2 ] min(L_{left}+L_{right})=min[\sum_{x_i\in{left}}(y_i- \bar{y} _{left})^2+\sum_{x_i\in{righr}}(y_i-\bar{y}_{right})^2] min(Lleft+Lright)=min[xileft(yiyˉleft)2+xirighr(yiyˉright)2]
然后按照上述步骤递归下去,直到达到预设的条件为止,比如树的最大深度等。

CART分类树采用叶子节点里概率最大的类别作为当前节点的预测类别。而回归树输出不是类别,它采用的是用最终叶子的均值或者中位数来预测输出结果。

1.4 CART的剪枝

由于决策树算法很容易对训练集过拟合,而导致泛化能力差,为了解决这个问题,我们需要对CART树进行剪枝,来增加决策树的泛化能力。CART采用的办法是后剪枝法,后面的内容主要来分析后剪枝算法。

也就是说,CART树的剪枝算法可以概括为两步,
第一步是从原始决策树生成各种剪枝效果的决策树,
第二步是用交叉验证来检验剪枝后的预测能力,选择泛化预测能力最好的剪枝后的树作为最终的CART树。

那么按照步骤来进行,我们可以分析如下:
对于位于节点t的任意一颗子树 T t T_t Tt,如果没有剪枝,它的损失函数是
C a ( T t ) = C ( T t ) + α ∣ T t ∣ Ca(T _t)=C(T _t )+\alpha∣T _t ∣ Ca(Tt)=C(Tt)+αTt
其中 α ​ \alpha​ α​是正则化因子, ∣ T t ∣ ​ ∣T_t∣​ Tt是子树 ​ T t ​ ​T_t​ Tt​的结点的个数, C ( T t ) C(T_t) C(Tt)​为训练数据的预测误差。
如果将其剪掉,仅仅保留根节点,则损失是
C a ( T t ) = C ( T ) + α Ca(T _t )=C(T)+\alpha Ca(Tt)=C(T)+α
这样分析之后,何时才能确定剪枝呢?
我们可以假设当剪枝前和剪枝后的损失函数相同,即T这个树的结点数更少,可以对 T t T_t Tt这个子树进行剪枝,直接将其变为树T。有了上面的假设,我们可以得到等式如下
C ( T t ) + α ∣ T t ∣ = C ( T ) + α C(T _t )+\alpha|T_t|=C(T)+\alpha C(Tt)+αTt=C(T)+α
解得:
α = C ( T ) − C ( T ) ∣ T t ∣ − 1 \alpha=\frac{C(T)-C(T)}{|T_t|-1} α=Tt1C(T)C(T)
那么如何选择出最优的CART分类树呢?我们可以采用交叉验证策略,上面我们计算出了每个子树是否剪枝的阈值 ​ α ​ ​\alpha​ α​​,如果我们把所有的节点是否剪枝的值 ​ α ​ ​\alpha​ α​都计算出来,然后分别针对不同的 ​ α ​ ​\alpha​ α​所对应的剪枝后的最优子树做交叉验证。这样就可以选择一个最好的 ​ α ​ ​\alpha​ α​,有了这个 ​ α ​ ​\alpha​ α​,我们就可以用对应的最优子树作为最终结果。
参考文章

二、Boosting

Boosting是一族可将弱学习器提升为强学习器的算法。这族算法的工作机制类似:先从初始训练集训练出一个基学习器,再根据基学习器的表现对训练样本分布进行调整,使得先前基学习器做错的训练样本在后续受到更多关注,然后基于调整后的样本分布来训练下一个基学习器;如此重复进行,直至基学习器数目达到事先指定的值M。最终将这M个学习器进行加权结合。

三、提升树Boosting Tree(BT)

基学习器是CART回归树
提升树算法:

  1. 初始化 F 0 ( x ) = 0 F_0(x)=0 F0(x)=0

  2. m = 1 , 2 , … , M m=1, 2, …, M m=1,2,,M
    (1)计算残差
    r m i = y i − F m − 1 ( x ) , i = 1 , 2 , … , N r_{mi}=y_i-F_{m-1}(x), i=1, 2, …,N rmi=yiFm1(x),i=1,2,,N
    (2) 拟合残差 r m i r_{mi} rmi学习一个回归树,得到 h m ( x ) h_m(x) hm(x)

    假设我们前一轮迭代得到的强学习器是 F t − 1 ( x ) F_{t-1}(x) Ft1(x)
    损失函数是 L ( y , F t − 1 ( x ) ) L(y,F_{t-1}(x)) L(y,Ft1(x))
    我们本轮迭代的目标是找到一个弱学习器 h t ( x ) h_t(x) ht(x)
    最小化本轮的损失
    L ( y , F t ( x ) ) = L ( y , F t − 1 ( x ) + h t ( x ) ) L(y,F_t(x))=L(y,F_{t-1}(x)+h_t(x)) L(y,Ft(x))=L(y,Ft1(x)+ht(x))
    当采用平方损失函数时
    L ( y , F t − 1 ( x ) + h t ( x ) ) = ( y − F t − 1 − h t ( x ) ) 2 = ( r − h t ( x ) ) 2 L(y,F_{t-1}(x)+h_t(x))=(y-F_{t-1}-h_t(x))^2=(r-h_t(x))^2 L(y,Ft1(x)+ht(x))=(yFt1ht(x))2=(rht(x))2
    这里 r = y − F t − 1 ( x ) r=y-F_{t-1}(x) r=yFt1(x)是当前模型拟合数据的残差。所以对于提升树来说只需要简单地拟合当前模型的残差。
    (3) 更新 F m ( x ) = F m − 1 ( x ) + h m ( x ) F_m(x)=F_{m-1}(x)+h_m(x) Fm(x)=Fm1(x)+hm(x)

  3. 得到回归问题提升树
    F M ( x ) = ∑ m = 1 M h m ( x ) F_M(x)=\sum_{m=1}^Mh_m(x) FM(x)=m=1Mhm(x)

参考文献

四、梯度提升Gradient boosting (GB)

当损失函数是平方损失和指数损失函数时,提升树每一步优化是很简单的,但是对于一般损失函数而言,往往每一步优化起来不那么容易,针对这一问题,Friedman提出了梯度提升算法,这是利用最速下降的近似方法,其关键是利用损失函数的负梯度作为提升树算法中的残差的近似值。
Gradient boosting是一种用于回归和分类问题的机器学习技术,是一种Boosting的方法。

Gradient boosting的主要思想是:迭代产生多个(M个)弱的模型,每一次建立模型是在之前建立模型损失函数的梯度下降方向。然后将每个弱模型的预测结果相加,后面的模型 F m + 1 ( h x ) F_{m+1}(hx) Fm+1(hx)基于前面学习模型的 F m ( x ) F_{m}(x) Fm(x)的效果生成的,关系如下:
F m ( x ) = F m − 1 ( x ) + ρ m h ( x ; α m ) F_{m}(x)=F_{m-1}(x)+\rho_mh (x;\alpha_m) Fm(x)=Fm1(x)+ρmh(x;αm)
将损失定义为任意函数的boosting就是Gradient Boosting。
算法步骤:

  1. 初始化模型 F 0 ( x ) = a r g m i n L ( y , ρ ) F_0(x)=argmin_L(y,\rho) F0(x)=argminL(y,ρ)
  2. m = 1 , 2 , … , M m=1, 2, …, M m=1,2,,M
    (1)计算伪残差
    r m i = − d L ( y , F m − 1 ( x i ) ) d F m − 1 ( x i ) , i = 1 , 2 , … , N r_{mi}=-\frac{dL(y,F_{m-1}(x_i))}{dF_{m-1}(x_i)}, i=1, 2, …,N rmi=dFm1(xi)dL(y,Fm1(xi)),i=1,2,,N
    (2) 拟合残差 r m i r_{mi} rmi学习一个弱学习器,得到 h ( x ; α m ) h(x;\alpha_m) h(x;αm)
    α m = a r g m i n α , β ∑ i = 1 N [ r m i − β h ( x i ; α ) ] \alpha_m=argmin_{\alpha,\beta} \sum_{i=1}^N[r_{mi}-\beta h(x_i;\alpha)] αm=argminα,βi=1N[rmiβh(xi;α)]
    ρ m = a r g m i n ρ ∑ i = 1 N L ( r m i , F n − 1 ( x i ) + ρ h ( x i ; α m ) ) \rho_m=argmin_\rho\sum_{i=1}^NL(r_{mi},F_{n-1}(x_i)+\rho h(x_i;\alpha_m)) ρm=argminρi=1NL(rmi,Fn1(xi)+ρh(xi;αm))
    (3) 更新 F m ( x ) = F m − 1 ( x ) + ρ m h ( x ; α m ) F_m(x)=F_{m-1}(x)+\rho_m h(x;\alpha_m) Fm(x)=Fm1(x)+ρmh(x;αm)
  3. 得到最终的强学习器
    F M ( x ) = ∑ m = 1 M ρ m h ( x ; α m ) F_M(x)=\sum_{m=1}^M\rho_m h(x;\alpha_m) FM(x)=m=1Mρmh(x;αm)

五、梯度提升决策树Gradient boosting Decision Tree(GBDT)

GBDT也是集成学习Boosting家族的成员,但是却和传统的Adaboost有很大的不同。
AdaBoost算法是模型为加法模型,损失函数为指数函数,学习算法为前向分步算法时的分类问题。而GBDT算法是模型为加法模型,学习算法为前向分步算法,基函数为CART树,损失函数为平方损失函数的回归问题,为指数函数的分类问题和为一般损失函数的一般决策问题。在针对基学习器的不足上,AdaBoost算法是通过提升错分数据点的权重来定位模型的不足,而梯度提升算法是通过算梯度来定位模型的不足。
GBDT使用的决策树是CART回归树,无论是处理回归问题还是二分类以及多分类,GBDT使用的决策树通通都是都是CART回归树。为什么不用CART分类树呢?因为GBDT每次迭代要拟合的是梯度值,是连续值所以要用回归树。
GBDT是GB和DT的结合
算法步骤:

  1. 初始化:(估计使损失函数极小化的常数值,它是只有一个根节点的树,一般平方损失函数为节点的均值,而绝对损失函数为节点样本的中位数)
    F 0 ( x ) = a r g m i n c ∑ i = 1 N L ( y i , c ) F_0(x)=argmin_c\sum_{i=1}^NL(y_i,c) F0(x)=argminci=1NL(yi,c)
  2. m = 1 , 2 , … , M m=1, 2, …, M m=1,2,,M (M表示迭代次数,即生成的弱学习器个数):
    (1) 对样本 i = 1 , 2 , . . . , M i=1,2,...,M i=1,2,...,M,计算损失函数的负梯度在当前模型的值将它作为残差的估计,对于平方损失函数为,它就是通常所说的残差;而对于一般损失函数,它就是残差的近似值(伪残差):
    r m i = − d L ( y , F m − 1 ( x i ) ) d F m − 1 ( x i ) , i = 1 , 2 , … , N r_{mi}=-\frac{dL(y,F_{m-1}(x_i))}{dF_{m-1}(x_i)}, i=1, 2, …,N rmi=dFm1(xi)dL(y,Fm1(xi)),i=1,2,,N
    (2) 对 ( x 1 , r m 1 ) , . . . , ( x m , r m N ) {(x_1,r_{m1}),..., (x_m,r_{mN})} (x1,rm1),...,(xm,rmN)拟合一个回归树,得到第m棵树的叶节点区域 R m j R_{mj} Rmj j − 1 , 2 , . . . , J j-1,2,..., J j1,2,...,J(J表示每棵树的叶节点个数)
    (3) 对 j − 1 , 2 , . . . , J j-1,2,..., J j1,2,...,J,利用线性搜索,估计叶节点区域的值,使损失函数最小化,计算
    c m j = a r g m i n c ∑ x i ∈ R m j L ( y i , F m − 1 ( x i + c ) ) c_{mj}=argmin_c\sum_{x_i\in R_{mj}}L(y_i,F_{m-1}(x_i+c)) cmj=argmincxiRmjL(yi,Fm1(xi+c))
    (4) 更新
    F m ( x ) = F m − 1 ( x ) + ∑ j = 1 J c m j I ( x ∈ R m j ) F_m(x)=F_{m-1}(x)+\sum_{j=1}^Jc_{mj}I(x\in R_{mj}) Fm(x)=Fm1(x)+j=1JcmjI(xRmj)
    3. 得到回归树
    F M ( x ) = ∑ m = 1 M ∑ j = 1 J c m j I ( x ∈ R m j ) F_M(x)=\sum_{m=1}^M\sum_{j=1}^Jc_{mj}I(x\in R_{mj}) FM(x)=m=1Mj=1JcmjI(xRmj)

5.1 GBDT优缺点

  1. GBDT优点
  • 可以灵活处理各种类型的数据,包括连续值和离散值。
  • 在相对较少的调参时间情况下,预测的准确率也比较高,相对SVM而言。
  • 在使用一些健壮的损失函数,对异常值得鲁棒性非常强。比如Huber损失函数和Quantile损失函数。
  1. GBDT缺点
  • 由于弱学习器之间存在较强依赖关系,难以并行训练。可以通过自采样的SGBT来达到部分并行。

5.2 GBDT防止过拟合——正则化

  1. 给每棵数的输出结果乘上一个步长 α \alpha α(learning rate)
    对于前面的弱学习器的迭代:
    F m ( x ) = F m − 1 + T ( x ; γ m ) F_m(x)=F_{m-1}+T(x;\gamma _m) Fm(x)=Fm1+T(x;γm)
    加上正则化项,则有
    F m ( x ) = F m − 1 + α T ( x ; γ m ) F_m(x)=F_{m-1}+\alpha T(x;\gamma _m) Fm(x)=Fm1+αT(x;γm)
    此处,a的取值范围为(0,1]。对于同样的训练集学习效果,较小的a意味着需要更多的弱学习器的迭代次数。通常我们用步长和迭代最大次数一起决定算法的拟合效果。
  2. 第二种正则化的方式就是通过子采样比例(subsample)。取值范围为(0,1]。
    GBDT这里的做法是在每一轮建树时,样本是从原始训练集中采用无放回随机抽样的方式产生,与随机森立的有放回抽样产生采样集的方式不同。若取值为1,则采用全部样本进行训练,若取值小于1,则不选取全部样本进行训练。选择小于1的比例可以减少方差,防止过拟合,但可能会增加样本拟合的偏差。取值要适中,推荐[0.5,0.8]。
  3. 第三种是对弱学习器即CART回归树进行正则化剪枝。(如控制树的最大深度、节点的最少样本数、最大叶子节点数、节点分支的最小样本数等)

5.3 sklearn参数

在scikit-learning中,GradientBoostingClassifier对应GBDT的分类算法,GradientBoostingRegressor对应GBDT的回归算法。
具体算法参数情况如下:

GradientBoostingRegressor(loss=’ls’, learning_rate=0.1, n_estimators=100,
subsample=1.0, criterion=’friedman_mse’, min_samples_split=2,
min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_depth=3,
min_impurity_decrease=0.0, min_impurity_split=None, init=None,
random_state=None, max_features=None, alpha=0.9, verbose=0,
max_leaf_nodes=None, warm_start=False, presort=’auto’,
validation_fraction=0.1, n_iter_no_change=None, tol=0.0001)

参数说明:

  • n_estimators:弱学习器的最大迭代次数,也就是最大弱学习器的个数。
  • learning_rate:步长,即每个学习器的权重缩减系数a,属于GBDT正则化方化手段之一。
  • subsample:子采样,取值(0,1]。决定是否对原始数据集进行采样以及采样的比例,也是GBDT正则化手段之一。
  • init:我们初始化的时候的弱学习器。若不设置,则使用默认的。
  • loss:损失函数,可选{‘ls’-平方损失函数,‘lad’绝对损失函数-,‘huber’-huber损失函数,‘quantile’-分位数损失函数},默认’ls’。
  • alpha:当我们在使用Huber损失"Huber"和分位数损失"quantile"时,需要指定相应的值。默认是0.9,若噪声点比较多,可适当降低这个分位数值。
  • criterion:决策树节搜索最优分割点的准则,默认是"friedman_mse",可选"mse"-均方误差与’mae"-绝对误差。
  • max_features:划分时考虑的最大特征数,就是特征抽样的意思,默认考虑全部特征。
  • max_depth:树的最大深度。
  • min_samples_split:内部节点再划分所需最小样本数。
  • min_samples_leaf:叶子节点最少样本数。
  • max_leaf_nodes:最大叶子节点数。
  • min_impurity_split:节点划分最小不纯度。
  • presort:是否预先对数据进行排序以加快最优分割点搜索的速度。默认是预先排序,若是稀疏数据,则不会预先排序,另外,稀疏数据不能设置为True。
  • validationfraction:为提前停止而预留的验证数据比例。当n_iter_no_change设置时才能用。
  • n_iter_no_change:当验证分数没有提高时,用于决定是否使用早期停止来终止训练。

5.4 GBDT应用场景

GBDT几乎可以用于所有回归问题(线性/非线性),相对loigstic regression仅能用于线性回归,GBDT的适用面非常广。亦可用于分类问题。
参考文章

六、XGBoost

经过前面的学习,我们已经知道,GBDT是一种基于集成思想下的Boosting学习器,并采用梯度提升的方法进行每一轮的迭代最终组建出强学习器,这样的话算法的运行往往要生成一定数量的树才能达到令我们满意的准确率。当数据集大且较为复杂时,运行一次极有可能需要几千次的迭代运算,这将对我们使用算法造成巨大的计算瓶颈。
针对这一问题,华盛顿大学的陈天奇博士开发出了XGBoost(eXtreme Gradient Boosting),它是Gradient Boosting Machine的一个c++实现,并在原有的基础上加以改进,从而极大地提升了模型训练速度和预测精度。可以说,XGBoost是Gradient Boosting的高效实现。

在XGBoost中,目标函数的形式为: O b j ( Θ ) = L ( θ ) + Ω ( Θ ) Obj(\Theta) = L(\theta) + \Omega(\Theta) Obj(Θ)=L(θ)+Ω(Θ)

  • L ( θ ) L(\theta) L(θ):损失函数,常用的损失函数有:
    1. 平方损失: L ( θ ) = ∑ i ( y i − y i ^ ) 2 L(\theta)=\sum_i(y_i-\hat{y_i})^2 L(θ)=i(yiyi^)2
    2. Logistic损失: L ( θ ) = ∑ i [ y i l n ( 1 + e − y i ^ ) + ( 1 − y i ) l n ( 1 + e y i ^ ) ] L(\theta)=\sum_i[y_iln(1+e^{-\hat{y_i}})+(1-y_i)ln(1+e^{\hat{y_i}})] L(θ)=i[yiln(1+eyi^)+(1yi)ln(1+eyi^)]
  • Ω ( Θ ) \Omega(\Theta) Ω(Θ):正则化项,之所以要引入它是因为我们的目标是希望生成的模型能准确的预测新的样本(即应用于测试数据集),而不是简单的拟合训练集的结果(这样会导致过拟合)。所以需要在保证模型“简单”的基础上最小化训练误差,这样得到的参数才具有好的泛化性能。而正则项就是用于惩罚复杂模型,避免预测模型过分拟合训练数据,常用的正则有L_1正则与L_2正则。

如果目标函数中的损失函数权重过高,那么模型的预测精度则不尽人意,反之如果正则项的权重过高,所生成的模型则会出现过拟合情况,难以对新的数据集做出有效预测。只有平衡好两者之间的关系,控制好模型复杂度,并在此基础上对参数进行求解,生成的模型才会“简单有效”(这也是机器学习中的偏差方差均衡)。

6.1 XGBoost的推导过程

6.1.1 目标函数的迭代与泰勒展开

由于之前已经学习过树的生成及集成方法,这里不再赘述。首先,我们可以把某一次迭代后集成的模型表示为:
y ^ i = ∑ k = 1 K F k ( x i ) , F k ∈ F \hat{y}_i=\sum_{k=1}^KF_k(x_i), F_k\in \mathcal{F} y^i=k=1KFk(xi),FkF
y ^ i \hat{y}_i y^i也就是上文中的 F m ( x ) F_m(x) Fm(x)
所对应的目标函数: O b j ( θ ) = L ( y i , y ^ i ) + ∑ k = 1 K ( F k ) Obj(\theta) = L(y_i,\hat{y}_i) + \sum_{k=1}^K(F_k) Obj(θ)=L(yi,y^i)+k=1K(Fk)
将这两个公式进行扩展,应用在前t轮的模型迭代中,具体表示为:
y ^ i ( 0 ) = 0 y ^ i ( 1 ) = F 1 ( x i ) = y ^ i ( 0 ) + F 1 ( x i ) y ^ i ( 2 ) = F 1 ( x i ) + F 2 ( x i ) = y ^ i ( 1 ) + F 2 ( x i ) ⋯ y ^ i ( t ) = ∑ k = 1 t F k ( x i ) = y ^ i ( t − 1 ) + F t ( x i ) \begin {aligned} &\hat{y}_i^{(0)}=0\\ &\hat{y}_i^{(1)}=F_1(x_i)=\hat{y}_i^{(0)}+F_1(x_i)\\ &\hat{y}_i^{(2)}=F_1(x_i)+F_2(x_i)=\hat{y}_i^{(1)}+F_2(x_i)\\ &\cdots\\ &\hat{y}_i^{(t)}=\sum_{k=1}^tF_k(x_i)=\hat{y}_i^{(t-1)}+F_t(x_i) \end{aligned} y^i(0)=0y^i(1)=F1(xi)=y^i(0)+F1(xi)y^i(2)=F1(xi)+F2(xi)=y^i(1)+F2(xi)y^i(t)=k=1tFk(xi)=y^i(t1)+Ft(xi)
y i ^ ( t − 1 ) \hat{y_i}^{(t-1)} yi^(t1)就是前 t − 1 t-1 t1轮的模型预测, F t ( x i ) F_t(x_i) Ft(xi)为新t轮加入的预测函数。
这里自然就涉及一个问题:如何选择在每一轮中加入的 F ( x i ) F(x_i) F(xi)呢?答案很直接,选取的 f ( x i ) f(x_i) f(xi)必须使得我们的目标函数尽量最大地降低(这里应用到了Boosting的基本思想,即当前的基学习器重点关注以前所有学习器犯错误的那些数据样本,以此来达到提升的效果)。先对目标函数进行改写,表示如下:
O b j ( t ) = ∑ i = 1 n L ( y i , y ^ i ( t ) ) + ∑ i = 1 t Ω ( F i ) = ∑ i = 1 n L ( y i , y ^ i ( t − 1 ) + F t ( x i ) ) + Ω ( F t ) + c o n s t a n t \begin{aligned} Obj^{(t)} & = \sum_{i=1}^nL(y_i, \hat{y}_i^{(t)}) + \sum_{i=1}^t \Omega(F_i) \\ & = \sum_{i=1}^n L(y_i, \hat{y}_i^{(t-1)} + F_t(x_i)) + \Omega(F_t) + constant \end{aligned} Obj(t)=i=1nL(yi,y^i(t))+i=1tΩ(Fi)=i=1nL(yi,y^i(t1)+Ft(xi))+Ω(Ft)+constant
如果我们考虑使用平方误差作为损失函数,公式可改写为:
O b j ( t ) = ∑ i = 1 n ( y i − ( y ^ i ( t − 1 ) + F t ( x i ) ) ) 2 + ∑ i = 1 t Ω ( F i ) = ∑ i = 1 n [ 2 ( y ^ i ( t − 1 ) − y i ) F t ( x i ) + F t ( x i ) 2 ] + Ω ( F t ) + c o n s t a n t \begin{aligned} Obj^{(t)} & = \sum_{i=1}^n (y_i - (\hat{y}_i^{(t-1)} + F_t(x_i)))^2 + \sum_{i=1}^t\Omega(F_i) \\ & = \sum_{i=1}^n [2(\hat{y}_i^{(t-1)} - y_i)F_t(x_i) + F_t(x_i)^2] + \Omega(F_t) + constant \end{aligned} Obj(t)=i=1n(yi(y^i(t1)+Ft(xi)))2+i=1tΩ(Fi)=i=1n[2(y^i(t1)yi)Ft(xi)+Ft(xi)2]+Ω(Ft)+constant
对于不是平方误差的情况,我们可以采用如下的泰勒展开近似来定义一个近似的目标函数,方便我们进行这一步的计算。

泰勒展开: f ( x + Δ x ) ≃ F ( x ) + F ′ ( x ) Δ x + 1 2 F ′ ′ ( x ) Δ x 2 f(x+\Delta x)\simeq F(x)+F^{'}(x)\Delta x+\frac{1}{2} F^{''}(x)\Delta x^2 f(x+Δx)F(x)+F(x)Δx+21F(x)Δx2
Obj ( t ) = ∑ i = 1 n [ L ( y i , y ^ i ( t − 1 ) ) + g i F t ( x i ) + 1 2 h i F t 2 ( x i ) ] + Ω ( F t ) + c o n s t a n t \text{Obj}^{(t)} = \sum_{i=1}^n [L(y_i, \hat{y}_i^{(t-1)}) + g_i F_t(x_i) + \frac{1}{2} h_i F_t^2(x_i)] + \Omega(F_t) + constant Obj(t)=i=1n[L(yi,y^i(t1))+giFt(xi)+21hiFt2(xi)]+Ω(Ft)+constant
其中 g i = ∂ y ^ i ( t − 1 ) L ( y i , y ^ i ( t − 1 ) ) , h i = ∂ y ^ i ( t − 1 ) 2 L ( y i , y ^ i ( t − 1 ) ) g_i= \partial_{\hat{y}_i^{(t-1)}} L(y_i, \hat{y}_i^{(t-1)}),h_i = \partial_{\hat{y}_i^{(t-1)}}^2 L(y_i, \hat{y}_i^{(t-1)}) gi=y^i(t1)L(yi,y^i(t1))hi=y^i(t1)2L(yi,y^i(t1))

如果移除掉常数项,我们会发现这个目标函数有一个非常明显的特点,它只依赖于每个数据点的在误差函数上的一阶导数和二阶导数 ( ∑ i = 1 n [ g i F t ( x i ) + 1 2 h i F t 2 ( x i ) ] + Ω ( F t ) (\sum_{i=1}^n [g_i F_t(x_i) + \frac{1}{2} h_i F_t^2(x_i)] + \Omega(F_t) i=1n[giFt(xi)+21hiFt2(xi)]+Ω(Ft)

6.1.2 决策树的复杂度

接着来讨论如何定义树的复杂度。我们先对于 F F F的定义做一下细化,把树拆分成结构部分 q q q和叶子权重部分 ω \omega ω。其中结构函数 q q q把输入映射到叶子的索引号上面去,而 ω \omega ω给定了每个索引号对应的叶子分数是什么。
具体公式为: F t ( x ) = ω q ( x ) , ω ∈ R T , q : R d → { 1 , 2 , ⋯   , T } F_t(x) = \omega _{q(x)}, \omega \in R^T, q: R^d\rightarrow \{1,2,\cdots,T\} Ft(x)=ωq(x),ωRT,q:Rd{1,2,,T}

当我们给定上述定义后,那么一棵树的复杂度就为 Ω ( F ) = γ T + 1 2 λ ∑ j = 1 T ω j 2 \Omega(F) = \gamma T + \frac{1}{2}\lambda \sum_{j=1}^T \omega_j^2 Ω(F)=γT+21λj=1Tωj2
这个复杂度包含了一棵树里面节点的个数(左侧),以及每个树叶子节点上面输出分数的 L 2 L_2 L2模平方(右侧)。当然这不是唯一的一种定义方式,不过这一定义方式学习出的树效果一般都比较不错。
简单提及一下 γ \gamma γ λ \lambda λ两个系数的作用, γ \gamma γ作为叶子节点的系数,使XGBoost在优化目标函数的同时相当于做了预剪枝 λ \lambda λ作为 L 2 L_2 L2平方模的系数 也是要起到防止过拟合的作用。

6.1.3 目标函数的最小化

接下来就是非常关键的一步,在这种新的定义下,我们可以把目标函数进行如下改写,其中 I I I被定义为每个叶子上面样本集合 I j = { i ∣ q ( x i ) = j } I_j = \{i|q(x_i)=j\} Ij={iq(xi)=j}
O b j ( t ) ≈ ∑ i = 1 n [ g i ω q ( x i ) + 1 2 h i ω q ( x i ) 2 ] + γ T + 1 2 λ ∑ j = 1 T ω j 2 = ∑ j = 1 T [ ( ∑ i ∈ I j g i ) ω j + 1 2 ( ∑ i ∈ I j h i + λ ) ω j 2 ] + γ T \begin{aligned} Obj^{(t)} &\approx \sum_{i=1}^n [g_i \omega_{q(x_i)} + \frac{1}{2} h_i \omega_{q(x_i)}^2] + \gamma T + \frac{1}{2}\lambda \sum_{j=1}^T \omega_j^2\\ &= \sum^T_{j=1} [(\sum_{i\in I_j} g_i) \omega_j + \frac{1}{2} (\sum_{i\in I_j} h_i + \lambda) \omega_j^2 ] + \gamma T \end{aligned} Obj(t)i=1n[giωq(xi)+21hiωq(xi)2]+γT+21λj=1Tωj2=j=1T[(iIjgi)ωj+21(iIjhi+λ)ωj2]+γT
分别定义 G j = ∑ i ∈ I j g i G_j = \sum_{i\in I_j} g_i Gj=iIjgi H j = ∑ i ∈ I j h i H_j = \sum_{i\in I_j} h_i Hj=iIjhi,上式简化为
O b j ( t ) = ∑ j = 1 T [ G j ω j + 1 2 ( H j + λ ) ω j 2 ] + γ T {Obj}^{(t)} = \sum^T_{j=1} [G_j\omega_j + \frac{1}{2} (H_j+\lambda) \omega_j^2] +\gamma T Obj(t)=j=1T[Gjωj+21(Hj+λ)ωj2]+γT
由此,我们将目标函数转换为一个一元二次方程求最小值的问题(在此式中,变量为 ω j \omega_j ωj,函数本质上是关于 ω j \omega_j ωj的二次函数),略去求解步骤,最终结果如下所示:
ω j ∗ = − G j H j + λ , O b j ∗ = − 1 2 ∑ j = 1 T G j 2 H j + λ + γ T \omega _j^\ast = -\frac{G_j}{H_j+\lambda},{Obj}^\ast = -\frac{1}{2} \sum_{j=1}^T \frac{G_j^2}{H_j+\lambda} + \gamma T ωj=Hj+λGjObj=21j=1THj+λGj2+γT
乍一看目标函数的计算与树的结构函数 q q q没有什么关系,但是如果我们仔细回看目标函数的构成,就会发现其中 G j G_j Gj H j H_j Hj的取值都是由第 j j j个树叶上数据样本所决定的。而第 j j j个树叶上所具有的数据样本则是由树结构函数 q q q决定的。也就是说,一旦树的结构 q q q确定,那么相应的目标函数就能够根据上式计算出来。那么树的生成问题也就转换为找到一个最优的树结构 q q q,使得它具有最小的目标函数。
计算求得的 O b j Obj Obj代表了当指定一个树的结构的时候,目标函数上面最多减少多少。所有我们可以把它叫做结构分数(structure score)。

6.1.4 枚举树的结构——贪心法

在前面分析的基础上,当寻找到最优的树结构时,我们可以不断地枚举不同树的结构,利用这个打分函数来寻找出一个最优结构的树,加入到我们的模型中,然后再重复这样的操作。不过枚举所有树结构这个操作不太可行,在这里XGBoost采用了常用的贪心法,即每一次尝试去对已有的叶子加入一个分割。对于一个具体的分割方案,我们可以获得的增益可以由如下公式计算得到:
G a i n = 1 2 [ G L 2 H L + λ + G R 2 H R + λ − ( G L + G R ) 2 H L + H R + λ ] − γ Gain = \frac{1}{2} \left[\frac{G_L^2}{H_L+\lambda}+\frac{G_R^2}{H_R+\lambda}-\frac{(G_L+G_R)^2}{H_L+H_R+\lambda}\right] - \gamma Gain=21[HL+λGL2+HR+λGR2HL+HR+λ(GL+GR)2]γ
其中 G L 2 H L + λ \frac{G_L^2}{H_L+\lambda} HL+λGL2代表左子树分数, G R 2 H R + λ \frac{G_R^2}{H_R+\lambda} HR+λGR2代表右子树分数, ( G L + G R ) 2 H L + H R + λ \frac{(G_L+G_R)^2}{H_L+H_R+\lambda} HL+HR+λ(GL+GR)2代表不分割时我们可以获得的分数, γ \gamma γ代表加入新叶子节点引入的复杂度代价。

对于每次扩展,我们还是要枚举所有可能的分割方案,那么如何高效地枚举所有的分割呢?假设需要枚举所有 x < a x<a x<a这样的条件,那么对于某个特定的分割 a a a我们要计算 a a a左边和右边的导数和,

我们可以发现对于所有的 a a a,我们只要做一遍从左到右的扫描就可以枚举出所有分割的梯度与 G L G_L GL G R G_R GR。然后用上面的公式计算每个分割方案的分数就可以了。

但需要注意是:引入的分割不一定会使得情况变好,因为在引入分割的同时也引入新叶子的惩罚项。所以通常需要设定一个阈值,如果引入的分割带来的增益小于一个阀值的时候,我们可以剪掉这个分割。此外在XGBoost的具体实践中,通常会设置树的深度来控制树的复杂度,避免单个树过于复杂带来的过拟合问题。
到这里为止,XGBoost的数学推导就简要介绍完毕。

6.2 XGBoost与GBDT比较

同样是梯度提升,同样是集成学习,那么XGBoost比GBDT要好在哪里呢?

  1. GBDT是以CART为基分类器,但XGBoost在此基础上还支持线性分类器,此时XGBoost相当于带 L 1 L_1 L1 L 2 L_2 L2正则化项的Logistics回归(分类问题)或者线性回归(回归问题)。
  2. XGBoost在目标函数里加入了正则项,用于控制模型的复杂度。正则项里包含了树的叶子节点个数和每棵树叶子节点上面输出分数的 L 2 L_2 L2模平方。从偏差方差权衡的角度来讲,正则项降低了模型的variance,使学习出来的模型更加简单,防止过拟合。
  3. 传统的GBDT在优化时只用到一阶导数,XGBoost则对目标函数进行了二阶泰勒展开,同时用到了一阶和二阶导数。(顺便提一下,XGBoost工具支持自定义代价函数,只要函数可一阶和二阶求导)。
  4. 树节点在进行分裂时,我们需要计算每个特征的每个分割点对应的增益,即用贪心法枚举所有可能的分割点。当数据无法一次载入内存或者在分布式情况下,贪心算法效率就会变得很低,所以XGBoost采用了一种近似的算法。大致的思想是根据百分位法列举几个可能成为分割点的候选者,然后从候选者中根据上面求分割点的公式计算找出最佳的分割点。
  5. Shrinkage(缩减),相当于学习速率(XGBoost中的eta)。XGBoost在进行完一次迭代后,会将叶子节点的权重乘上该系数,主要是为了削弱每棵树的影响,让后面有更大的学习空间。实际应用中,一般把eta设置得小一点,然后迭代次数设置得大一点。(当然普通的GBDT实现也有学习速率)。
  6. 特征列排序后以块的形式存储在内存中,在迭代中可以重复使用;虽然boosting算法迭代必须串行,但是在处理每个特征列时可以做到并行。
  7. 列抽样(column subsampling):XGBoost借鉴了随机森林的做法,支持列抽样,不仅能降低过拟合,还能减少计算,这也是XGBoost异于传统GBDT的一个特性。
  8. 除此之外,XGBoost还考虑了当数据量比较大,内存不够时怎么有效的使用磁盘,主要是结合多线程、数据压缩、分片的方法,尽可能的提高算法效率。
    参考文章

6.3 XGBoost的优势

  1. 正则化
  • 标准GBM的实现没有像XGBoost这样的正则化步骤。正则化对减少过拟合也是有帮助的。
  • 实际上,XGBoost以“正则化提升(regularized boosting)”技术而闻名。
  1. 并行处理
  • XGBoost可以实现并行处理,相比GBM有了速度的飞跃。
  • 不过,众所周知,Boosting算法是顺序处理的,它怎么可能并行呢?每一课树的构造都依赖于前一棵树,那具体是什么让我们能用多核处理器去构造一个树呢?我希望你理解了这句话的意思。如果你希望了解更多,点击这个链接。
  • XGBoost 也支持Hadoop实现。
  1. 高度的灵活性
  • XGBoost 允许用户定义自定义优化目标和评价标准。
  • 它对模型增加了一个全新的维度,所以我们的处理不会受到任何限制。
  1. 缺失值处理
  • XGBoost内置处理缺失值的规则。
  • 用户需要提供一个和其它样本不同的值,然后把它作为一个参数传进去,以此来作为缺失值的取值。XGBoost在不同节点遇到缺失值时采用不同的处理方法,并且会学习未来遇到缺失值时的处理方法。
  1. 剪枝
  • 当分裂时遇到一个负损失时,GBM会停止分裂。因此GBM实际上是一个贪心算法。
  • XGBoost会一直分裂到指定的最大深度(max_depth),然后回过头来剪枝。如果某个节点之后不再有正值,它会去除这个分裂。
  • 这种做法的优点,当一个负损失(如-2)后面有个正损失(如+10)的时候,就显现出来了。GBM会在-2处停下来,因为它遇到了一个负值。但是XGBoost会继续分裂,然后发现这两个分裂综合起来会得到+8,因此会保留这两个分裂。
  1. 内置交叉验证
  • XGBoost允许在每一轮boosting迭代中使用交叉验证。因此,可以方便地获得最优boosting迭代次数。
  • 而GBM使用网格搜索,只能检测有限个值。
  1. 在已有的模型基础上继续
  • XGBoost可以在上一轮的结果上继续训练。这个特性在某些特定的应用上是一个巨大的优势。
  • sklearn中的GBM的实现也有这个功能,两种算法在这一点上是一致的。

6.4 XGBoost的参数

XGBoost的作者把所有的参数分成了三类:

  1. 通用参数:宏观函数控制。
  2. Booster参数:控制每一步的booster(tree/regression)。
  3. 学习目标参数:控制训练目标的表现。

6.4.1 通用参数

这些参数用来控制XGBoost的宏观功能。

  1. booster[默认gbtree]
  • 选择每次迭代的模型,有两种选择:
    gbtree:基于树的模型
    gbliner:线性模型
  1. silent[默认0]
    -当这个参数值为1时,静默模式开启,不会输出任何信息。
  • 一般这个参数就保持默认的0,因为这样能帮我们更好地理解模型。
  1. nthread[默认值为最大可能的线程数]
  • 这个参数用来进行多线程控制,应当输入系统的核数。
  • 如果你希望使用CPU全部的核,那就不要输入这个参数,算法会自动检测它。

还有两个参数,XGBoost会自动设置,目前你不用管它。接下来咱们一起看booster参数。

6.4.2 booster参数

尽管有两种booster可供选择,我这里只介绍tree booster,因为它的表现远远胜过linear booster,所以linear booster很少用到。

  1. eta[默认0.3]
  • 和GBM中的 learning rate 参数类似。
  • 通过减少每一步的权重,可以提高模型的鲁棒性。
  • 典型值为0.01-0.2。
  1. min_child_weight[默认1]
  • 决定最小叶子节点样本权重和。
  • 和GBM的 min_child_leaf 参数类似,但不完全一样。XGBoost的这个参数是最小样本权重的和,而GBM参数是最小样本总数。
  • 这个参数用于避免过拟合。当它的值较大时,可以避免模型学习到局部的特殊样本。
  • 但是如果这个值过高,会导致欠拟合。这个参数需要使用CV来调整。
  1. max_depth[默认6]
  • 和GBM中的参数相同,这个值为树的最大深度。
  • 这个值也是用来避免过拟合的。max_depth越大,模型会学到更具体更局部的样本。
  • 需要使用CV函数来进行调优。
  • 典型值:3-10
  1. max_leaf_nodes
  • 树上最大的节点或叶子的数量。
  • 可以替代max_depth的作用。因为如果生成的是二叉树,一个深度为n的树最多生成 n 2 n2 n2 个叶子。-
  • 如果定义了这个参数,GBM会忽略max_depth参数。
  1. gamma[默认0]
  • 在节点分裂时,只有分裂后损失函数的值下降了,才会分裂这个节点。Gamma指定了节点分裂所需的最小损失函数下降值。
  • 这个参数的值越大,算法越保守。这个参数的值和损失函数息息相关,所以是需要调整的。
  1. max_delta_step[默认0]
  • 这参数限制每棵树权重改变的最大步长。如果这个参数的值为0,那就意味着没有约束。如果它被赋予了某个正值,那么它会让这个算法更加保守。
  • 通常,这个参数不需要设置。但是当各类别的样本十分不平衡时,它对逻辑回归是很有帮助的。
  • 这个参数一般用不到,但是你可以挖掘出来它更多的用处。
  1. subsample[默认1]
  • 和GBM中的subsample参数一模一样。这个参数控制对于每棵树,随机采样的比例。
  • 减小这个参数的值,算法会更加保守,避免过拟合。但是,如果这个值设置得过小,它可能会导致欠拟合。
  • 典型值:0.5-1
  1. colsample_bytree[默认1]
  • 和GBM里面的max_features参数类似。用来控制每棵随机采样的列数的占比(每一列是一个特征)。
  • 典型值:0.5-1
  1. colsample_bylevel[默认1]
  • 用来控制树的每一级的每一次分裂,对列数的采样的占比。
  • 我个人一般不太用这个参数,因为subsample参数和colsample_bytree参数可以起到相同的作用。但是如果感兴趣,可以挖掘这个参数更多的用处。
  1. lambda[默认1]
  • 权重的L2正则化项。(和Ridge regression类似)。
  • 这个参数是用来控制XGBoost的正则化部分的。虽然大部分数据科学家很少用到这个参数,但是这个参数在减少过拟合上还是可以挖掘出更多用处的。
  1. alpha[默认1]
  • 权重的 L 1 L_1 L1正则化项。(和Lasso regression类似)。
  • 可以应用在很高维度的情况下,使得算法的速度更快。
  1. scale_pos_weight[默认1]
  • 在各类别样本十分不平衡时,把这个参数设定为一个正值,可以使算法更快收敛。

6.4.3 学习目标参数

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

  1. objective[默认reg:linear]
  • 这个参数定义需要被最小化的损失函数。最常用的值有:
    (1) binary:logistic 二分类的逻辑回归,返回预测的概率(不是类别)。
    (2) multi:softmax 使用softmax的多分类器,返回预测的类别(不是概率)。
    在这种情况下,你还需要多设一个参数:num_class(类别数目)。
    (3) multi:softprob 和multi:softmax参数一样,但是返回的是每个数据属于各个类别的概率。
    2. eval_metric[默认值取决于objective参数的取值]
    • 对于有效数据的度量方法。
    • 对于回归问题,默认值是rmse,对于分类问题,默认值是error。
    • 典型值有:
      (1) rmse 均方根误差 ( ∑ i = 1 N ϵ 2 N ) (\sqrt \frac{\sum_{i=1}^N \epsilon^2}{N}) (Ni=1Nϵ2 )
      (2) mae 平均绝对误差 ( ∑ i = 1 N ∣ ϵ ∣ N ) (\frac {\sum_{i=1}^N |\epsilon|}{N} ) (Ni=1Nϵ)
      (3) logloss 负对数似然函数值
      (4) error 二分类错误率(阈值为0.5)
      (5) merror 多分类错误率
      (6) mlogloss 多分类logloss损失函数
      (7) auc 曲线下面积
    1. seed(默认0)
    • 随机数的种子
    • 设置它可以复现随机数据的结果,也可以用于调整参数
      如果你之前用的是Scikit-learn,你可能不太熟悉这些参数。但是有个好消息,python的XGBoost模块有一个sklearn包,XGBClassifier。这个包中的参数是按sklearn风格命名的。会改变的函数名是:
      (1) eta -> learning_rate
      (2) lambda -> reg_lambda
      (3) alpha -> reg_alpha
      你肯定在疑惑为啥咱们没有介绍和GBM中的n_estimators类似的参数。XGBClassifier中确实有一个类似的参数,但是,是在标准XGBoost实现中调用拟合函数时,把它作为num_boosting_rounds参数传入。
      XGBoost Guide 的一些部分是我强烈推荐大家阅读的,通过它可以对代码和参数有一个更好的了解:
      XGBoost Parameters (official guide)
      XGBoost Demo Codes (xgboost GitHub repository)
      Python API Reference (official guide)
  1. 调参示例
    我们从Data Hackathon 3.x AV版的hackathon中获得数据集,和GBM 介绍文章中是一样的。更多的细节可以参考competition page
    数据集可以从这里下载。我已经对这些数据进行了一些处理:
  • City变量,因为类别太多,所以删掉了一些类别。
  • DOB变量换算成年龄,并删除了一些数据。
  • 增加了 EMI_Loan_Submitted_Missing 变量。如果EMI_Loan_Submitted变量的数据缺失,则这个参数的值为1。否则为0。删除了原先的EMI_Loan_Submitted变量。
  • EmployerName变量,因为类别太多,所以删掉了一些类别。
  • 因为Existing_EMI变量只有111个值缺失,所以缺失值补充为中位数0。
  • 增加了 Interest_Rate_Missing 变量。如果Interest_Rate变量的数据缺失,则这个参数的值为1。否则为0。删除了原先的Interest_Rate变量。
  • 删除了Lead_Creation_Date,从直觉上这个特征就对最终结果没什么帮助。
  • Loan_Amount_Applied, Loan_Tenure_Applied 两个变量的缺项用中位数补足。
  • 增加了 Loan_Amount_Submitted_Missing 变量。如果Loan_Amount_Submitted变量的数据缺失,则这个参数的值为1。否则为0。删除了原先的Loan_Amount_Submitted变量。
  • 增加了 Loan_Tenure_Submitted_Missing 变量。如果 Loan_Tenure_Submitted 变量的数据缺失,则这个参数的值为1。否则为0。删除了原先的 Loan_Tenure_Submitted 变量。
  • 删除了LoggedIn, Salary_Account 两个变量
  • 增加了 Processing_Fee_Missing 变量。如果 Processing_Fee 变量的数据缺失,则这个参数的值为1。否则为0。删除了原先的 Processing_Fee 变量。
  • Source前两位不变,其它分成不同的类别。
  • 进行了离散化和独热编码(一位有效编码)。
    如果你有原始数据,可以从资源库里面下载data_preparation的Ipython notebook 文件,然后自己过一遍这些步骤。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值