0 i2 h! l F0 ]& _; Y, }9 ]4 y 2.基于生成基学习器! r1 q( Z$ `- x0 M/ N! r, b
* C# z! o) G7 O: }; E' ~. k, u
3.计算最优的 $ x, g$ N4 N' _6 K) n$ f! t, d& i. p1 D6 ^0 ]
, m9 v6 |( r; J0 R5 R3 H S
: D h. Y. p$ Z7 j/ t D
4.更新模型; b; B" }; c. x( d p U
; Y- g h: d% d* |9 J7 J
; p9 @& y7 F/ C! E! H2 O # [; ?& D8 f! J- c! |0 V( [1.2、Gradient boosting Decision Tree(GBDT) . _" o5 r( I9 b. a U8 w GBDT的原理篇在上一篇已经阐述过,这里稍微总结性下,GBDT是GB和DT的结合。要注意的是这里的决策树是分类回归树(是一种二叉树),GBDT中的决策树是个弱模型,有些GBDT的实现加入了随机抽样(subsample 0.5<=f <=0.8)提高模型的泛化能力。通过交叉验证的方法选择最优的参数。! i( A4 h. K+ r# [, t$ Z
f6 \! L* _# {: W% q. ?" \+ d$ `
因此GBDT实际的核心问题变成怎么基于使用CART回归树生成? 2 D M4 E0 n4 _+ H5 a! ^& c k4 ]2 h( W# Q+ J
2、Xgboost算法 ! J2 p) W: c2 d 前面已经说过,xgboost可以说集成思想达到顶峰的一个模型,至少目前是这样,所以我们学习机器学习算法, 掌握这个是很有必要的。顺带提一下,Xgboost目前scikit-learn中没有实现,需要我们自行安装Xgboost,可以通过python调用,我自己也记录了一个纯小白都能安装好的方法。2 I6 f- q9 V: j; B* u0 i G Y2 y
% `$ V7 P; ~2 Y# S0 k+ q. W
全称:eXtreme Gradient Boosting(极值梯度提升算法)6 D8 r6 r* o m. w
作者:陈天奇(华盛顿大学博士) ( j* e, T( t% J2 ~/ E
基础:GBDT 1 m" [1 d- K- H3 v) d
所属:boosting迭代型、树类算法。 0 a4 a! q% K1 s2 `适用范围:分类、回归等: @ T( Z# E* b' \' Q5 c
优点:速度快、效果好、能处理大规模数据、支持多种语言、支持自定义损失函数等等。 4 S7 A# ]; A5 w2.1、与GBDT的区别:; B( g3 K; ?0 x1 d1 y6 y8 j
首先我们先在大体上对xgboost有个大致的印象,然后我们在对其原理做详细的阐述。; K, M( a3 b( k$ J: V
$ d. X+ x. j% _9 b/ F • XGBoost的基学习器除了可以是CART(这个时候就是GBDT)也可以是线性分类器,而GBDT只能是CART。! n! G! ~' H, u, l' r# b1 U2 c- y7 F
• XGBoost在代价函数中加入了正则项,用于控制模型的复杂度(正则项的方式不同,如果你仔细点话,GBDT是一种类似于缩 减系数,而XGBoost类似于L2正则化项)。 7 e: R+ j/ c @# b* Q( Z9 F • XGBoost借鉴了随机森林的做法,支持特征抽样,不仅防止过拟合,还能减少计算 : @$ \" i! ^! g • XGBoost工具支持并行化 * w" m! s' q1 s5 j4 F+ V • 综合来说Xgboost的运算速度和算法精度都会优于GBDT% [( y8 J, V' j
0 H# f) n/ y; I3 a$ s, d
2.2 Xgboost算法原理 - K# Y& M3 U- ] Xgboost是GB算法的高效实现,xgboost中的基学习器除了可以是CART也可以是线性分类器(gblinear)。下面所有的内容来自原始paper,包括公式。 0 S: E* s! P) |* i" {2 I( t3 L, ~7 S: E0 F3 i6 \! ~
1)树的结构 ; i, J2 C7 Q7 w4 V8 P8 \+ I1 L, H ; B X6 C. y: q8 G. Y" y6 @ 我们从单一的树来考虑。对于其中每一棵回归树,其模型可以写成: 1 b0 ^3 e% }) A F2 p# v$ j9 g. f6 ]# i( X5 l$ ^# p0 X4 V
& y) F; x- {* U' s" h( }
; |; v' F! C+ p# m3 F% o% Q0 m 其中为叶子节点的得分值,表示样本对应的叶子节点。为该树的叶子节点个数。 3 R, \( C$ q+ G5 p6 w8 _! b3 x z8 Z1 _' e% R7 F( c9 ^( z 因此,在这里。我们将该树的复杂度写成:; _9 j& K5 l$ s5 S; W2 A6 R# r
6 I% J& T3 `' X" z
其中,γγ为L1L1正则的惩罚项,λλ为L2L2正则的惩罚项 1 ~6 s4 X" ?* a4 t7 S, ~ % l7 R' C, J7 Q 复杂度计算例子如下: I2 ]- H9 d& W2 F6 Q$ z) [, O+ ?; a" s( ?7 f$ b
^( F7 ]7 P. Y' \# {
# t* h' _/ K) m @+ ~& w9 k
2) 损失函数, [+ o- W6 a5 I; }6 y
9 i3 N0 u5 D0 `8 W* m) M5 d/ Q5 x
前面已经说过,为了一般性,实际中往往是基于loss Function 在函数空间的的负梯度学习,对于回归问题残差和负梯度也是相同的。和传统的boosting tree模型一样,xgboost的提升模型也是采用的残差(或梯度负方向),不同的是分裂结点选取的时候不一定是最小平方损失。 ) @3 P0 r. `" h* T* a! Y7 [, P
7 Y$ S6 _+ G' d' b; u( ^
3 d$ e: M: J& g. m4 ?$ R
* h* z* ^: @3 M8 t* |9 L
对目标函数的改写:+ A; l5 l& _2 S h
( U/ s2 G/ D9 a, }( c+ n1 n
( T% \' k# }% [6 i4 |# O* N3 g3 E6 b+ \ J* R! ?
最终的目标函数只依赖于每个数据点的在误差函数上的一阶导数和二阶导数。这么写的原因很明显,由于之前的目标函数求最优解的过程中只对平方损失函数时候方便求,对于其他的损失函数变得很复杂,通过二阶泰勒展开式的变换,这样求解其他损失函数变得可行了。& S% Z4 A) _; ?! b' _) y
+ c9 T& E; }5 k) O. W% d, k7 h 我相信到这里肯定都没有问题,接下来的理解是整个损失函数的难点,我自己开始学的时候想了一些时间,接下来我尽量用白话来叙述。 5 p" A% b5 ]8 h" `- R7 o + T0 [ {1 I% i1)对的理解:在上面我们已经说了,当一个样本进来的时候,不管是回归问题还是分类问题,你最终都会掉到叶子结点上,而每颗树的每个叶子节点都会对应有一个得分(想象一下回归问题,每个叶子节点对应的是落入该叶子结点的所有训练样本的均值),所以可以理解为一个样本在t轮最终的得分函数。; r. X* ]0 B9 k& k. O$ d
9 C/ {2 G: ~2 u. B8 l& K9 o8 ]2)对的理解:其实这个的理解,我最初钻了牛角尖,其实只要当我们的损失函数一旦确定下来(理解的前提),这个求导就和我们高数中的求导一回事啦,只不过表达式看起来很唬人。. M& M, [- K: r8 b- ~" X+ w
6 M2 ] G0 R# n2 Y: e
3)目标函数全部转换成在第t棵树叶子节点的形式。从求和符号我们可以看出,是在对每个样本求损失,我们在第一点就已经说了,第i个样本最终都会落到树的叶子结点中去的,只是不同的叶子节点,你会取不同的值罢了。那我们能不能讲对样本的损失转移到对叶子结点中再求损失呢(后话,这个就是这么做的), 可以看做是每个样本在第t棵树的叶子节点得分值相关函数的结果之和,所以我们也能从第t棵树的叶子节点上来表示。4 H- d% V1 c* |, _& b& O
, s$ U. R9 I4 r' `
" b% u, C" V5 O( z& X, L1 O
, ^0 l4 K5 {3 F+ ^% _
这里也在解释下,描述了一整颗树的模型,他当然能分解成每个叶子结点的集合啦,而刚好是每个叶子节点的得分函数,这两个于是就可以相互转化了。 7 ^+ {- r1 C5 B& I1 w2 H' s! D# ~; b6 f: c" P1 K+ U% a; Y
其中为第t棵树中总叶子节点的个数,表示样本落在第个叶子节点上,为第个叶子节点的得分值。 / @: r. q D5 W6 v4 p* Z6 c1 n 1 f2 ]. w; a) _! f1 N. D0 O- k在这里,令 8 f0 K5 t, _. K2 h3 L. z 9 I: f- x N. {) w* _5 J. g: G , G" X0 k' U" b3 [, T* f* M& @$ G& W+ z- _
对求偏导,并使其导函数等于0,则有: ; g+ x% w: p' q+ S% e6 w& |) b: _! u3 ]+ R( A V
" _4 A0 z& [9 o) B
0 c+ g( [" J9 h C. A % D9 d* ]) d3 T ; ~1 O: T/ j1 o' E$ {到此,损失函数的推导完成。 2 ?- d9 T2 O5 `- @6 |8 ~ 1 s% V. L# T; v8 [, C7 g3)树结构的打分函数: u( ^. r: i; k1 x
9 ^+ Q1 j' K8 g! J0 e; F, r
Obj代表了当指定一个树的结构的时候,在目标上面最多减少多少。结构分数(structure score) : z; [' |( V3 f * V! e! x$ M6 M4 J6 C ( e3 A/ E4 u$ I: P$ r1 s$ B7 ^6 C5 G
xgboost算法的步骤和GB基本相同,都是首先初始化为一个常数,gb是根据一阶导数ri,xgboost是根据一阶导数gi和二阶导数hi,迭代生成基学习器,相加更新学习器。 8 L3 D5 }* q5 h0 Q9 \8 e# R( f0 e$ j% t: l C: Q! E1 L
对于每一次尝试去对已有的叶子加入一个分割) T( e) i# V: }# g# I
4 D- Q( I+ `( ~4 X" R N3 V( |7 o1 p& F& R: P7 x' F2 I8 b/ k) p( ?
这样就可以在建树的过程中动态的选择是否要添加一个结点。 联想决策树中信息增益,这里的原理类似。这一步实质上是为了寻找分裂结点的候选集。 * Y ?* L0 t, t+ o$ D% }/ ]" ^% K! p- D
如何高效地枚举所有的分割呢?我假设我们要枚举所有x < a 这样的条件,对于某个特定的分割a我们要计算a左边和右边的导数和。 & }& N# }( Z3 M, K! \ 2 M, @, u: ~/ a: D% i + m7 ]$ H+ D4 D# Y * j2 a2 Y" \: T& `. @1 P我们可以发现对于所有的a,我们只要做一遍从左到右的扫描就可以枚举出所有分割的梯度和和。然后用上面的公式计算每个分割方案的分数就可以了。! c6 z e0 B8 p P" Y
! T2 y4 {3 x) t9 W. fxgboost算法伪代码如下:( ]" m3 e; S5 d: I
* ^/ v, q" f: Q) k" X/ d! c. d: J( A( l' |9 z' ]
: R7 T# P" Q( t8 ^% w# f f
3、Xgboost算法参数9 e4 f- h! [# C% h7 T+ K7 t
XGBoost的作者把所有的参数分成了三类:- p+ o x, I- h, @
$ R& l( u, L& I* d- Q9 W通用参数:宏观函数控制。% j6 C0 d I0 X% \( w+ a
Booster参数:控制每一步的booster(tree/regression)。 % R# F4 l0 g* z* G. D学习目标参数:控制训练目标的表现。 1 m s6 y6 M- c& @" ~3.1通用参数& Z: N' D m+ ~
这些参数用来控制XGBoost的宏观功能。( V& Z% v+ o0 @% O
0 C. \5 r5 b& s8 e2 v
1、booster[默认gbtree]0 o( Z. ?# D+ a
' T1 Z1 E/ t) l, y0 P8 {$ R
选择每次迭代的模型,有两种选择: ( h3 i/ m& K4 s I# R8 c" }' |
gbtree:基于树的模型 - Q5 b# `4 e1 Z4 T4 y1 K! u
gbliner:线性模型1 e) f% e/ w! B( T$ {5 W
2、silent[默认0] ! L; A& Z8 W0 V: C4 o, e0 Y: k+ |0 {
当这个参数值为1时,静默模式开启,不会输出任何信息。8 V$ ?$ ~; ?- H6 O, F) o$ f
一般这个参数就保持默认的0,因为这样能帮我们更好地理解模型。2 t) ^# s/ a* k+ |
3、nthread[默认值为最大可能的线程数]# p, n, E) p8 m& A( p
+ F4 r5 _& z+ W' v( z这个参数用来进行多线程控制,应当输入系统的核数。 $ ], \+ z5 k9 k. L( W如果你希望使用CPU全部的核,那就不要输入这个参数,算法会自动检测它。- G- H {7 ]9 W8 ^' {1 {% R1 z
还有两个参数,XGBoost会自动设置,目前你不用管它。接下来咱们一起看booster参数。4 h; P$ \. H& s! ^# `' T4 i- `
5 K8 y8 ], L+ i, v8 Y
3.2 booster参数$ B5 J& x6 W' b4 m
尽管有两种booster可供选择,我这里只介绍tree booster,因为它的表现远远胜过linear booster,所以linear booster很少用到。 * |: G6 W( X) J; c1 f9 K& J. } Z8 j. g6 S3 v* z$ p4 c6 G1、eta[默认0.3]( ~' O, c" [" _7 y: m$ f
) o& a0 Z1 O9 M. B: Y5 R和GBM中的 learning rate 参数类似。 : r: u# } U9 k* J2 R* d2 w通过减少每一步的权重,可以提高模型的鲁棒性。0 g( E- J( H; F, m7 k$ t
典型值为0.01-0.2。. T4 Y' U6 l: t4 v9 E1 B) p
2、min_child_weight[默认1]1 Q$ g: U/ B/ _* U( x6 X4 @: n5 ^- J
% m1 E% S0 W8 _: s" @
决定最小叶子节点样本权重和。6 I% E D% G* g" l; T
和GBM的 min_child_leaf 参数类似,但不完全一样。XGBoost的这个参数是最小样本权重的和,而GBM参数是最小样本总数。 * y! E/ ~+ `5 a7 x这个参数用于避免过拟合。当它的值较大时,可以避免模型学习到局部的特殊样本。 ( \! V& {4 T2 r但是如果这个值过高,会导致欠拟合。这个参数需要使用CV来调整。" q) |% f, V% I4 L1 O5 H6 V
3、max_depth[默认6]3 q$ \. Q3 n1 M0 _* [
$ l# |1 `8 T0 i' y& e9 k# }% G2 I7 m
和GBM中的参数相同,这个值为树的最大深度。9 M5 |: s o6 L) ~ K
这个值也是用来避免过拟合的。max_depth越大,模型会学到更具体更局部的样本。+ q3 y$ e& Z/ d% a
需要使用CV函数来进行调优。 5 V4 Z. l3 w" K! S( R, \典型值:3-10% h4 S/ ^: W# N g
4、max_leaf_nodes& c6 a. ]. y7 Y1 {0 S' C+ y