: D' u) Y, b& Z N5 G/ x- e 其中为叶子节点的得分值,表示样本对应的叶子节点。为该树的叶子节点个数。 : e$ Q' \2 m7 L9 x1 P. \ 9 G) \' Y' E& `$ w* ^ 因此,在这里。我们将该树的复杂度写成:0 T2 V* h0 h& N" q, B& }
" g! X2 V) Y& I6 l' l* t. u2 _ 其中,γγ为L1L1正则的惩罚项,λλ为L2L2正则的惩罚项3 m: t* e6 k3 \6 t
2 Z2 f- y! J" t# k% I/ F
复杂度计算例子如下:% z7 K# b& j: d8 _! ^& I- A
& W2 ^3 {- M' E! M: r/ Q3 g4 S; K
5 X0 d1 x i( [4 z# d$ o
- S2 V9 p% M; v& V2) 损失函数 " u& v- D0 R$ W3 R- q; ` ( ?1 H: T+ g6 g9 { 前面已经说过,为了一般性,实际中往往是基于loss Function 在函数空间的的负梯度学习,对于回归问题残差和负梯度也是相同的。和传统的boosting tree模型一样,xgboost的提升模型也是采用的残差(或梯度负方向),不同的是分裂结点选取的时候不一定是最小平方损失。 + n5 C8 |9 U, g+ G5 m: ^9 C3 q7 F ; h; ]( p- ~$ H( d# t+ }$ s/ h' \0 N. K a+ k6 K0 ^8 S' g" ?/ A. K* d) P0 |; @
对目标函数的改写:1 {, z+ {! \$ ]* s6 q: I X0 A
% `% e2 t% {( \: l3 }* B" G3 _: i % ~3 i- z( z; i; ]% v" c s ' _: L# M E6 H6 i 最终的目标函数只依赖于每个数据点的在误差函数上的一阶导数和二阶导数。这么写的原因很明显,由于之前的目标函数求最优解的过程中只对平方损失函数时候方便求,对于其他的损失函数变得很复杂,通过二阶泰勒展开式的变换,这样求解其他损失函数变得可行了。 9 E2 _: C$ g% N, I0 [ Q- ?4 f: E1 Z( y* [& @; e
我相信到这里肯定都没有问题,接下来的理解是整个损失函数的难点,我自己开始学的时候想了一些时间,接下来我尽量用白话来叙述。 4 ]! t# a/ R8 Z* `! j. M( n% u# y2 i
1)对的理解:在上面我们已经说了,当一个样本进来的时候,不管是回归问题还是分类问题,你最终都会掉到叶子结点上,而每颗树的每个叶子节点都会对应有一个得分(想象一下回归问题,每个叶子节点对应的是落入该叶子结点的所有训练样本的均值),所以可以理解为一个样本在t轮最终的得分函数。 9 i' U. f1 O( y4 h7 @; a1 I5 H7 F6 u3 r6 [3 G. c9 `
2)对的理解:其实这个的理解,我最初钻了牛角尖,其实只要当我们的损失函数一旦确定下来(理解的前提),这个求导就和我们高数中的求导一回事啦,只不过表达式看起来很唬人。 / c. d6 j+ G1 t/ e, @7 t, S4 l4 Q ! u4 u v: ?% ` H2 b" X' T l& F! e3)目标函数全部转换成在第t棵树叶子节点的形式。从求和符号我们可以看出,是在对每个样本求损失,我们在第一点就已经说了,第i个样本最终都会落到树的叶子结点中去的,只是不同的叶子节点,你会取不同的值罢了。那我们能不能讲对样本的损失转移到对叶子结点中再求损失呢(后话,这个就是这么做的), 可以看做是每个样本在第t棵树的叶子节点得分值相关函数的结果之和,所以我们也能从第t棵树的叶子节点上来表示。 ' c% g- b8 S' c' _" @3 D$ M% y6 U; k( h1 X, g, L. e p
* o+ @4 b5 o: `" [$ T( n" `
L) L4 I8 S3 E7 ?: x* `
这里也在解释下,描述了一整颗树的模型,他当然能分解成每个叶子结点的集合啦,而刚好是每个叶子节点的得分函数,这两个于是就可以相互转化了。: g3 I4 G$ R' G& R! M7 ^" D/ y% O
& l6 U3 s- i) T+ n
其中为第t棵树中总叶子节点的个数,表示样本落在第个叶子节点上,为第个叶子节点的得分值。 0 u% V+ h, W0 D, ^8 D4 _) L 3 z/ I* h; b) b$ l r) `1 ?* \在这里,令 ! q l2 Y: _1 y% ]+ l+ R6 F! _. r; X7 z# |# Q& f: v
& O, N3 q+ K, V0 H
, [" H7 {% a5 w$ B7 C
对求偏导,并使其导函数等于0,则有: C" x' C5 Y/ v; f
/ X, e" K* B- h/ A* F/ {& m; F x6 y1 [8 r
# ?( k% z6 B' x& K2 R/ n6 b
* | N' `1 O4 t& R. \& L: S! g
: l G0 ?7 a" i P0 _# l
到此,损失函数的推导完成。 & _- T! H: |' b% D) F0 {6 Y8 b2 ~2 w 3 G& O, v) k! W- f8 {" o3)树结构的打分函数" ]: d2 M2 ]) d
& T, n. p* I. u; U
Obj代表了当指定一个树的结构的时候,在目标上面最多减少多少。结构分数(structure score) ; W: I8 e4 o7 J: n' }4 Q. v 6 i: l) o$ C( S3 B" |+ ^4 K4 W1 v6 l u: ~) S" P7 d0 _ Y% }
& D5 m6 m' U0 r5 e8 ^4 G xgboost算法的步骤和GB基本相同,都是首先初始化为一个常数,gb是根据一阶导数ri,xgboost是根据一阶导数gi和二阶导数hi,迭代生成基学习器,相加更新学习器。 ! v5 ]4 t0 a, ~1 n" w' U, ]& n+ K: f& t
对于每一次尝试去对已有的叶子加入一个分割/ k& c( k7 J5 Y) u& n i4 y/ A
3 ~; I F% }/ l$ U5 t
) [4 `5 u1 x; U$ e& b. X E& |9 u6 s E
这样就可以在建树的过程中动态的选择是否要添加一个结点。 联想决策树中信息增益,这里的原理类似。这一步实质上是为了寻找分裂结点的候选集。) N4 ?) P1 s" O2 p4 ~* _/ ?$ a
2 L' p& E, Q( D4 b1 {& E$ U
如何高效地枚举所有的分割呢?我假设我们要枚举所有x < a 这样的条件,对于某个特定的分割a我们要计算a左边和右边的导数和。- \' w! v1 o# u3 o. z9 s
z. @, a( i. V! I
2 D( z. a1 S3 c& a6 ~" J: ~2 V0 ?* g
我们可以发现对于所有的a,我们只要做一遍从左到右的扫描就可以枚举出所有分割的梯度和和。然后用上面的公式计算每个分割方案的分数就可以了。 , d3 H+ ]- o h4 A! o' Q- ?8 t" H/ q" A' j* b9 p# K
xgboost算法伪代码如下: : k; y. W ~ q5 A- ?/ q/ U - e8 _7 B4 }) Y * O% \* t: A; K6 Z x( o# L! ]6 |. J( S8 }
3、Xgboost算法参数9 F' ?2 ]& f. F6 V
XGBoost的作者把所有的参数分成了三类: ; H! _8 B, |" [" @' j0 X5 x' Q3 Q9 c4 c6 F p+ G
通用参数:宏观函数控制。 5 N$ `( Y q4 I1 Q2 a5 oBooster参数:控制每一步的booster(tree/regression)。 + n3 ^: z, P( G" t3 W学习目标参数:控制训练目标的表现。6 P5 u, o- J1 j. w
3.1通用参数3 b5 c# h8 G Y, H* ~7 M S# I! O @
这些参数用来控制XGBoost的宏观功能。/ _4 E, c/ K8 y# v: C3 f: T( N
3 k6 P, r: o3 M' G6 f q1、booster[默认gbtree]) ]) ]* e6 d: N
1 T2 a8 S' ^: b' w
选择每次迭代的模型,有两种选择: 0 z) _1 S1 o+ U: d1 f% _gbtree:基于树的模型 : E# a5 Q+ q* @% P7 O7 Qgbliner:线性模型7 z0 b8 M/ @/ s7 r: H
2、silent[默认0] " I, U% u7 R' ?) ?3 A7 O& o+ a# j9 W6 N; t/ L' R) E2 a: I
当这个参数值为1时,静默模式开启,不会输出任何信息。% z+ i6 B$ F/ D8 @
一般这个参数就保持默认的0,因为这样能帮我们更好地理解模型。 # v4 [) @5 W. m0 F" X3 \3、nthread[默认值为最大可能的线程数] ! L+ l9 u% F, j+ G, {2 S. R/ W, {9 k4 v; c. k6 G5 I9 {
这个参数用来进行多线程控制,应当输入系统的核数。 # d/ ~8 }6 y$ s如果你希望使用CPU全部的核,那就不要输入这个参数,算法会自动检测它。 9 v# H2 I1 P$ _8 f4 C) F还有两个参数,XGBoost会自动设置,目前你不用管它。接下来咱们一起看booster参数。/ c& x+ u1 C3 I+ p$ D( @
& u$ k; L, L, g+ A0 }0 J& s3.2 booster参数- K5 b9 K. g# a) M: |3 m1 h Z6 X5 X
尽管有两种booster可供选择,我这里只介绍tree booster,因为它的表现远远胜过linear booster,所以linear booster很少用到。 + D" L5 I( }$ P9 a1 D: u6 a5 v7 p/ `/ n0 m
1、eta[默认0.3]6 W+ n3 M7 P7 n9 N8 e Q' z4 k/ g
$ D) j+ j, J* ~/ @ m和GBM中的 learning rate 参数类似。 * t' s# m+ w4 U8 D: N通过减少每一步的权重,可以提高模型的鲁棒性。 ( A3 B8 K" z! W4 J% A! ]: U4 r典型值为0.01-0.2。 2 Q, y; w1 R! y: ^2、min_child_weight[默认1]* r! m* e _; H I: [
" I! p4 z/ n4 ~: H
决定最小叶子节点样本权重和。 7 b! w1 b% @3 P; B0 e& Y和GBM的 min_child_leaf 参数类似,但不完全一样。XGBoost的这个参数是最小样本权重的和,而GBM参数是最小样本总数。* M, P/ P8 v, U. ?# _- Y
这个参数用于避免过拟合。当它的值较大时,可以避免模型学习到局部的特殊样本。 \1 Q/ x1 q5 ^ r& O0 ?: f但是如果这个值过高,会导致欠拟合。这个参数需要使用CV来调整。 ! g9 m' ~/ l* l4 u, V7 n' V" f2 N3、max_depth[默认6]7 G/ D' y# R1 |1 j6 x; ]5 [
$ s+ W, N, D% v
和GBM中的参数相同,这个值为树的最大深度。% Y2 `, }9 W/ c* ~3 r M4 ]' k
这个值也是用来避免过拟合的。max_depth越大,模型会学到更具体更局部的样本。4 ?3 @6 R3 C% u$ {; p5 o( C
需要使用CV函数来进行调优。4 K% W7 A7 b2 U& h8 j
典型值:3-10 6 Y. M. z$ l( M1 z; {4、max_leaf_nodes 2 U4 k3 Q0 y! f+ [4 [- k# L) p" A. ~1 K4 W5 l
树上最大的节点或叶子的数量。 / L% F; u f! \: Z C! E" r可以替代max_depth的作用。因为如果生成的是二叉树,一个深度为n的树最多生成n2n2个叶子。 5 @) M. M+ E. [4 s' g& r2 i如果定义了这个参数,GBM会忽略max_depth参数。 0 {$ J0 ^0 g" n% l1 X% w5、gamma[默认0] 2 n1 M" \, F- ]7 c4 a5 [$ z& h* v! t9 I: z( C4 y/ m+ f
在节点分裂时,只有分裂后损失函数的值下降了,才会分裂这个节点。Gamma指定了节点分裂所需的最小损失函数下降值。 o! h( F3 E" f
这个参数的值越大,算法越保守。这个参数的值和损失函数息息相关,所以是需要调整的。2 c) s" g) N' l! q
6、max_delta_step[默认0]8 @7 v& T" K$ g y
1 P. E) Y \/ Q
这参数限制每棵树权重改变的最大步长。如果这个参数的值为0,那就意味着没有约束。如果它被赋予了某个正值,那么它会让这个算法更加保守。9 L. U2 |5 }2 W( F: P" r
通常,这个参数不需要设置。但是当各类别的样本十分不平衡时,它对逻辑回归是很有帮助的。 , s3 c1 |9 |4 N" f! u! f% r这个参数一般用不到,但是你可以挖掘出来它更多的用处。9 a" Q8 H2 e5 b7 l+ ]
7、subsample[默认1] 0 K! |2 [1 N3 r2 `8 ^& {+ L" M" { ) }' {8 J D' P1 V, p2 i9 N和GBM中的subsample参数一模一样。这个参数控制对于每棵树,随机采样的比例。- o2 K! n6 N1 X# X, y0 w& O
减小这个参数的值,算法会更加保守,避免过拟合。但是,如果这个值设置得过小,它可能会导致欠拟合。2 e4 Q, Z. B, J, U6 ?, Q: G+ b1 Y
典型值:0.5-12 N: n0 }& @1 v: l2 L" ?& ^
8、colsample_bytree[默认1]* |. F9 T2 y4 P/ j
! ^) g+ d) s' o0 R L1 P4 j; T2 H: M
和GBM里面的max_features参数类似。用来控制每棵随机采样的列数的占比(每一列是一个特征)。) G$ A3 h' F t+ ?, y% G0 l2 O
典型值:0.5-1 & o! Q# f1 J6 ?7 M3 `1 ^9、colsample_bylevel[默认1]8 P$ D1 K. d, ]
* D7 u+ o, B# E+ M
用来控制树的每一级的每一次分裂,对列数的采样的占比。4 x# d% {9 ?2 _- [
我个人一般不太用这个参数,因为subsample参数和colsample_bytree参数可以起到相同的作用。但是如果感兴趣,可以挖掘这个参数更多的用处。 * Z3 O; U8 H) Y6 B10、lambda[默认1] " }5 Q" c9 p( g, A @' i* D0 J9 l) T0 t0 f+ O# A
权重的L2正则化项。(和Ridge regression类似)。& g0 b9 w8 r6 U
这个参数是用来控制XGBoost的正则化部分的。虽然大部分数据科学家很少用到这个参数,但是这个参数在减少过拟合上还是可以挖掘出更多用处的。; D x9 S9 P! D. u3 Y
11、alpha[默认1] / T( u- T$ F! i3 B# g3 U$ S& E6 }5 A8 u8 A6 A8 W
权重的L1正则化项。(和Lasso regression类似)。 5 y- ` q) f6 j& E可以应用在很高维度的情况下,使得算法的速度更快。3 Q; E1 b8 n6 k e( K8 S. e
12、scale_pos_weight[默认1]3 p. A# I6 d% T/ `5 V% r2 @
1 ]" W0 a0 k0 j j( l在各类别样本十分不平衡时,把这个参数设定为一个正值,可以使算法更快收敛。) V" N: a0 v l
3.3学习目标参数# T! p( Z6 z" B4 A5 P5 n8 L" ?
这个参数用来控制理想的优化目标和每一步结果的度量方法。0 I5 B% n- C3 _8 {
$ R' {5 B! @1 O- |* R: b; e
1、objective[默认reg:linear] 9 o: X- o) B9 R' a) I! J9 A" V) M: v7 }
这个参数定义需要被最小化的损失函数。最常用的值有: 9 _/ H/ A+ T5 H3 s; Q, Wbinary:logistic 二分类的逻辑回归,返回预测的概率(不是类别)。 ( }: e+ ?$ Y" X: i: W/ Y. J) amulti:softmax 使用softmax的多分类器,返回预测的类别(不是概率)。 在这种情况下,你还需要多设一个参数:num_class(类别数目)。: l) R0 g/ g1 S" n
multi:softprob 和multi:softmax参数一样,但是返回的是每个数据属于各个类别的概率。 4 Z. S, Y6 n) X4 O: S" K2、eval_metric[默认值取决于objective参数的取值]) Y5 l- O6 O& i; P4 s: M. C/ Z
6 v/ Y2 W+ B. ~& {2 c6 m
对于有效数据的度量方法。 # E8 Q$ E5 G. D& F7 n. N对于回归问题,默认值是rmse,对于分类问题,默认值是error。 % \& q. ^% @! }5 Q典型值有: * w8 m. P1 e7 i; | f: t @+ drmse 均方根误差(∑Ni=1ϵ2N−−−−−√∑i=1Nϵ2N) 4 r3 Y% |4 `7 x) Y7 O9 C" ?mae 平均绝对误差(∑Ni=1|ϵ|N∑i=1N|ϵ|N)1 K( F5 i$ |; Y- m+ N( q2 y
logloss 负对数似然函数值 * w, B" T. ~( \0 i" q9 nerror 二分类错误率(阈值为0.5)( a* k) t6 p Q3 y. T* {& p
merror 多分类错误率- i# }+ l" w, _# s2 U$ a5 W
mlogloss 多分类logloss损失函数9 l* \2 `/ q4 i7 F) O$ y! [" h3 I
auc 曲线下面积 7 Q/ E4 r2 s6 d& H; u7 K$ d' cpython的Xgbosoost调参实例:推荐看 https://blog.csdn.net/han_xiaoyang/article/details/52665396- G, ^$ m8 ~! x' w! B
' \+ c: c/ o' ?( I: b' U) \% b
除此以外,xgboost除了原生版的调用以外,sklearn还为我们封装了一个sklearn版本调用的方法,from xgboost import XGBClassifier,调参同样可以借用网格搜索的方法,这是一篇xgboost的网格搜索的案例. r( ~8 I- Q& X: L: y3 d. y9 X8 @
1 G$ H+ h( P0 k. d* Y4、小结 + o1 a& B b" Q$ Lxgboost与gdbt除了上述的不同,xgboost在实现时还做了许多优化:(以下转载于 机器学习系列(12)_XGBoost参数调优完全指南(附Python代码))! b" e/ o9 {- D$ g6 e
: ~. `" ]& ? K/ f. z$ k( T
1)并行处理+ k% _3 u' y! E! v3 C# B
# C) l2 q) M* h
XGBoost可以实现并行处理,相比GBM有了速度的飞跃。 . n8 |8 T7 x+ [7 \) o: ?. T L/ t不过,众所周知,Boosting算法是顺序处理的,它怎么可能并行呢?每一课树的构造都依赖于前一棵树,那具体是什么让我们能用多核处理器去构造一个树呢?我希望你理解了这句话的意思。如果你希望了解更多,点击这个链接。; B: i7 c6 L; g& i/ D9 z
XGBoost 也支持Hadoop实现。 ! p4 p+ B% n0 s! R) ]% C! s2)高度的灵活性$ L4 {! |" S$ ?' Z3 C- K0 Q
1 C% r0 r3 ?1 Q. R
XGBoost 允许用户定义自定义优化目标和评价标准, z. v) a" u, X+ o2 K- S4 p7 O
3)缺失值处理# _ ^! U) t2 y0 ^1 O8 v
5 ?$ `" |6 Y$ ]- `. f" j0 b
XGBoost内置处理缺失值的规则。7 B$ v) d- x/ W; ] P5 q
用户需要提供一个和其它样本不同的值,然后把它作为一个参数传进去,以此来作为缺失值的取值。XGBoost在不同节点遇到缺失值时采用不同的处理方法,并且会学习未来遇到缺失值时的处理方法。; ?# c+ f, s6 R" ?$ l* i
4)剪枝 5 f3 W1 v1 T3 A. p' @ ' i# V7 s, C. J) v5)内置交叉验证 F! c* ]& Q2 u! S7 K 2 ]- L: r" T! v* U: lXGBoost允许在每一轮boosting迭代中使用交叉验证。因此,可以方便地获得最优boosting迭代次数。: k2 ?% T) Y i4 G+ @' ]. E& ?
而GBM使用网格搜索,只能检测有限个值。 2 O3 i/ B! j9 ?0 Q; C* ^: z) _. F! {; q3 e9 u" P& n; V. c
! r- \: a9 m; N0 X) e: j& `
参考资料:! B" o; n c! t7 U0 L
' ^" O+ L% @8 ^/ {2 L1 r
https://www.cnblogs.com/wxquare/p/5541414.html 0 }8 B" Q4 y5 \$ T& E 0 f% L8 U( w2 j0 L! L, O. P9 F [https://blog.csdn.net/a1b2c3d4123456/article/details/52849091 & D% N, E3 @8 i3 p 4 s$ f$ Y3 Q2 S. B4 S+ W) ~3 f* y陈天奇的boosting tree的ppt:http://homes.cs.washington.edu/~tqchen/pdf/BoostedTree.pdf( ^$ G. B5 }( D9 \2 z/ T
2 q! h; h' i8 H- j- b0 b0 X8 i
sklearn版本调用的方法:XGBoost Python API Reference (official guide) " x, h) ]6 F* U* d7 h2 l: l ) }9 p4 Q) J6 g( I4 t- N" }8 |XGBoost 参数:http://xgboost.apachecn.org/cn/latest/parameter.html# 6 ]2 U8 u: v2 s0 {1 J- j) N& A& v6 Z' L
XGBoost-Python完全调参指南-参数解释篇https://blog.csdn.net/wzmsltw/article/details/50994481 4 w+ y& A5 N% O' v7 y$ v9 p0 j ; B* d2 v1 F, ~: ZXGBoost参数调优完全指南(附Python代码)https://blog.csdn.net/han_xiaoyang/article/details/52665396 4 I9 ]% B; p3 s( Y$ }7 u8 a4 a8 k+ X9 V5 D2 Y* A
python 下实现xgboost 调参演示https://blog.csdn.net/weixin_41370083/article/details/792768878 ?! g5 t* D; u' g4 e* s