XGBoost 3 - XGBoost原理及调用

XGBoost原理

主要内容包括:

  • Boosting Boosting (提升算法)
    • AdaBoost AdaBoost (经典的提升算法)
  • Gradient Boosting Gradient Boosting (梯度提升)
  • XGBoost XGBoost (梯度提升的优化实现)

1 - Boosting

Boosting Boosting : 将弱学习器组合成强分类

  • 构造一个性能很高的强学习器是一件很困难的事情
  • 但构造一个性能一般的弱学习器并不难
  • 弱学习器:性能比随机猜测好(层数不深的 CART CART 是一个好选择)
G(x)=t=1Tαtϕt(x) G ( x ) = ∑ t = 1 T α t ϕ t ( x )

2 - AdaBoost

通过改变样本的权重得到不同的弱学习器 f(t) f ( t ) ,初始时每个样本的权重为 1N 1 N , 在得到一个弱分类器之后,计算该弱分类器的分类误差率 ϵt ϵ t ,由此为依据更新每个样本的权重 w(t)n w n ( t ) ,使得被误分类的样本点权重增大,正确分类的样本的权重减少,这样使得在下一轮的学习当中,误分样本能得到更多的关注,并由分类误差率 ϵt ϵ t 计算得到当前弱分类器在最终分类模型中的权重 αt α t

2.1 - AdaBoost M1算法

给定训练集合 {xn,yn} { x n , y n } , yn{1,1} y n ∈ { − 1 , 1 }

  • 初始训练集样本权重: w(t)1=1N w 1 ( t ) = 1 N
  • t=1,2,,T t = 1 , 2 , ⋯ , T
    • 训练弱分类器: ϕt(x) ϕ t ( x )
    • 计算分类误差:
      ϵt=Nn=1wtn1(ynϕt(xn))Nn=1wtn ϵ t = ∑ n = 1 N w n t 1 ( y n ≠ ϕ t ( x n ) ) ∑ n = 1 N w n t
    • 计算弱分类器的权重:
      αt=log(1ϵtϵt) α t = l o g ( 1 − ϵ t ϵ t )
    • 更新样本的权重:
      w(t+1)n=w(t)nexp(αtynϕt(xn)) w n ( t + 1 ) = w n ( t ) e x p ( − α t y n ϕ t ( x n ) )

最终得到强分类器:

G(x)=sign(t=1Tαtϕt(x)) G ( x ) = s i g n ( ∑ t = 1 T α t ϕ t ( x ) )

3 - Adaboost算法分析

Adaboost Adaboost 可以看成当前向分步算法的损失函数为指数损失函数时的加法模型

模型最终的目的是要找到一堆弱学习器 gt(x) g t ( x ) 的组合去逼近最优的 f f ,采用的方法是每次找一个弱分类器添加到已经集成的模型当中。与梯度下降算法的思路相似,无法直接得到最优解,而是一步一步的去逼近。

3.1 - 前向分步加法算法

  • 损失函数:L(f(x),y)

    • 目标函数:
      minf1Ni=1NL(f(xi),yi) m i n f 1 N ∑ i = 1 N L ( f ( x i ) , y i )
    • 前向逐步递增:
      • 初始化:
        f0(x)=argminf1Ni=1NL(f(xi),yi) f 0 ( x ) = a r g m i n f 1 N ∑ i = 1 N L ( f ( x i ) , y i )
      • 递增:
        (βt,ϕt)=argminβ,ϕ1Ni=1NL(ft1(xi)+βtϕt(xi),yi) ( β t , ϕ t ) = a r g m i n β , ϕ 1 N ∑ i = 1 N L ( f t − 1 ( x i ) + β t ϕ t ( x i ) , y i )

        ft(x)=ft1(x)+βtϕt(x) f t ( x ) = f t − 1 ( x ) + β t ϕ t ( x )
    • 3.2 - 前向分步算法与Adaboost

      Adaboost Adaboost 可以看成当前向分步算法的损失函数为指数损失函数时的加法模型。

      证明如下:

      L(f(x),y)=exp(yf(x)) L ( f ( x ) , y ) = e x p ( − y f ( x ) )
      在第 t t 步:
      (1)(βt,ϕt(x))=argminβ,ϕi=1Nexp(yi(ft1(xi)+βϕ(xi)))(2)=argminβ,ϕi=1Nexp(yi(ft1(xi))exp(yiβϕ(xi))(3)=argminβ,ϕi=1Nw¯i(t)exp(yiβϕ(xi))(4)=argminβ,ϕϕ(xi)=yiw¯i(t)eβ+ϕ(xi)yiw¯i(t)eβ(5)=argminβ,ϕϕ(xi)=yiw¯i(t)eβ+ϕ(xi)yiw¯i(t)eβ+ϕ(xi)yiw¯i(t)eβϕ(xi)yiw¯i(t)eβ(6)=argminβ,ϕeβi=1Nw¯i(t)+(eβeβ)ϕ(xi)yiw¯i(t)(1)=argminβ,ϕeβi=1Nw¯i(t)+(eβeβ)i=1Nw¯i(t)I(yiϕ(xi))
      其中令:
      w¯(t)i=exp(yi(ft1(xi)) w ¯ i ( t ) = e x p ( − y i ( f t − 1 ( x i ) )
      因为 w¯(t)i w ¯ i ( t ) 既不依赖于 β β 也不依赖于 ϕ ϕ ,所以与最优化无关。 所以能够使得 (1) ( 1 ) 最小化的 ϕ ϕ 如下:
      ϕt(x)=argminϕi=1Nw¯(t)iI(yiϕ(xi))(*) (*) ϕ t ( x ) = a r g m i n ϕ ∑ i = 1 N w ¯ i ( t ) I ( y i ≠ ϕ ( x i ) )
      接下来求解最佳的 β β 为了求解能够使得 (1) ( 1 ) 最小的 β β ,我们首先对 β β 求偏导:
      Lβ=eβi=1Nw¯(t)i+eβi=1Nw¯(t)iI(yiϕ(xi))+eβi=1Nw¯(t)iI(yiϕ(xi))(7) (7) ∂ L ∂ β = − e − β ∑ i = 1 N w ¯ i ( t ) + e β ∑ i = 1 N w ¯ i ( t ) I ( y i ≠ ϕ ( x i ) ) + e − β ∑ i = 1 N w ¯ i ( t ) I ( y i ≠ ϕ ( x i ) )
      Lβ=0 ∂ L ∂ β = 0 得到:
      eβi=1Nw¯(t)iI(yiϕ(xi))=eβ(i=1Nw¯(t)ii=1Nw¯(t)iI(yiϕ(xi))) e β ∑ i = 1 N w ¯ i ( t ) I ( y i ≠ ϕ ( x i ) ) = e − β ( ∑ i = 1 N w ¯ i ( t ) − ∑ i = 1 N w ¯ i ( t ) I ( y i ≠ ϕ ( x i ) ) )
      log(eβ)+log(i=1Nw¯(t)iI(yiϕ(xi)))=log(eβ)+log((i=1Nw¯(t)ii=1Nw¯(t)iI(yiϕ(xi)))) l o g ( e β ) + l o g ( ∑ i = 1 N w ¯ i ( t ) I ( y i ≠ ϕ ( x i ) ) ) = l o g ( e − β ) + l o g ( ( ∑ i = 1 N w ¯ i ( t ) − ∑ i = 1 N w ¯ i ( t ) I ( y i ≠ ϕ ( x i ) ) ) )
      两边取 log l o g
      logeβ=12logNi=1w¯(t)iNi=1w¯(t)iI(yiϕ(xi))logNi=1w¯(t)iI(yiϕ(xi)) l o g e β = 1 2 l o g ∑ i = 1 N w ¯ i ( t ) − ∑ i = 1 N w ¯ i ( t ) I ( y i ≠ ϕ ( x i ) ) l o g ∑ i = 1 N w ¯ i ( t ) I ( y i ≠ ϕ ( x i ) )
      βt=12logNi=1w¯(t)iNi=1w¯(t)iI(yiϕ(xi))logNi=1w¯(t)iI(yiϕ(xi)) β t = 1 2 l o g ∑ i = 1 N w ¯ i ( t ) − ∑ i = 1 N w ¯ i ( t ) I ( y i ≠ ϕ ( x i ) ) l o g ∑ i = 1 N w ¯ i ( t ) I ( y i ≠ ϕ ( x i ) )
      因为:
      ϵt=Ni=1w¯(t)iI(yiϕ(xi))Ni=1w¯(t)i ϵ t = ∑ i = 1 N w ¯ i ( t ) I ( y i ≠ ϕ ( x i ) ) ∑ i = 1 N w ¯ i ( t )
      得到
      βt=12log1ϵtϵt(*) (*) β t = 1 2 l o g 1 − ϵ t ϵ t
      现在已经求出了最佳的 βt β t ϕt(x) ϕ t ( x ) ,所以:
      ft(x)=ft1(x)+βtϕt(x) f t ( x ) = f t − 1 ( x ) + β t ϕ t ( x )
      以及
      w¯(t)i=exp(yi(ft1(xi)) w ¯ i ( t ) = e x p ( − y i ( f t − 1 ( x i ) )

      w¯(t+1)i=exp(yi(ft1(x)+βtϕt(x))=w¯(t)iexp(yiβtϕt(x)) w ¯ i ( t + 1 ) = e x p ( − y i ( f t − 1 ( x ) + β t ϕ t ( x ) ) = w ¯ i ( t ) e x p ( − y i β t ϕ t ( x ) )

      得到了 Adaboost Adaboost 算法中的样本权重的更新规则。所以现在可以证得, Adaboost Adaboost 算法为前向分步加法算法损失函数为指数损失时候的特例。

      因为指数损失对outliers比较敏感 ,因此另一种选择的损失函数为 负log似然损失(交叉熵损失/logistic损失) ,这时会得到logitBoost。另外对于回归问题,损失函数可以取为L2损失(平方误差损失) ,此时得到的是L2Boosting

      3.3 - 提升树用于回归

      当损失函数为 L2 L 2 损失的时候:

      L(f(x),y)=(f(x)y)2 L ( f ( x ) , y ) = ( f ( x ) − y ) 2

      • 初始化为: f0(x)=y¯ f 0 ( x ) = y ¯

      • 在第 t t 步的时候:

      (18)argminβ,ϕL(ft(x),y)=argminβ,ϕL(ft1(x)+βϕ(x),y)(19)=argminβ,ϕ(ft1(x)+βϕ(x)y)2(20)=argminβ,ϕ((yft1(x))βϕ(x))2(21)=argminβ,ϕ(rβϕ(x))2

      因此每一轮是使用弱分类器来拟合残差 yft1(x) y − f t − 1 ( x )

      提升树利用加法模型与前向分步计算法实现了学习的优化过程,当损失函数为指数损失和平方误差损失的时候,每一步的优化是简单的。但是对于一般的损失函数来说,往往比较复杂,所以出现了梯度提升算法。其关键是利用损失函数的负梯度在当前模型的值作为残差的近似值。

      4 - GBDT

      Boosting Tree Boosting Tree (提升树)适合于损失函数为平方损失(拟合残差)或者指数损失( Adaboost Adaboost 的弱学习器限制为受限的决策树桩)。而 Gradient Boosting Gradient Boosting 适合各类损失函数。

      对于 GBDT GBDT ,其学习流程与 boosting tree boosting tree 相似,只是不再使用残差作为新的训练数据而是使用损失函数的梯度作为新的训练数据的 y y 值,具体的来说就是使用损失函数L(f(x),y) f(x) f ( x ) 求梯度然后带入 fm1(x) f m − 1 ( x ) 作为新的 y y 值,即利用损失函数的负梯度在当前模型的值作为回归问题提升树中残差的近似值来拟合一棵回归树:

      [L(y,f(xi))f(xi)]f(x)=ft1(x)

      提升树模型每一次的提升都是靠上次的预测结果与训练数据的 y y 值差值作为新的训练数据进行重新训练,GDBT则是将残差计算替换成了损失函数的梯度方向,将上一次的预测结果带入梯度中求出本轮的训练数据,这两种模型就是在生成新的训练数据时采用了不同的方法。

      5 - XGBoost

      gradient boost gradient boost 的优化实现

      • 可自定义损失函数
      • 正则项:叶子节点的数目,叶子节点的分数( GBDT GBDT 中没有正则项)
      • 建树和剪枝
        • 支持分裂点近似搜索
        • 系数特征处理
        • 缺失值处理
      • 特征重要性和特征选择
      • 并行,缓存

      gradient boost gradient boost 算法虽然对常见损失函数适用,但除了 L2 L 2 损失函数,其他损失函数推导还是比较复杂。

      5.1 - xgboost中的损失函数

      XGBoost XGBoost 对损失函数用二阶Taylor展开来近似。

      f(x+Δx)=f(x)+f(x)Δx+12f′′(x)Δx2 f ( x + Δ x ) = f ( x ) + f ′ ( x ) Δ x + 1 2 f ″ ( x ) Δ x 2
      在第 t t 步,令
      gt,i=[L(f(xi),yi)f(xi)]f=ft1
      ht,i=[2L(f(xi),yi)2f(xi)]f=ft1 h t , i = [ ∂ 2 L ( f ( x i ) , y i ) ∂ 2 f ( x i ) ] f = f t − 1
      这样可以得到:
      L(ft1(xi)+ϕ(xi),yi)=L(ft1(xi),yi)+gt,iϕ(xi)+12ht,iϕ(xi)2 L ( f t − 1 ( x i ) + ϕ ( x i ) , y i ) = L ( f t − 1 ( x i ) , y i ) + g t , i ϕ ( x i ) + 1 2 h t , i ϕ ( x i ) 2
      去掉与 ϕ(xi) ϕ ( x i ) 无关的量

      L(ft1(xi)+ϕ(xi),yi)=gt,iϕ(xi)+12ht,iϕ(xi)2 L ( f t − 1 ( x i ) + ϕ ( x i ) , y i ) = g t , i ϕ ( x i ) + 1 2 h t , i ϕ ( x i ) 2

      实例:对于L2损失:

      L(f(x),y)=12(f(x)y)2 L ( f ( x ) , y ) = 1 2 ( f ( x ) − y ) 2
      L(f(x),y)f(x)=f(x)y ∂ L ( f ( x ) , y ) ∂ f ( x ) = f ( x ) − y
      2L(f(x),y)2f(x)=1 ∂ 2 L ( f ( x ) , y ) ∂ 2 f ( x ) = 1
      所以可以得到:
      gt,i=ft1(xi)yi g t , i = f t − 1 ( x i ) − y i
      ht,i=1 h t , i = 1

      5.2 - xgboost中的树的定义

      重新对树进行了定义,将树拆成了结构部分 q q 和叶子分数部分w

      ϕ(x)=wq(x) ϕ ( x ) = w q ( x )

      • 结构函数 q q :把输入映射到叶子的索引号
      • 分数函数w:把叶子索引号映射到叶子分数

      5.3 - 树的复杂度的定义

      模型的复杂度作为正则项:(不是唯一的定义方式,可视具体的问题而定)

      Ω(ϕ(x))=γT+12λt=1Tw2t Ω ( ϕ ( x ) ) = γ T + 1 2 λ ∑ t = 1 T w t 2

      其中第一项叶子结点的数目 T T 相当于L1正则,第二项叶子节点的分数相当于 L2 L 2 正则。

      5.4 - 目标函数

      这里对以下要用到的符号进行一下说明:

      • gm,i,hm,i g m , i , h m , i 为损失函数第 m m 轮在第i个样本上的一阶导数和二阶导数, m=1,,M m = 1 , ⋯ , M , M M 为弱分类器的个数,i=1,,N N N 为样本的总数
      • T为叶子节点的总数
      • 令每一个叶子 t t 上的样本集合为It={i|q(xi)=t}
      J(θ)=i=1NL(fm(xi),yi)+Ω(θ)=i=1Ngm,iϕ(xi)+12hm,iϕ(xi)2+γT+12λt=1Tw2t=i=1Ngm,iwq(xi)+12hm,iw2q(xi)+γT+12λt=1Tw2t=t=1T[iItgm,iwt+12iIthm,iw2t+12λw2t]+γT=t=1T[iItgm,iwt+12(iIthm,i+λ)w2t]+γT=t=1T[Gtwt+12(Ht+λ)w2t]+γT(12)(13)(14)(15)(16)(17) (12) J ( θ ) = ∑ i = 1 N L ( f m ( x i ) , y i ) + Ω ( θ ) (13) = ∑ i = 1 N g m , i ϕ ( x i ) + 1 2 h m , i ϕ ( x i ) 2 + γ T + 1 2 λ ∑ t = 1 T w t 2 (14) = ∑ i = 1 N g m , i w q ( x i ) + 1 2 h m , i w q ( x i ) 2 + γ T + 1 2 λ ∑ t = 1 T w t 2 (15) = ∑ t = 1 T [ ∑ i ∈ I t g m , i w t + 1 2 ∑ i ∈ I t h m , i w t 2 + 1 2 λ w t 2 ] + γ T (16) = ∑ t = 1 T [ ∑ i ∈ I t g m , i w t + 1 2 ( ∑ i ∈ I t h m , i + λ ) w t 2 ] + γ T (17) = ∑ t = 1 T [ G t w t + 1 2 ( H t + λ ) w t 2 ] + γ T
      J(θ)=t=1T[Gtwt+12(Ht+λ)w2t]+γT(1) (1) J ( θ ) = ∑ t = 1 T [ G t w t + 1 2 ( H t + λ ) w t 2 ] + γ T
      如果树的结构 q q 已经知道的话,可以通过对(1)求偏导得出最佳的 w w ,也就是叶子节点的分数。

      J(θ)wt=Gt+(Ht+λ)wt=0

      得到 每一个叶子最佳的分数 w w 为:

      w:wt=GtHt+λ

      将求得的 w w 带入目标函数J(θ),可视为树的分数:

      J(θ)=t=1T[GtGtHt+λ+12(Ht+λ)(GtHt+λ)2]+γT J ( θ ) = ∑ t = 1 T [ − G t G t H t + λ + 1 2 ( H t + λ ) ( − G t H t + λ ) 2 ] + γ T

      J(θ)=12t=1T[G2tHt+λ]+γT(2) (2) J ( θ ) = − 1 2 ∑ t = 1 T [ G t 2 H t + λ ] + γ T


      这里写图片描述

      现在我们同样想要最小化 J(θ) J ( θ )

      现在的问题是,什么样的树的结构可以使得 J(θ) J ( θ ) 最小呢?

      5.6 - 建树

      理论上,需要枚举所有可能的树的结构,根据 (2) ( 2 ) 计算结构的分数,选择分数最小的结构。

      实践中,我们贪婪的增加树的叶子结点的数目:

      • 从深度为0的树开始(所有的样本都在一个节点上)
      • 对于树的每一个叶子节点,尝试增加一个分裂点:

        • IL,IR I L , I R 分别表示加入分裂点之后左右叶子结点的样本集合
          • GL=iILgm,i G L = ∑ i ∈ I L g m , i
          • GR=iIRgm,i G R = ∑ i ∈ I R g m , i
          • HL=iILhm,i H L = ∑ i ∈ I L h m , i
          • HR=iIRhm,i H R = ∑ i ∈ I R h m , i
        • 则增加分裂点之后目标函数的变化为

          Gain=(G2L+G2RHL+HR+λ+Tm1γ)((G2LHL+λ+G2RHR+λ)+(Tm1+1)γ) Gain = ( − G L 2 + G R 2 H L + H R + λ + T m − 1 γ ) − ( − ( G L 2 H L + λ + G R 2 H R + λ ) + ( T m − 1 + 1 ) γ )

          Gain=G2LHL+λ+G2RHR+λG2L+G2RHL+HR+λγ Gain = G L 2 H L + λ + G R 2 H R + λ − G L 2 + G R 2 H L + H R + λ − γ

      如何找最佳的分裂点?

      5.6.1 - 建树,精确搜索算法
      • 对每一个节点,穷举所有的特征(没有特征消耗),对每一个特征,穷举所有的分裂点
        • 对每个特征,通过特征的取值将实例进行排序
        • 寻求该特征的最优分裂点
        • 对所有的特征采用如下的操作

      深度为k的树的时间复杂度:对特征所有取值的排序为 NlogN N l o g N ,N为样本点数目,若有D维特征,则 kDNlogN k D N l o g N


      这里写图片描述

      5.6.2 - 建树,近似搜索算法

      当数据太多不能装载到内存时,不能进行精确搜索分裂,只能近似搜索

      • 根据特征分布的百分位数,提出特征的一些候选分裂点
      • 将连续特征值映射到桶里(候选点对应的分裂),然后根据桶里样本的统计量,从这些候选中选择最佳分裂点

      根据候选提出的时间,分为

      • 全局近似:在构造树的初始阶段提出所有的候选分裂点,然后对各个层次采用相同的候选
        • 提出候选的次数少,但每次的候选数目多(因为候选不更新)
      • 局部近似:在每次分裂都重新提出候选,
        • 对层次较深的树更适合,候选分裂点的数目不需要太多


      这里写图片描述

      5.6.3 - 建树,稀疏特征和缺失值

      在实际任务中,极有可能遇到稀疏特征

      • 缺失数据
      • 人工设计的特征:如one-hot编码

      XGBoost XGBoost :在树的每个结点设置一个缺省方向


      这里写图片描述

      5.7 - 剪枝

      分裂的增益

      Gain=G2LHL+λ+G2RHR+λG2L+G2RHL+HR+λγ Gain = G L 2 H L + λ + G R 2 H R + λ − G L 2 + G R 2 H L + H R + λ − γ

      提前终止

      • 如果出现负值,提前停止( scikit-learn scikit-learn 中采用的策略)
      • 但被提前终止掉的分裂可能其后续的分裂会带来好处

      但是在 XGBoost XGBoost 中采用的是过后剪枝策略:将树分裂到最大深度,然后再基于上述增益计算剪枝。在实现时还有学习率/收缩因子,给后续轮留机会,进一步防止。

      6 - sklearn参数设置

      xgboost.XGBClassifier(max_depth=3, learning_rate=0.1, n_estimators=100,silent=True, objective=‘binary:logistic’, nthread=-1, gamma=0,min_child_weight=1, max_delta_step=0, subsample=1, colsample_bytree=1,colsample_bylevel=1, reg_alpha=0, reg_lambda=1, scale_pos_weight=1,base_score=0.5, random_state=0, seed=None, missing=None,**kwargs)
      • max_depth max_depth 树的最大深度。越大通常模型复杂,更容易过拟合,这里作为弱学习器一般设置为1-10
      • learning_rate learning_rate 学习率或收缩因子。学习率和迭代次数/弱分类器数目n_estimators相关。 缺省:0.1 (与直接调用xgboost的eta参数含义相同)
      • n_estimators n_estimators 弱分类器数目. 缺省:100
      • objective objective 待优化的目标函数,常用值有:
        • binary:logistic binary:logistic 二分类的逻辑回归,返回预测的概率
        • multi:softmax multi:softmax 使用softmax的多分类器,返回预测的类别(不是概率)。
        • multi:softprob multi:softprob 和multi:softmax参数一样,但是返回的是每个数据属于各个类别的概率。
        • 支持用户自定义目标函数
      • booster booster :选择每次迭代的模型,有两种选择:
        • gbtree gbtree :基于树的模型,为缺省值。
        • gbliner gbliner :线性模型
      • gamma gamma :节点分裂所需的最小损失函数下降值,缺省0
      • min_child_weight min_child_weight :叶子结点需要的最小样本权重( hessian hessian )和
      • subsample subsample :构造每棵树的所用样本比例(样本采样比例)
      • colsample_bytree colsample_bytree :构造每棵树的所用特征比例
      • colsample_bylevel colsample_bylevel :树在每层每个分裂的所用特征比例
      • reg_alpha reg_alpha L1 L 1 正则的惩罚系数
      • reg_lambda reg_lambda L2 L 2 正则的惩罚系数
      • scale_pos_weight scale_pos_weight :正负样本的平衡,通常用于不均衡数据
      • slient slient :参数值为1时,静默模式开启,不输出任何信息
      • nthread nthread :用来进行多线程控制。 如果你希望使用CPU全部的核,那就用缺省值-1,算法会自动检测它。
      • max_delta_step max_delta_step :允许的树的最大权重

      7 -xgboost的其他功能

      7.1 - 特征重要性

      采用树集成学习(如 Gradient Boosting Gradient Boosting )的好处之一是可以从训练好的预测模型得到特征重要性

      • 单棵树中的特征重要性:每个分裂点对性能的提升量,并用每个结点的样本数加权。
        • 性能测量可以是用于选择分裂点的指标(纯度)或其他更特别的误差函数
      • 整个模型中的特征重要性:模型中每棵树的平均

      XGBoost XGBoost 中已经自动算好,存放在 feature_importances feature_importances

      from matplotlib import pyplot
      pyplot.bar(range(len(model_XGB.feature_importances_)), model_XGB.feature_importances_)
      pyplot.show()

      还可以使用 XGBoost XGBoost 内嵌的函数,按特征重要性排序

      from xgboost import plot_importance
      plot_importance(model_XGB)
      pyplot.show()

      7.2 - 特征选择

      以根据特征重要性进行特征选择

      from sklearn.feature_selection import SelectFromModel

      输入一个(在全部数据集上)训练好的模型和给定阈值,重要性大于阈值的特征被选中

      selection = SelectFromModel(model, threshold=thresh, prefit=True)
      select_X_train = selection.transform(X_train)

      8 - 实战

      加载必要的包和数据

      from xgboost import XGBClassifier
      import pandas as pd
      from sklearn.preprocessing import LabelEncoder
      from sklearn.cross_validation import train_test_split
      import numpy as np
      from sklearn.metrics import accuracy_score
      import matplotlib.pyplot as plt
      data = pd.read_csv("./data/mushrooms.csv")

      查看数据的形状和属性名。

      print(data.shape)
      print(data.columns)
      (8124, 23)
      Index(['class', 'cap-shape', 'cap-surface', 'cap-color', 'bruises', 'odor',
             'gill-attachment', 'gill-spacing', 'gill-size', 'gill-color',
             'stalk-shape', 'stalk-root', 'stalk-surface-above-ring',
             'stalk-surface-below-ring', 'stalk-color-above-ring',
             'stalk-color-below-ring', 'veil-type', 'veil-color', 'ring-number',
             'ring-type', 'spore-print-color', 'population', 'habitat'],
            dtype='object')
      

      查看是否有空值

      print(data.isnull().sum())
      class                       0
      cap-shape                   0
      cap-surface                 0
      cap-color                   0
      bruises                     0
      odor                        0
      gill-attachment             0
      gill-spacing                0
      gill-size                   0
      gill-color                  0
      stalk-shape                 0
      stalk-root                  0
      stalk-surface-above-ring    0
      stalk-surface-below-ring    0
      stalk-color-above-ring      0
      stalk-color-below-ring      0
      veil-type                   0
      veil-color                  0
      ring-number                 0
      ring-type                   0
      spore-print-color           0
      population                  0
      habitat                     0
      dtype: int64
      

      查看 target value target value 的取值

      print(data["class"].unique())
      ['p' 'e']
      

      查看特征的数据类型

      print(data.dtypes)
      class                       object
      cap-shape                   object
      cap-surface                 object
      cap-color                   object
      bruises                     object
      odor                        object
      gill-attachment             object
      gill-spacing                object
      gill-size                   object
      gill-color                  object
      stalk-shape                 object
      stalk-root                  object
      stalk-surface-above-ring    object
      stalk-surface-below-ring    object
      stalk-color-above-ring      object
      stalk-color-below-ring      object
      veil-type                   object
      veil-color                  object
      ring-number                 object
      ring-type                   object
      spore-print-color           object
      population                  object
      habitat                     object
      dtype: object
      

      进行编码

      labelencoder = LabelEncoder()
      for col in data.columns:
          data[col] = labelencoder.fit_transform(data[col])
      data.head(5)

      得到 X X y

      X = data.iloc[:,1:23]
      y = data.iloc[:,0]
      print(X.shape)
      print(y.shape)
      (8124, 22)
      (8124,)
      

      划分训练集和测试集

      X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
      print(X_train.shape)
      print(y_train.shape)
      print(X_test.shape)
      print(y_test.shape)
      (6499, 22)
      (6499,)
      (1625, 22)
      (1625,)
      

      使用默认配置的 XGBClassifier XGBClassifier 并训练

      xgb = XGBClassifier()
      xgb.fit(X_train, y_train)
      XGBClassifier(base_score=0.5, booster='gbtree', colsample_bylevel=1,
             colsample_bytree=1, gamma=0, learning_rate=0.1, max_delta_step=0,
             max_depth=3, min_child_weight=1, missing=None, n_estimators=100,
             n_jobs=1, nthread=None, objective='binary:logistic', random_state=0,
             reg_alpha=0, reg_lambda=1, scale_pos_weight=1, seed=None,
             silent=True, subsample=1)
      

      在测试集上的表现

      pred_test = xgb.predict(X_test)
      pred_test = np.where(pred_test > 0.5, 1, 0)
      print("Test Accuracy: " + str(accuracy_score(y_test, pred_test)))
      Test Accuracy: 1.0
      

      查看特征重要性

      print(xgb.feature_importances_)
      [0.00638298 0.00425532 0.00638298 0.         0.35531914 0.
       0.05106383 0.04255319 0.05319149 0.02340426 0.04680851 0.03617021
       0.04680851 0.00851064 0.01702128 0.         0.         0.04680851
       0.         0.15531915 0.07659575 0.02340426]
      
      plt.bar(range(len(xgb.feature_importances_)), xgb.feature_importances_)
      plt.show()


      这里写图片描述

      from xgboost import plot_importance
      plot_importance(xgb)
      plt.show()


      这里写图片描述

      进行特征选择

      thresholds = sorted(xgb.feature_importances_)
      for thresh in thresholds:
          selection = SelectFromModel(xgb, threshold=thresh, prefit=True)
          select_X_train = selection.transform(X_train)
          xgb_select = XGBClassifier()
          xgb_select.fit(select_X_train, y_train)
          select_X_test = selection.transform(X_test)
          pred = xgb_select.predict(select_X_test)
          pred = np.where(pred>0.5, 1, 0)
          print("thresh:%f, features size:%d, accuracy:%.3f" % (thresh, select_X_train.shape[1], accuracy_score(pred, y_test)))
      thresh:0.000000, features size:22, accuracy:1.000
      thresh:0.000000, features size:22, accuracy:1.000
      thresh:0.000000, features size:22, accuracy:1.000
      thresh:0.000000, features size:22, accuracy:1.000
      thresh:0.000000, features size:22, accuracy:1.000
      thresh:0.004255, features size:17, accuracy:1.000
      thresh:0.006383, features size:16, accuracy:1.000
      thresh:0.006383, features size:16, accuracy:1.000
      thresh:0.008511, features size:14, accuracy:1.000
      thresh:0.017021, features size:13, accuracy:1.000
      thresh:0.023404, features size:12, accuracy:1.000
      thresh:0.023404, features size:12, accuracy:1.000
      thresh:0.036170, features size:10, accuracy:1.000
      thresh:0.042553, features size:9, accuracy:1.000
      thresh:0.046809, features size:8, accuracy:1.000
      thresh:0.046809, features size:8, accuracy:1.000
      thresh:0.046809, features size:8, accuracy:1.000
      thresh:0.051064, features size:5, accuracy:0.993
      thresh:0.053191, features size:4, accuracy:0.993
      thresh:0.076596, features size:3, accuracy:0.993
      thresh:0.155319, features size:2, accuracy:0.993
      thresh:0.355319, features size:1, accuracy:0.985
      

      参考资料

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值