数据分析(五)Boosting 集成模型:AdaBoost 与 GBDT(上)
这一讲是关于两个最常见的集成模型的具体实现原理—— AdaBoost 和 GBDT。理解原理的用处,是为了能明白模型的局限性和适用场景,在出问题时能尽快地定位到核心问题所在。再次提醒,由于主流上当我们谈及集成模型时,主要是指分类集成模型,所以下面所有的措辞都是用分类器相关的说法。That’s pretty much it. Let’s get started! 内容略长,分为上下篇,上篇为 AdaBoost,下篇为 GBDT 。
Boosting 提升算法
在了解 AdaBoost 与 GBDT 之前,需要先了解其所在的大家族:Boosting 提升算法。Boosting 提升算法跟集成模型是一个东西的不同叫法而已,大家都懂。其核心思想可以理解为利用【弱分类器】(也就是简单模型)集成【强分类器】。对于一个具体的 Boosting 算法,使用的弱分类器一般是固定的一种(比如 AdaBoost 可以用决策树),但是集成过程会生成弱分类器的多个实例。
关于 Boosting 算法,网上的资料质量参差不齐,个人认为 这篇文章 写得非常好。里面提到两个概念:加法模型和前向分步算法。
加法模型
加法模型是指强分类器由一系列的弱分类器线性相加而成,如这种组合:
G
(
x
)
=
∑
t
=
1
T
α
t
G
t
(
x
)
G(x)=\sum_{t=1}^T \alpha_t G_t (x)
G ( x ) = t = 1 ∑ T α t G t ( x )
其中
G
t
(
x
)
G_t(x)
G t ( x ) 是指过程中生成的所有弱分类器的实例,
α
t
\alpha_t
α t 是指每个弱分类器对应的权重,
G
(
x
)
G(x)
G ( x ) 就是最终我们要的强分类器(虽然通常还要有最后一步的转化过程)。
BTW,在 Bagging 集成模型中,
α
\alpha
α 相当于取为
1
T
\frac{1}{T}
T 1 。
前向分步
前向分步是指在集成的过程中,后一轮迭代产生的(“准”强)分类器是根据前一轮迭代的结果确定的,把上面的加法模型拆开,其实就可以看出每一次迭代后的结果,都是【上一次迭代的结果】加上【本次迭代所生成的弱分类器乘上其权重】:
G
(
x
)
=
(
∑
t
=
1
T
−
1
α
t
G
t
(
x
)
)
+
α
T
G
T
(
x
)
=
G
∗
(
x
)
+
α
T
G
T
(
x
)
G(x) = (\sum_{t=1}^{T-1} \alpha_t G_t(x)) +\alpha_T G_T(x) = G^*(x)+\alpha_T G_T(x)
G ( x ) = ( t = 1 ∑ T − 1 α t G t ( x ) ) + α T G T ( x ) = G ∗ ( x ) + α T G T ( x )
这个模式在推导 AdaBoost 等具体算法的原理时就会派上用场。
AdaBoost
主要思想
损失函数为指数型
每一轮迭代都是随机采样,每个样本被采样的概率(本文称为权重)可能不同
根据每轮迭代的结果,修改样本的权重(体现在随机采样的过程),以及确定当前弱分类器在最终结果中所占的权重
对上一点的补充:上一轮被正确分类的样本,在下一轮中权重下降,因此可以将分类重心转移到被误分的样本上;分类正确率高的弱分类器所占的权重较高,也就是在所有弱分类器中较有表决权
算法框架
不妨记样本集的形式为
(
x
1
,
y
1
)
,
.
.
.
,
(
x
n
,
y
n
)
(x_1, y_1), ..., (x_n, y_n)
( x 1 , y 1 ) , . . . , ( x n , y n ) ,其中
x
i
x_i
x i 指特征,
y
i
y_i
y i 指分类标签 。则算法框架 可表述为:
初始化样本权重:
w
i
0
=
1
n
,
i
=
1
,
2
,
.
.
.
,
n
w_i^0 = \frac{1}{n}, i = 1, 2, ..., n
w i 0 = n 1 , i = 1 , 2 , . . . , n
for t = 0:T
根据权重
w
i
t
w_i^t
w i t 在样本中随机选择若干样本,训练弱分类器
G
t
(
x
)
G_t(x)
G t ( x )
计算当前弱分类器的分类误差:
ϵ
t
=
∑
i
=
1
n
w
i
t
I
(
y
i
≠
G
t
(
x
i
)
)
∑
i
=
1
n
w
i
t
\epsilon_t = \frac{ \sum_{i=1}^n w_i^t I(y_i \neq G_t(x_i))}{\sum_{i=1}^nw_i^t}
ϵ t = ∑ i = 1 n w i t ∑ i = 1 n w i t I ( y i ̸ = G t ( x i ) ) ,其中当
y
i
≠
G
t
(
x
i
)
y_i \neq G_t(x_i)
y i ̸ = G t ( x i ) 时,
I
(
y
i
≠
G
t
(
x
i
)
)
=
1
I(y_i \neq G_t(x_i)) =1
I ( y i ̸ = G t ( x i ) ) = 1 ,当
y
i
=
G
t
(
x
i
)
y_i = G_t(x_i)
y i = G t ( x i ) 时,
I
(
y
i
≠
G
t
(
x
i
)
)
=
0
I(y_i \neq G_t(x_i)) =0
I ( y i ̸ = G t ( x i ) ) = 0
根据分类误差计算当前弱分类器的权重:
α
t
=
1
2
log
1
−
ϵ
t
ϵ
t
\alpha_t = \frac{1}{2} \log{\frac{1-\epsilon_t}{\epsilon_t}}
α t = 2 1 log ϵ t 1 − ϵ t
根据弱分类器的权重更新样本权重:
w
i
t
+
1
=
w
i
t
exp
(
−
α
t
y
i
G
t
(
x
i
)
)
Z
t
w_i^{t+1}=\frac{w_i^t \exp(-\alpha_t y_i G_t(x_i))}{Z_t}
w i t + 1 = Z t w i t exp ( − α t y i G t ( x i ) ) ,其中
Z
t
=
∑
i
=
1
n
exp
(
−
α
t
y
i
G
t
(
x
i
)
)
Z_t = \sum_{i=1}^n \exp(-\alpha_t y_i G_t(x_i))
Z t = ∑ i = 1 n exp ( − α t y i G t ( x i ) ) 为归一化因子
end for
输出:
G
(
x
)
=
s
i
g
n
[
∑
t
=
1
T
α
t
G
t
(
x
)
]
G(x) = sign[\sum_{t=1}^T \alpha_t G_t(x)]
G ( x ) = s i g n [ ∑ t = 1 T α t G t ( x ) ]
从这个算法框架中我们能看出一些性质:
当前弱分类器的权重,与当前弱分类器的分类误差直接关联,分类误差越小,权重越大(不妨自己试试将分类误差为 0.0,0.5,1.0 分别代入看看);
假设
ϵ
t
<
0.5
\epsilon_t < 0.5
ϵ t < 0 . 5 ,即
α
t
>
0
\alpha_t > 0
α t > 0 (也就是分类器效果优于随机瞎猜),以二分类即标签为(1, -1)为例说明样本权重:对于每个样本而言,当弱分类器将其正确分类时,
y
i
G
t
(
x
i
)
=
1
y_iG_t(x_i)=1
y i G t ( x i ) = 1 ,因此
exp
(
−
α
t
y
i
G
t
(
x
i
)
)
=
exp
(
−
α
t
)
<
1
\exp(-\alpha_t y_i G_t(x_i))=\exp(-\alpha_t)<1
exp ( − α t y i G t ( x i ) ) = exp ( − α t ) < 1 ,其在下一轮迭代中的权重下降;当弱分类器将其错误分类时,
y
i
G
t
(
x
i
)
=
−
1
y_iG_t(x_i)=-1
y i G t ( x i ) = − 1 ,因此
exp
(
−
α
t
y
i
G
t
(
x
i
)
)
=
exp
(
α
t
)
>
1
\exp(-\alpha_t y_i G_t(x_i))=\exp(\alpha_t)>1
exp ( − α t y i G t ( x i ) ) = exp ( α t ) > 1 ,其在下一轮迭代中的权重上升。当
ϵ
t
>
=
0.5
\epsilon_t >= 0.5
ϵ t > = 0 . 5 ,即
α
t
<
=
0
\alpha_t <= 0
α t < = 0 时,就是说分类器刚好猜反了(zhen de sao),所以以上推导过程刚好反过来成立。
示意图
我们用一个图形样例来示意这个过程:
初始样本状态为
D
1
D_1
D 1 :
第一轮迭代,误分了 3 个正样本,调整样本权重为
D
2
D_2
D 2 :
第二轮迭代,误分了 3 个负样本,调整样本权重为
D
3
D_3
D 3 :
第三轮迭代,误分了 2 个正样本,1 个负样本,调整样本权重为
D
4
D_4
D 4 :
最终的集成分类器:
AdaBoost 的优缺点
优点:分类精度相对单个弱分类器更高;使用简单,只需要选定弱分类器及其个数即可;能较好地防止过拟合
缺点:因为中间过程样本权重的调整过程是不可见的,模型的可解释性降低了许多;对异常值敏感;当弱分类器太复杂或分类效果太差时也会过拟合
原理推导
有心学习的伙伴看到这或许会好奇这个算法中用到的公式,到底是如何得来的。下面介绍其推导过程。
回顾下前面的前向分步:
G
(
x
)
=
(
∑
t
=
1
T
−
1
α
t
G
t
(
x
)
)
+
α
T
G
T
(
x
)
=
G
∗
(
x
)
+
α
T
G
T
(
x
)
G(x) = (\sum_{t=1}^{T-1} \alpha_t G_t(x)) +\alpha_T G_T(x) = G^*(x)+\alpha_T G_T(x)
G ( x ) = ( t = 1 ∑ T − 1 α t G t ( x ) ) + α T G T ( x ) = G ∗ ( x ) + α T G T ( x )
不妨记
g
n
(
x
)
=
∑
t
=
1
n
α
t
G
t
(
x
)
g_n(x) = \sum_{t=1}^{n} \alpha_t G_t(x)
g n ( x ) = ∑ t = 1 n α t G t ( x ) ,则上式更合理的表述方式为:
g
T
(
x
)
=
g
T
−
1
(
x
)
+
α
T
G
T
(
x
)
g_T(x) = g_{T-1}(x) +\alpha_T G_T(x)
g T ( x ) = g T − 1 ( x ) + α T G T ( x ) 推广到每一步迭代就是
g
t
(
x
)
=
g
t
−
1
(
x
)
+
α
t
G
t
(
x
)
g_t(x) = g_{t-1}(x) +\alpha_t G_t(x)
g t ( x ) = g t − 1 ( x ) + α t G t ( x )
在 AdaBoost 中,使用到的损失函数是
C
o
s
t
(
x
,
y
)
=
∑
i
=
1
n
exp
(
−
y
i
g
t
(
x
i
)
)
=
∑
i
=
1
n
exp
(
−
y
i
(
g
t
−
1
(
x
i
)
+
α
t
G
t
(
x
i
)
)
)
=
∑
i
=
1
n
exp
(
−
y
i
g
t
−
1
(
x
i
)
)
exp
(
−
y
i
α
t
G
t
(
x
i
)
)
Cost(x, y) = \sum_{i=1}^n \exp(-y_i g_t(x_i)) = \sum_{i=1}^n \exp(-y_i (g_{t-1}(x_i)+\alpha_t G_t(x_i))) = \sum_{i=1}^n \exp(-y_i g_{t-1}(x_i)) \exp(-y_i \alpha_t G_t(x_i))
C o s t ( x , y ) = i = 1 ∑ n exp ( − y i g t ( x i ) ) = i = 1 ∑ n exp ( − y i ( g t − 1 ( x i ) + α t G t ( x i ) ) ) = i = 1 ∑ n exp ( − y i g t − 1 ( x i ) ) exp ( − y i α t G t ( x i ) ) 如果记
w
i
t
=
exp
(
−
y
i
g
t
−
1
(
x
i
)
)
w_i^t=\exp(-y_i g_{t-1}(x_i))
w i t = exp ( − y i g t − 1 ( x i ) ) ,可以发现
w
i
t
=
exp
(
−
y
i
g
t
−
2
(
x
i
)
−
y
i
α
t
−
1
G
t
−
1
(
x
i
)
)
=
w
i
t
−
1
exp
(
−
y
i
α
t
−
1
G
t
−
1
(
x
i
)
)
w_i^t = \exp(-y_i g_{t-2}(x_i)-y_i\alpha_{t-1}G_{t-1}(x_i))=w_i^{t-1} \exp(-y_i \alpha_{t-1} G_{t-1}(x_i))
w i t = exp ( − y i g t − 2 ( x i ) − y i α t − 1 G t − 1 ( x i ) ) = w i t − 1 exp ( − y i α t − 1 G t − 1 ( x i ) ) 到这里,与上面的算法一比较,就不难理解权重的迭代公式是怎么来的了。归一化是为了方便计算。
如果你理解了权重的迭代原理,那你下一个要好奇自然就是这个
α
t
\alpha_t
α t 要怎么计算。显然,我们的最终目标是最小化损失函数,在数学上可以通过对
α
t
\alpha_t
α t 求导来找到最小化损失函数的
α
t
\alpha_t
α t 。注意!下面的过程一定、一定、一定要小心推导 !
首先求损失函数的偏导数:
∂
C
o
s
t
∂
α
t
=
∑
i
=
1
n
w
i
t
(
−
y
i
G
t
(
x
i
)
)
exp
(
−
y
i
α
t
G
t
(
x
i
)
)
=
∑
i
=
1
n
w
i
t
(
−
y
i
G
t
(
x
i
)
)
exp
(
−
y
i
α
t
G
t
(
x
i
)
)
∑
i
=
1
n
w
i
t
=
∑
y
i
=
G
t
(
x
i
)
w
i
t
(
−
1
)
exp
(
−
α
t
)
+
+
∑
y
i
≠
G
t
(
x
i
)
w
i
t
exp
(
α
t
)
∑
i
=
1
n
w
i
t
=
(
ϵ
t
−
1
)
exp
(
−
α
t
)
+
ϵ
t
exp
(
α
t
)
\frac{\partial Cost}{\partial \alpha_t} = \sum_{i=1}^n w_i^t (-y_i G_t(x_i))\exp(-y_i\alpha_tG_t(x_i)) \newline = \frac{\sum_{i=1}^n w_i^t (-y_i G_t(x_i))\exp(-y_i\alpha_tG_t(x_i))}{\sum_{i=1}^nw_i^t} \newline = \frac{\sum_{y_i=G_t(x_i)} w_i^t (-1)\exp(-\alpha_t) + +\sum_{y_i \neq G_t(x_i)} w_i^t \exp(\alpha_t)}{\sum_{i=1}^nw_i^t} \newline = (\epsilon_t - 1)\exp(-\alpha_t)+\epsilon_t \exp(\alpha_t)
∂ α t ∂ C o s t = i = 1 ∑ n w i t ( − y i G t ( x i ) ) exp ( − y i α t G t ( x i ) ) = ∑ i = 1 n w i t ∑ i = 1 n w i t ( − y i G t ( x i ) ) exp ( − y i α t G t ( x i ) ) = ∑ i = 1 n w i t ∑ y i = G t ( x i ) w i t ( − 1 ) exp ( − α t ) + + ∑ y i ̸ = G t ( x i ) w i t exp ( α t ) = ( ϵ t − 1 ) exp ( − α t ) + ϵ t exp ( α t )
令该导数为零,得
(
ϵ
t
−
1
)
+
ϵ
t
exp
(
2
α
t
)
=
0
(\epsilon_t - 1)+\epsilon_t \exp(2\alpha_t)=0
( ϵ t − 1 ) + ϵ t exp ( 2 α t ) = 0 从而
α
t
=
1
2
ln
1
−
ϵ
t
ϵ
t
\alpha_t= \frac{1}{2} \ln \frac{1-\epsilon_t}{\epsilon_t}
α t = 2 1 ln ϵ t 1 − ϵ t
在算法的世界里,对数无差别,所以我们更经常见到的表示方式为
α
t
=
1
2
log
1
−
ϵ
t
ϵ
t
\alpha_t= \frac{1}{2} \log \frac{1-\epsilon_t}{\epsilon_t}
α t = 2 1 log ϵ t 1 − ϵ t
恭喜你,至此你可以算是理解了 AdaBoost 的原理了。How nice!