1 XGBoost
∙
\bullet
∙ XGBoost: eXtreme Gradient Boosting
∙
\bullet
∙ Gradient Boosting Machines(GBM)的C++优化实现,快速有效。由DMLC(Distributed(Deep) Machine Learning Community)维护。
∙
\bullet
∙ Tianqi Chen(on Quora.com): The name xgboost, though, actually refers to the engineering goal to push the limit of computations resources for boosted tree algorithms.Which is the reason why many people use xgboos.
∙
\bullet
∙ http://github.com/dmlc/xgboost
工程目标,是不是就是意味着Gradient Boosting的核心算法是不变的?尽管也明确说明了是C++版的优化实现,但工程目标的词是第一次遇见。
∙
\bullet
∙ 可自定义损失函数:采用二阶Taylor展开近似损失函数。应该指的是用二阶泰勒展开代替原有的损失函数吧?
∙
\bullet
∙ 规范化的正则项:
∙
\bullet
∙ 叶子结点数目(L1正则)
∙
\bullet
∙ 叶子结点的分数(L2正则)
∙
\bullet
∙ 建树
∙
\bullet
∙ 支持分裂点近似搜索
∙
\bullet
∙ 稀疏特征处理
∙
\bullet
∙ 缺失值处理
∙
\bullet
∙ 剪枝:先建完全树,后剪枝
∙
\bullet
∙ 老师语音:GBM用的是梯度下降,所以是一阶泰勒展开近似损失函数。Scikit-Learn中实现的CART没有后剪枝,只有过早停止。当样本量、特征数比较大时,采用精确的穷举搜索不太现实,所以支持了分裂点近似搜索。XGBoost在并行计算和缓存优化方面也做了许多工作,所以运行速度比较快。
非XGBoost(比如单棵树、GBM等)有没有采用正则,或者类似的手段呢?
2 损失函数的二阶近似
f
(
x
+
△
x
)
=
f
(
x
)
+
f
′
(
x
)
△
x
+
1
2
f
′
′
(
x
)
△
f(x+\triangle x) = f(x) + f'(x)\triangle x+ \frac{1}{2}f''(x)\triangle
f(x+△x)=f(x)+f′(x)△x+21f′′(x)△
∙
\bullet
∙ 在第m步时,令
g
m
,
i
=
[
∂
L
(
f
(
x
i
)
,
y
i
)
∂
f
(
x
i
)
]
f
=
f
m
−
1
,
h
m
,
i
=
[
∂
2
L
(
f
(
x
i
)
,
y
i
)
∂
2
f
(
x
i
)
]
f
=
f
m
−
1
g_{m,i} = [\frac{\partial L(f(x_i),y_i)}{\partial f(x_i)}]_{f=f_{m-1}}, h_{m,i} = [\frac{\partial^2 L(f(x_i),y_i)}{\partial^2 f(x_i)}]_{f=f_{m-1}}
gm,i=[∂f(xi)∂L(f(xi),yi)]f=fm−1,hm,i=[∂2f(xi)∂2L(f(xi),yi)]f=fm−1
∙
\bullet
∙ XGBoost对损失函数将
L
(
f
(
x
i
)
,
y
i
)
L(f(x_i),y_i)
L(f(xi),yi)在
f
m
−
1
f_{m-1}
fm−1处进行二阶泰勒展开:
∙
\bullet
∙
f
m
(
x
i
)
=
f
m
−
1
(
x
i
)
+
ϕ
(
x
i
)
f_m(x_i) = f_{m-1}(x_i) + \phi(x_i)
fm(xi)=fm−1(xi)+ϕ(xi)
∙
\bullet
∙
L
(
y
i
,
f
m
−
1
(
x
i
)
+
ϕ
(
x
i
)
)
=
L
(
y
i
,
f
m
−
1
(
x
i
)
)
+
g
m
,
i
ϕ
(
x
i
)
+
1
2
h
m
,
i
ϕ
(
x
i
)
L(y_i, f_{m-1}(x_i) + \phi(x_i)) = L(y_i,f_{m-1}(x_i)) + g_{m,i}\phi(x_i) + \frac{1}{2}h_{m,i}\phi(x_i)
L(yi,fm−1(xi)+ϕ(xi))=L(yi,fm−1(xi))+gm,iϕ(xi)+21hm,iϕ(xi),其中
L
(
y
i
,
f
m
−
1
(
x
i
)
)
L(y_i,f_{m-1}(x_i))
L(yi,fm−1(xi))这部分与未知量
ϕ
(
x
i
)
\phi(x_i)
ϕ(xi)无关
∙
\bullet
∙ 所以
L
(
y
i
,
f
m
−
1
(
x
i
)
+
ϕ
(
x
i
)
)
=
g
m
,
i
ϕ
(
x
i
)
+
1
2
h
m
,
i
ϕ
(
x
i
)
L(y_i, f_{m-1}(x_i) + \phi(x_i)) = g_{m,i}\phi(x_i) + \frac{1}{2}h_{m,i}\phi(x_i)
L(yi,fm−1(xi)+ϕ(xi))=gm,iϕ(xi)+21hm,iϕ(xi)
普通GBM是在第m-1次时,用当次目标函数
L
m
−
1
L_{m-1}
Lm−1对当次得到的模型
f
m
−
1
f_{m-1}
fm−1求导,再以
f
m
−
1
f_{m-1}
fm−1减去负梯度,得到模型
f
m
f_{m}
fm。要求的第m次弱分类器,就是拟合负梯度的结果。
XGBoost是把第m次要求的弱分类器
ϕ
(
x
)
\phi(x)
ϕ(x),作为
△
\triangle
△加在第m-1次的模型之上,再求损失函数,即
L
(
y
i
,
f
m
−
1
(
x
)
+
ϕ
(
x
)
)
L(y_i, f_{m-1}(x) + \phi(x))
L(yi,fm−1(x)+ϕ(x)),然后再进行泰勒展开。但是泰勒展开后,要做什么,却不确定,估计是代替GBM里的原始损失函数,还需要继续求负梯度,并拟合出
ϕ
(
x
)
\phi(x)
ϕ(x),但看起来好像又不太可能这么做,因为泰勒展开后的结果中也含
ϕ
(
x
)
\phi(x)
ϕ(x),不太好用自己去拟合一个含有自己的表达式。后续补充:本节后边,会用到展开后的公式,大概是将映射到叶子分数向量
w
\mathbf w
w的函数作为弱学习器
ϕ
\phi
ϕ,代入由展开式作为因子的目标函数,目标函数经过一系列变换后,令目标函数导数为0,得到最佳的w,然后将w代入目标函数变换后的式子里,即得到整个树的分数,该分数越小越好,注意:树的分数和叶子结点的分数
w
\mathbf w
w是两个不同的概念。
∙
\bullet
∙ XGBoost是把正则项放在了基学习器决策树上,XGBoost中不管分类任务还是回归任务,用的都是回归树。
3 基学习器:回归树
∙
\bullet
∙ Recall:回归树的定义:把树拆分成结构部分q和叶子分数部分w
∙
\bullet
∙
ϕ
(
x
)
=
w
q
(
x
)
,
w
∈
R
T
,
q
:
R
D
—
>
{
1
,
.
.
.
,
T
}
\phi(\mathbf x) = w_{q(x)}, w \in R^T, q:R^D—>\{1,...,T\}
ϕ(x)=wq(x),w∈RT,q:RD—>{1,...,T}
∙
\bullet
∙ 结构函数q: 把输入映射到叶子的索引
∙
\bullet
∙ w: 给出每个索引号对应的叶子的分数
∙
\bullet
∙ T为树中叶子节点的数目,D为特征数。
注意:此处的
R
T
R^T
RT、
R
D
R^D
RD代表的是T维实向量、D维实向量,不是次方。
4 树的复杂度
∙
\bullet
∙ 树的复杂度定义为(不是唯一的方式):
R
(
ϕ
(
x
)
)
=
γ
T
+
1
2
λ
∑
t
=
1
T
w
t
2
R(\phi(x)) = \gamma T + \frac{1}{2}\lambda\sum_{t=1}^{T}w_t^2
R(ϕ(x))=γT+21λt=1∑Twt2
∙
\bullet
∙ 叶子节点的数目T(L1正则)、叶子节点分数的平方和(L2正则)
注意:
γ
\gamma
γ和T之间是乘积关系,不是次方。叶子节点数目是L1正则,那么线性回归一章,L1正则是各参数绝对值之和,这两种L1正则还是有很大的差异吧。
5 目标函数
令每个叶子t上的样本集合为
I
t
=
{
i
∣
q
(
x
i
)
=
t
}
I_t = \{i|q(\mathbf x_i) = t\}
It={i∣q(xi)=t}(看起来,这里的
i
i
i可以理解为整个样本集的索引,而
q
(
x
i
)
=
t
q(x_i) = t
q(xi)=t,代表样本
x
i
\mathbf x_i
xi通过函数
q
q
q,得到叶子结点的索引
t
t
t。)
J
(
ϕ
(
x
)
)
=
∑
i
=
1
N
L
(
f
(
x
i
)
,
y
i
)
+
R
(
ϕ
(
x
)
)
J(\phi(\mathbf x)) = \sum_{i=1}^{N}L(f(\mathbf x_i), y_i) + R(\phi(\mathbf x))
J(ϕ(x))=i=1∑NL(f(xi),yi)+R(ϕ(x))
≅
∑
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
\cong \sum_{i=1}^{N}(g_{m,i}\phi(\mathbf x_i) + \frac{1}{2}h_{m,i}\phi(\mathbf x_i)^2) + \gamma T + \frac{1}{2}\lambda\sum_{t=1}^{T}w_t^2
≅i=1∑N(gm,iϕ(xi)+21hm,iϕ(xi)2)+γT+21λt=1∑Twt2
=
∑
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
= \sum_{i=1}^{N}(g_{m,i}w_{q(\mathbf x_i)}+ \frac{1}{2}h_{m,i}w_{q(x_i)}^2) + \gamma T + \frac{1}{2}\lambda\sum_{t=1}^{T}w_t^2
=i=1∑N(gm,iwq(xi)+21hm,iwq(xi)2)+γT+21λt=1∑Twt2样本集里每个样本连加 = 所有叶子结点中的所有样本相加,于是:
=
∑
t
=
1
T
(
∑
i
∈
I
t
g
m
,
i
w
t
+
1
2
∑
i
∈
I
t
h
m
,
i
w
t
2
)
+
γ
T
+
1
2
λ
∑
t
=
1
T
w
t
2
= \sum_{t=1}^{T}(\sum_{i \in I_t} g_{m,i}w_{t}+ \frac{1}{2}\sum_{i \in I_t} h_{m,i}w_{t}^2) + \gamma T + \frac{1}{2}\lambda\sum_{t=1}^{T}w_t^2
=t=1∑T(i∈It∑gm,iwt+21i∈It∑hm,iwt2)+γT+21λt=1∑Twt2分数越小越好
6 例:树的分数
7 建树
∙ \bullet ∙ 枚举可能的树结构,根据公式 J ( ϕ ( x ) ) = − 1 2 ∑ t = 1 T G t 2 H t + λ + γ T J(\phi(x)) = -\frac{1}{2}\sum_{t=1}^{T}\frac{G_t^2}{H_t + \lambda} + \gamma T J(ϕ(x))=−21∑t=1THt+λGt2+γT计算结构分数,选择分数最小的树结构,并且并且运用最有的权重/分数(这里的权重/分数指的是叶子结点的分数 w w w吗?如果是的话,好像没有讲过如果确定最优?上边只有通过令导数为0,得到的 w w w。)但是树的结构有很多种可能,枚举所有可能不现实,对此可以采用贪心算法。贪心算法的具体概念是什么,贪心二字又是如何体现的?不管如何,之前理解的贪心算法类似于穷举,从这里来看,这样的理解是不正确的。
8 建树(cont.)
∙
\bullet
∙ 实践中,我们贪婪的增加树的叶子结点数目:
∙
\bullet
∙ (1)从深度为0的树开始。注意:深度定义:对于任意节点n,n的深度为从根到n的唯一路径长,根的深度为0;高度定义:对于任意节点n,n的高度为从n到一片树叶的最长路径长,树叶的高度为0;
∙
\bullet
∙ (2)对于树的每个叶子结点,尝试增加一个分裂点:
∙
\bullet
∙ 另
I
L
I_L
IL和
I
R
I_R
IR分别表示加入分裂点后左右叶子结点的样本集合,
I
=
I
L
∪
I
R
I = I_L \cup I_R
I=IL∪IR,
∙
\bullet
∙
G
L
=
∑
i
∈
I
L
g
m
,
i
,
G
R
=
∑
i
∈
I
R
g
m
,
i
,
H
L
=
∑
i
∈
I
L
h
m
,
i
,
H
R
=
∑
i
∈
I
R
h
m
,
i
G_L = \sum_{i \in I_L}g_{m,i}, G_R = \sum_{i \in I_R}g_{m,i}, H_L = \sum_{i \in I_L}h_{m,i}, H_R = \sum_{i \in I_R}h_{m,i}
GL=∑i∈ILgm,i,GR=∑i∈IRgm,i,HL=∑i∈ILhm,i,HR=∑i∈IRhm,i
∙
\bullet
∙ 则增加分裂点后目标函数的变化为:
G
a
i
n
=
G
L
2
H
L
+
λ
+
G
R
2
H
R
+
λ
−
G
L
2
+
G
R
2
H
L
+
H
R
+
λ
−
γ
Gain = \frac{G_L^2}{H_L + \lambda} + \frac{G_R^2}{H_R + \lambda} - \frac{G_L^2 + G_R^2}{H_L + H_R + \lambda} - \gamma
Gain=HL+λGL2+HR+λGR2−HL+HR+λGL2+GR2−γ(怎么算出来的,是分裂后的结构分数 减去 分别前的结构分数吗?后续补充:是的。但按照这方式去计算,好像结果有点不对啊。之后在算的时候要注意:分裂为2后T就变味了2。)
∙
\bullet
∙ 但是该怎么找到最有的分裂点呢?
9 建树——精确搜索算法
∙
\bullet
∙ 对每一个结点,穷举所有特征、所有可能的分裂点
∙
\bullet
∙ 对每个特征,通过特征值将实例进行排序
∙
\bullet
∙ 运用先行扫描来寻找该特征的最优分裂点。不好理解这句话,老师讲的就是,循环检查各个特征取值中间的点,那要是连续型的实数类特征,这样的取值点就会特别多吧。
∙
\bullet
∙ 对所有特征,采用最佳分裂点。
∙
\bullet
∙ 深度为
k
k
k的树的时间复杂度:
∙
\bullet
∙ 对于一层排序,需要时间
N
l
o
g
(
N
)
Nlog(N)
Nlog(N),N为样本树。查过资料,长度为N的序列进行排序,复杂度取决于具体的算法,
N
l
o
g
(
N
)
Nlog(N)
Nlog(N)应该是最好的一种(不是很确定)。老师也说到这个复杂度是快速排序法的复杂度。
∙
\bullet
∙ 由于有D个特征,k层,所以为
k
D
N
l
o
g
(
N
)
kDNlog(N)
kDNlog(N)。一个特征的全体数据集排序,是Nlog(N),D个特征,就应该是DNlog(N)。但除根节点外,各层节点包含的并不是整个数据集的样本,计算方式不是简单的在DNlog(N)基础上乘k,应该是通过一定的推导变形才能得到
k
D
N
l
o
g
(
N
)
kDNlog(N)
kDNlog(N)。
应将此处(包括本节后文)讲的树结构构造方式,和之前决策数那一章讲的构造方式进行比较。上章图片是精确搜索的算法,老师没怎么讲。
10 建树——近似搜索算法
当数据太多不能装载到内存时,不能进行精确搜索分裂,只能近似
∙
\bullet
∙ 根据特征分布的百分位数,提出特征的一些候选分裂点。老师:使得划分到每个区间的样本数相等。
∙
\bullet
∙ 将连续特征值映射到桶里(候选点对应的分裂),然后根据桶里样本的统计量,从这些候选中选择最佳分裂点。老师:以特征取值等分成一组区间,类似于直方图,所以XGBoost支持直方图近似建树,之后要讲的LightGBM也支持直方图快速建树。
根据候选提出的时间,分为
∙
\bullet
∙ 全局近似:在构造树的初始阶段提出所有的候选分裂点,然后对各层次采用相同的候选
∙
\bullet
∙ 提出候选的次数少,但每次候选的数目多(因为候选不更新)。老师大致的意思是:这种方式的候选特征需要覆盖更大的范围,所以就需要更多的候选数目
∙
\bullet
∙ 局部近似:在每次分裂都重新提出候选。
∙
\bullet
∙ 对层次较深的树更适合。为什么,是不是因为层次较深,分裂到最后,结点的样本就少,若候选分裂点太多,而真正需要的又很少,就会造成很大的计算资源的浪费
老师:在XGBoost里,树一般不会太深,所以还是全局近似用的更广一些
∙
\bullet
∙ 近似搜索的伪代码算法
11 建树—稀疏特征
∙
\bullet
∙ 在实际任务中,极有可能遇到稀疏特征,比如有些数据可能会缺失,用one-hot编码这样人工设计的特征,这些都是稀疏数据的来源。
∙
\bullet
∙ XGBoost处理稀疏特征的方法:在树的每个节点设置一个缺省方向,具体选择哪边也没有一个好的办法,就是左边试一下,右边试一下,看哪边好。注意:是每个节点,也就是说,每个节点的缺省方向可能不一样。
∙
\bullet
∙ 下面的这个PPT没讲
12 剪枝
∙ \bullet ∙ 分裂的增益: G a i n = G L 2 H L + λ + G R 2 H R + λ − G L 2 + G R 2 H L + H R + λ − γ Gain = \frac{G_L^2}{H_L + \lambda} + \frac{G_R^2}{H_R + \lambda} - \frac{G_L^2 + G_R^2}{H_L + H_R + \lambda} - \gamma Gain=HL+λGL2+HR+λGR2−HL+HR+λGL2+GR2−γ,如果前边三项足够小,小于 γ \gamma γ,最后就是负数,这说明分裂后分数反倒变小了。可是之前还说,分数越小越好啊,如何来理解这句话呢?。 − γ -\gamma −γ的项是因为引入新叶子有复杂度惩罚。
∙
\bullet
∙ 提前终止
∙
\bullet
∙ 如果出现负值,提前停止(scikit-learn中采用该策略)
∙
\bullet
∙ 但陪提前终止掉的分裂可能其后续的分裂会带来好处。
∙
\bullet
∙ 过后剪枝
∙
\bullet
∙ 将树分裂到最大深度,然后再基于上述增益计算剪枝
∙
\bullet
∙ 有必要:在实现时还有学习率/收缩,给后续轮留机会(老师讲的是留空间),进一步防止过拟合:
f
m
(
x
i
)
=
f
m
−
1
(
x
i
)
+
η
ϕ
m
(
x
i
)
f_m(\mathbf x_i) = f_{m-1}(\mathbf x_i) + \eta\phi_m(\mathbf x_i)
fm(xi)=fm−1(xi)+ηϕm(xi)。完全没听懂学习率跟剪枝存在怎样的因果关系
∙
\bullet
∙ Scikit-Learn中的决策树,没有剪枝,只有过早停止。