2 K# \% { }, ?$ O 因此,在这里。我们将该树的复杂度写成: # ~ [* O1 v6 ~5 k) G$ ?' p/ ^ ) t0 X& A& q8 k, C5 d, Z 其中,γγ为L1L1正则的惩罚项,λλ为L2L2正则的惩罚项1 k7 @7 {, e; j5 M C. F% _
0 k& [8 B& S: G6 Y7 N4 A" f2 b
复杂度计算例子如下: 2 e$ |6 x8 q7 {9 c ) q* `3 ?8 I( H% X, O5 D& g z4 x$ s' {: }! v
& w+ L4 A( \+ s' [+ Y
2) 损失函数 ' {' @! P0 _6 j( A+ k5 a8 | ?+ K% ^% v& {( ~
前面已经说过,为了一般性,实际中往往是基于loss Function 在函数空间的的负梯度学习,对于回归问题残差和负梯度也是相同的。和传统的boosting tree模型一样,xgboost的提升模型也是采用的残差(或梯度负方向),不同的是分裂结点选取的时候不一定是最小平方损失。 " W T5 R0 n5 V2 `' ?9 O7 p$ H9 L( U% w. p
4 Z+ f0 @8 |7 g; O 8 J3 F& M" W: ] h$ q对目标函数的改写:0 [/ ~8 L# {8 [; e2 d
$ G1 T9 u8 |) d2 t
, w* G- x& E6 ?# W% D5 _: `
# Q# v' K e8 } @) `6 c' r n4 |& G# u
最终的目标函数只依赖于每个数据点的在误差函数上的一阶导数和二阶导数。这么写的原因很明显,由于之前的目标函数求最优解的过程中只对平方损失函数时候方便求,对于其他的损失函数变得很复杂,通过二阶泰勒展开式的变换,这样求解其他损失函数变得可行了。 $ ^ J. U# k7 h* T% `, W, q7 h+ W* W5 u2 E9 w" Z, w4 e! h
我相信到这里肯定都没有问题,接下来的理解是整个损失函数的难点,我自己开始学的时候想了一些时间,接下来我尽量用白话来叙述。 ( i4 ]" @( {" v) P9 n& c' N% I 1 J5 k* G6 L6 D9 f1)对的理解:在上面我们已经说了,当一个样本进来的时候,不管是回归问题还是分类问题,你最终都会掉到叶子结点上,而每颗树的每个叶子节点都会对应有一个得分(想象一下回归问题,每个叶子节点对应的是落入该叶子结点的所有训练样本的均值),所以可以理解为一个样本在t轮最终的得分函数。1 s" ]' B7 O x8 x; {3 _7 W9 F0 L
! H0 @; u( V6 c4 o
2)对的理解:其实这个的理解,我最初钻了牛角尖,其实只要当我们的损失函数一旦确定下来(理解的前提),这个求导就和我们高数中的求导一回事啦,只不过表达式看起来很唬人。 h' I5 H4 w0 O3 Y) d/ J: v/ ]' ]# L
3)目标函数全部转换成在第t棵树叶子节点的形式。从求和符号我们可以看出,是在对每个样本求损失,我们在第一点就已经说了,第i个样本最终都会落到树的叶子结点中去的,只是不同的叶子节点,你会取不同的值罢了。那我们能不能讲对样本的损失转移到对叶子结点中再求损失呢(后话,这个就是这么做的), 可以看做是每个样本在第t棵树的叶子节点得分值相关函数的结果之和,所以我们也能从第t棵树的叶子节点上来表示。8 M1 Q2 B3 t! ~$ l6 Q
- j+ h% [ A' ~5 }, A/ b: [ ! N; x( q" N$ z9 B! { 2 J- Q+ H: y3 J" Y 这里也在解释下,描述了一整颗树的模型,他当然能分解成每个叶子结点的集合啦,而刚好是每个叶子节点的得分函数,这两个于是就可以相互转化了。 7 c* u" y9 V0 T) W0 q/ Z/ }" ~1 [0 t7 f
其中为第t棵树中总叶子节点的个数,表示样本落在第个叶子节点上,为第个叶子节点的得分值。' y8 u) T q) r' b( \2 |
% @ y: _! b$ w* N: `! Y6 s; y
在这里,令 . [" s# G8 D4 i8 W5 e; o 3 W% E% S' A* H* n; }7 D1 M ' x+ X3 \( [( H- F' v. Q+ Q# N: q9 Z% K9 v- C* Q
对求偏导,并使其导函数等于0,则有: $ d1 O' t( u1 b' L V D+ m9 W ' n! U' X- O, w# k& L5 O0 x( c 9 I8 ?9 c6 f- r) \ 6 K z \ d/ k! V Q/ C% ` * x1 |4 s$ M; t% K3 T2 f: _0 s+ @3 X8 n( q% n4 p5 n" ~/ n
到此,损失函数的推导完成。, e7 W/ {) _9 a0 P& w4 O: ?0 d6 d
/ R) P* o% S+ r/ A5 J& u$ C3 A
3)树结构的打分函数 9 T) K* K6 p) z0 k! } , l/ s |# |8 j; b3 F9 P Obj代表了当指定一个树的结构的时候,在目标上面最多减少多少。结构分数(structure score) 2 { o) F) _! Q4 _" D % X ]6 P7 J, e- i# z% v 5 e3 x: l" N# c2 q* W! H( c6 T" _- z# b6 e' y
xgboost算法的步骤和GB基本相同,都是首先初始化为一个常数,gb是根据一阶导数ri,xgboost是根据一阶导数gi和二阶导数hi,迭代生成基学习器,相加更新学习器。 0 |1 j8 m9 x0 K% T* s : H/ \0 ]: B4 g% ]对于每一次尝试去对已有的叶子加入一个分割 0 Z4 ^: J# w8 y0 h d$ G. y' c. y5 ?! k4 ], q6 F
8 v# S! e+ N E* n- [; a4 t8 |1 _% g* ]6 D
这样就可以在建树的过程中动态的选择是否要添加一个结点。 联想决策树中信息增益,这里的原理类似。这一步实质上是为了寻找分裂结点的候选集。 , C0 Z( w5 w: ]+ L' `2 b# Y 7 D. U' C* o, \4 M 如何高效地枚举所有的分割呢?我假设我们要枚举所有x < a 这样的条件,对于某个特定的分割a我们要计算a左边和右边的导数和。0 c( J5 _8 [ D& i, D1 P. s# g. ?
0 A1 g ^8 Q0 H, A) n' o2 y) q4 a " J7 s3 k, m/ y6 Q% ~ $ |* Y+ w% z% }, }6 A) {/ ]我们可以发现对于所有的a,我们只要做一遍从左到右的扫描就可以枚举出所有分割的梯度和和。然后用上面的公式计算每个分割方案的分数就可以了。 $ h5 g: M' B; Z+ S: ]( t+ m; c& E6 }# p
xgboost算法伪代码如下:1 x7 q, i- a% g0 z
" P$ k3 }8 B$ V( J! C# Q3 c
9 w. y+ T- V0 |$ v4 b; g6 n. ~
# j j" b- F# R# P" c- ^3、Xgboost算法参数; |% d4 Z# s {6 l3 m8 A
XGBoost的作者把所有的参数分成了三类:2 q- ~( m4 n# E6 A+ i
7 M" |5 I# u- }
通用参数:宏观函数控制。 # \0 M- q- l' H" ?! i9 oBooster参数:控制每一步的booster(tree/regression)。 $ p& X4 K3 f/ o; R- |学习目标参数:控制训练目标的表现。 " o6 `/ z- { J% p9 I5 a5 R5 A3.1通用参数 U- S" ~+ H @& }0 n. t这些参数用来控制XGBoost的宏观功能。0 k" Z% G# N; P' E, _9 w
7 H- E P, u" O G! M0 d$ ^
1、booster[默认gbtree] , Y& d& [4 `; u1 j4 q3 @) c# J @! o) Y) j$ u( w v! B
选择每次迭代的模型,有两种选择: & O: T* V1 c5 I5 s/ `+ }
gbtree:基于树的模型 c# _- ^ a+ z
gbliner:线性模型. s; w# ~. g) h
2、silent[默认0]& j5 Q m) ~5 R5 J! a. ?# \ T
4 N) `3 A* O6 ?$ o2 I3 P
当这个参数值为1时,静默模式开启,不会输出任何信息。 9 T/ ]8 y5 G" X一般这个参数就保持默认的0,因为这样能帮我们更好地理解模型。0 P2 M( g6 |5 Q. S, p: o
3、nthread[默认值为最大可能的线程数] + Z) t5 I% j: Z" p' u 1 j* V& T/ O! i4 t/ x; i) n6 H这个参数用来进行多线程控制,应当输入系统的核数。4 c& B8 i8 u* @' M; ?% Z' U$ L8 y+ C
如果你希望使用CPU全部的核,那就不要输入这个参数,算法会自动检测它。 : h/ p% ~) w2 ~7 G8 ]0 O s3 L还有两个参数,XGBoost会自动设置,目前你不用管它。接下来咱们一起看booster参数。 $ C, a+ n3 E, x& ~- g* G+ H3 ^4 h$ M+ M, `! Y8 E& g" u4 R
3.2 booster参数! G9 p3 b. d3 Z# ~/ q+ J3 `; u
尽管有两种booster可供选择,我这里只介绍tree booster,因为它的表现远远胜过linear booster,所以linear booster很少用到。6 y" c- A) @$ P2 H. C
; z$ \ h Y" J. x, f* }( A和GBM中的参数相同,这个值为树的最大深度。 $ x9 P, r. I* C+ H, n. A2 v这个值也是用来避免过拟合的。max_depth越大,模型会学到更具体更局部的样本。1 ?: D+ N$ b5 s
需要使用CV函数来进行调优。; Q9 K1 i3 c5 N" W' T* F. \3 O' F
典型值:3-10 * b% p! c) l K( B9 b2 U1 g/ R! f4、max_leaf_nodes % J* k4 v" l$ o: I0 k- a2 Y, a , x6 X8 q: h% M2 Z4 Z, F* W$ `树上最大的节点或叶子的数量。( ^- y3 \* U( e* e: G
可以替代max_depth的作用。因为如果生成的是二叉树,一个深度为n的树最多生成n2n2个叶子。 7 h+ q5 J6 H1 W8 q$ g2 ?+ s3 X7 W* E' f如果定义了这个参数,GBM会忽略max_depth参数。 " k9 H' @+ O% k. b2 e5、gamma[默认0] : w( w, `4 t; e 9 y1 |! w' d/ Z$ P5 Y: m' j( d在节点分裂时,只有分裂后损失函数的值下降了,才会分裂这个节点。Gamma指定了节点分裂所需的最小损失函数下降值。 3 p0 v3 Y0 t9 E$ C* b这个参数的值越大,算法越保守。这个参数的值和损失函数息息相关,所以是需要调整的。5 @: Y f/ l. J, \* q2 O3 R
6、max_delta_step[默认0]6 D9 A! t! Y! @1 K) Z
7 Y8 N6 @3 R u; |) d
这参数限制每棵树权重改变的最大步长。如果这个参数的值为0,那就意味着没有约束。如果它被赋予了某个正值,那么它会让这个算法更加保守。 4 M1 V0 o" U! J7 x. }" ]通常,这个参数不需要设置。但是当各类别的样本十分不平衡时,它对逻辑回归是很有帮助的。 . F" `+ \+ j$ t# v2 w这个参数一般用不到,但是你可以挖掘出来它更多的用处。: u" K6 X- O9 F) J5 |3 F+ z4 h
7、subsample[默认1]8 `; ]' v7 Z: {+ b9 A3 c
: F# u h) M% g, M6 k. l9 t
和GBM中的subsample参数一模一样。这个参数控制对于每棵树,随机采样的比例。# o, i9 p1 h7 G% l: h1 }
减小这个参数的值,算法会更加保守,避免过拟合。但是,如果这个值设置得过小,它可能会导致欠拟合。- X' \( q4 W! Q; [
典型值:0.5-1' g8 E1 Q+ M; x& N' s( G; P
8、colsample_bytree[默认1]4 @$ f- e6 c+ N3 L4 s
, D* c0 q0 k/ _! O和GBM里面的max_features参数类似。用来控制每棵随机采样的列数的占比(每一列是一个特征)。 ( y t8 d* N! F典型值:0.5-17 g7 C1 c. k. y L( l8 |, L
9、colsample_bylevel[默认1]/ D7 a! g- g4 g# r. \; B
; n# T# p3 d& C7 u用来控制树的每一级的每一次分裂,对列数的采样的占比。- e4 r5 L" W0 E4 S* ], m+ q0 y* m$ {
我个人一般不太用这个参数,因为subsample参数和colsample_bytree参数可以起到相同的作用。但是如果感兴趣,可以挖掘这个参数更多的用处。1 V/ P1 E0 C4 U& A
10、lambda[默认1] ! a6 k/ ^! Z% ]3 g6 ~% ^8 N' l/ ?- b- _. }! D
权重的L2正则化项。(和Ridge regression类似)。% d9 I+ ^1 f/ Y6 w" C7 O
这个参数是用来控制XGBoost的正则化部分的。虽然大部分数据科学家很少用到这个参数,但是这个参数在减少过拟合上还是可以挖掘出更多用处的。 ! ~7 v3 s" R" s: k& o! M& R5 Y. R; G11、alpha[默认1] 4 p& h. E9 h' f3 q5 h: e' m% a4 E4 M7 k8 z) S, l9 H: O
权重的L1正则化项。(和Lasso regression类似)。 # A/ L4 b A) L( n. q" ]5 P. y9 A( b可以应用在很高维度的情况下,使得算法的速度更快。 ) l# k4 T/ J% N1 r& {7 I n2 g12、scale_pos_weight[默认1] # J" ~6 g2 S2 P' v + k% P" I q3 T( W" I4 c在各类别样本十分不平衡时,把这个参数设定为一个正值,可以使算法更快收敛。8 b) [& X' c F/ u7 O
3.3学习目标参数$ U2 F( _* f% p6 ]9 z1 ^, g: ?
这个参数用来控制理想的优化目标和每一步结果的度量方法。" u& N4 h3 v/ a. F* S D, K' o