1. bagging原理
1.1 bootstrap sampling自助采样
自助法(bootstrap)的一个通俗的解释为:有放回抽样。
bootstrap的过程为,对于包含m个样本的数据集D,我们对它进行采样产生数据集D’:每次随机从D中挑选一个样本,将其拷贝放入D’,然后再将该样本放回初始数据集D中,使得该样本在下次采样时仍有可能被采到;这个过程重复执行m次后,我们就得到了包含m个样本的数据集D’,这就是自助采样的结果。
显然,D中有一部分样本会在D’中多次出现,而另一部分样本不出现。可以做一个简单的估计,样本在m次采样中始终不被采到的概率是
(
1
−
1
m
)
m
(1-\frac1m)^m
(1−m1)m,取极限得:
l i m m → ∞ ( 1 − 1 m ) m → 1 e ≈ 0.368 (公式1) lim_{m→∞}(1-\frac1m)^m →\frac1e≈0.368 \tag{公式1} limm→∞(1−m1)m→e1≈0.368(公式1)
即通过自助采样,初始数据集D中约有36.8%得样本未出现在采样数据集D’中。于是我们可将D’作为训练集,D\D’作为测试集;这样,实际评估的模型与期望评估的模型都使用m个训练样本,而我们仍有数据总量约1/3的、没有在训练集中出现的样本用于测试。这样的测试结果,亦称“包外估计”(out-of-bag-estimate)。
1.2 bagging
Bagging直接基于自助采样法(bootstrap)。由公式1可知,初始训练集中约有63.2%的样本出现在采样集中。
照这样,可以采出采样出T个含K个样本的采样集合,然后基于每个采样集合训练出一个基学习器,再将这些基学习器进行结合,这就是Bagging的基本流程。
在对预测输出进行结合式,Bagging通常对分类任务使用简单投票法,对于回归任务使用简单平均法。若分类预测时出现两个类收到同样票数的情形,则最简单的做法是随机选择一个,也可进一步考察学习器投票的置信度来确定最终胜者。
1.3 随机森林
随机森林(Random Forest,简称RF)是Bagging的一个扩展变体。RF在以决策树为基学习器构建Bagging集成的基础上,进一步在决策树的训练过程中引入了随机属性选择。具体来说,传统决策树在选择划分属性时,是在所有属性中选择一个“最优属性”(基于信息熵或信息增益等);而在RF中,基于决策树的每个节点,先从该节点的所有属性的集合中,随机选择一个包含k个属性的子集,然后再从这个子集中选择一个“最优属性”进行划分。一般情况下,
k
=
l
o
g
2
d
k=log_2d
k=log2d。
下面就拿周志华老师的“西瓜数据集2.0”来举个例子。
假设这里我们使用ID3决策树。在决策树开始时,根节点包含D中的所有样例,其中正例占
p
1
=
8
17
p_1=\frac8{17}
p1=178,反例占
p
2
=
9
17
p2=\frac9{17}
p2=179。于是,根节点的信息熵为:
E
n
t
(
D
)
=
−
∑
k
=
1
2
p
k
l
o
g
2
p
k
=
−
(
8
17
l
o
g
2
8
17
+
9
17
l
o
g
2
9
17
)
=
0.998
Ent(D) = -\sum_{k=1}^2p_klog_2p_k=-(\frac8{17}log_2{\frac8{17}}+\frac9{17}log_2{\frac9{17}})=0.998
Ent(D)=−k=1∑2pklog2pk=−(178log2178+179log2179)=0.998
然后对于当前每个属性,我们均要计算出其信息熵,以属性“色泽”为例:
E
n
t
(
色
泽
=
青
绿
)
=
−
(
3
6
l
o
g
2
3
6
+
3
6
l
o
g
2
3
6
)
=
1.000
E
n
t
(
色
泽
=
乌
黑
)
=
−
(
4
6
l
o
g
2
4
6
+
2
6
l
o
g
2
2
6
)
=
0.918
E
n
t
(
色
泽
=
浅
白
)
=
−
(
1
5
l
o
g
2
1
5
+
4
5
l
o
g
2
4
5
)
=
0.722
Ent(色泽=青绿) = -(\frac3{6}log_2{\frac3{6}}+\frac3{6}log_2{\frac3{6}})=1.000 \\ Ent(色泽=乌黑) =-(\frac4{6}log_2{\frac4{6}}+\frac2{6}log_2{\frac2{6}})=0.918 \\ Ent(色泽=浅白) = -(\frac1{5}log_2{\frac1{5}}+\frac4{5}log_2{\frac4{5}})=0.722
Ent(色泽=青绿)=−(63log263+63log263)=1.000Ent(色泽=乌黑)=−(64log264+62log262)=0.918Ent(色泽=浅白)=−(51log251+54log254)=0.722
所以,“色泽”的信息增益为:
G
a
i
n
(
D
,
色
泽
)
=
E
n
t
(
D
)
−
∑
v
=
1
3
∣
D
v
∣
∣
D
∣
E
n
t
(
D
v
)
=
0.998
−
(
6
17
×
1.000
+
6
17
×
0.918
+
5
17
×
0.722
)
=
0.109
\begin{aligned} Gain(D,色泽) &= Ent(D)-\sum_{v=1}^3\frac{|D^v|}{|D|}Ent(D^v)\\ &=0.998-(\frac6{17}\times1.000+\frac6{17}\times0.918+\frac5{17}\times0.722)\\ &=0.109\end{aligned}
Gain(D,色泽)=Ent(D)−v=1∑3∣D∣∣Dv∣Ent(Dv)=0.998−(176×1.000+176×0.918+175×0.722)=0.109
类似的,我们可以计算出其他属性的信息增益:
G
a
i
n
(
D
,
根
蒂
)
=
0.143
;
G
a
i
n
(
D
,
敲
声
)
=
0.141
G
a
i
n
(
D
,
纹
理
)
=
0.381
;
G
a
i
n
(
D
,
脐
部
)
=
0.289
G
a
i
n
(
D
,
根
蒂
)
=
0.006
\begin{aligned} &Gain(D,根蒂)=0.143;\ \ &Gain(D,敲声)=0.141\\ &Gain(D,纹理)=0.381;\ \ &Gain(D,脐部)=0.289\\ &Gain(D,根蒂)=0.006 \end{aligned}
Gain(D,根蒂)=0.143; Gain(D,纹理)=0.381; Gain(D,根蒂)=0.006Gain(D,敲声)=0.141Gain(D,脐部)=0.289
显然,“纹理”的信息增益最大,于是他被选为划分属性,基于“纹理”对根节点进行划分:
这样,我们就完成了对决策树的第一个属性划分。
那么,如果是随机森林呢?假如随机森林使用的也是信息信息增益作为属性选择的策略。根据
k
=
l
o
g
2
d
k=log_2d
k=log2d的原则,这里的d=6,所以在一开始随机选择两个属性。假设这里选择的两个属性为“敲声”和“脐部”,那么在根节点的属性选择上,我们只能在这两个属性中,选择信息增益较大的那一个,则根据信息增益,根节点应当以“脐部”属性作为划分依据:
之后的每个节点属性划分,以此类推。
Bagging+rf 的形式,在采样的时候,使用bootstrap,之后对于每个采样集,再使用随机森林。通过前面的学习我们知道,当个体学习器“异质”时,集成学习可以取得较好效果。bagging分别使用了bootstrap和随机森林,在样本扰动的基础上,又添加了属性扰动,这就导致虽然每个基学习器都是决策树,但取得的结果却有很大差异。这使得最终集成的泛化性能可通过个体学习器之间差异度的增加而进一步提升。
2. bagging的案例分析
# evaluate bagging algorithm for classification
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.ensemble import BaggingClassifier
#创建含有1000个样本,20个属性的分类数据集
X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=5)
# 使用bagging模型
model = BaggingClassifier()
#使用重复的分层k-fold交叉验证来评估该模型,一共重复3次,每次有10个fold。我们将评估该模型在所有重复交叉验证中性能的平均值和标准差。
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
# report performance
print('Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
最终模型的效果是Accuracy: 0.854 标准差0.031