创建时间:2024-12-09
首发时间:2024-12-09
最后编辑时间:2024-12-09
作者:Geeker_LStar
嘿嘿,你好呀!我又来啦~~
前面我们讲完了集成学习之 Boooooosting,这篇我们来看看集成学习的另一个分支——Bagging!
(嗯这篇的数学也简单,感觉集成学习这块的数学都相对简单嘿嘿~)
这是之前两篇关于 Boosting 的文章:
【高中生讲机器学习】26. 梯度提升树 GBDT 超详细讲解!
【高中生讲机器学习】25. AdaBoost 算法详解+推导来啦!
嗯,那我们开始这一篇吧~!(我觉得这会是整个专栏中第二简单的一篇哈哈哈哈哈((
Bagging 主要思想
嗯! 我们还是从 Bagging 的主要思想说起。
在第 24 篇(集成学习概述)中我说过,模型训练的过程主要会遇到两个困难——高方差和高偏差。前者主要代表过拟合,后者则主要代表欠拟合。而集成学习的两个分支——Bagging 和 Boosting,就是分别来解决这两个问题的。
和 Boosting 主要关注降低模型的偏差不同,Bagging 主要关注降低模型的方差,所以它使用的基学习器通常是深层决策树(容易过拟合,造成低偏差、高方差的情况)。
同样,和 Boosting 的串行生成,即每个基学习器都在前一个基学习器的基础上生成不同,Bagging 采用的并行生成策略,即所有的基学习器同时生成,不涉及到根据前一个基学习器动态调整权重或拟合负梯度这样的情况。
Bagging 的核心在于三个字——多样性。一个基学习器会过拟合,那我就训练出很多很多个,再综合考量它们的结果,这样不就能缓解过拟合了吗?
于是问题来了:现在的数据集只有这么多,怎么利用这个有限的数据集训练出很多不同的决策树?
显然,如果让所有的决策树都在这一整个数据集上训练,那最终训练出来的每棵树不会有任何区别,我们也就没必要把它们组合起来了。
所以,我们必须要让每棵树的训练数据有所区别。
Bagging 很聪明,既然不能所有树都在相同的数据(数据集中所有的数据)上进行训练,那就让每棵树都在从原始数据集中随机抽取的样本上训练,这样每棵树训练出来就都是不同的了。
well 这就涉及到了一些更细节的问题/…
——数据抽取的过程具体是怎么样的?
啊这个问题看起来很蠢()但是还是需要 clarify 一下的(clarify 之后你就会发现这个问题一点也不蠢,相反,它还很重要!)
注意,在下面的讨论中,我们讨论的都是对于一棵树的情况。换言之,下面所说的数据抽取的流程,是给一棵树抽取训练集的流程。
有一点是需要提前明确的。在 Bagging 中,无论我们训练多少棵树,每棵树的训练样本集的大小和原始数据集的大小都是一样的。换言之,我可能训练了 100 棵树,这 100 棵树的训练集大小都是一样的,都等于原始数据集的大小。
诶这是怎么做到的? M M M 棵树对应的 M M M 个训练数据集大小都和原始数据数据集一样,但这 M M M 个训练数据集又彼此不相同…
好好好我们接着说 Bagging 的抽样方法,然后这个问题就很好解释啦~
Bagging 中的抽取是有放回的。即,第一次我抽取了一个样本 x 1 x_1 x1,在下一次抽取之前,我会把 x 1 x_1 x1 放回去。换言之,每次抽取都是在原始的完整数据集中抽取的。
这也很好理解,如果我不放回,那最终抽取得到的还是原始数据集,所以每次抽取完肯定都要放回。
举个例子,比如现在原始数据集中有五个数据
{
x
1
,
x
2
,
x
3
,
x
4
,
x
5
}
\{x_1, x_2, x_3, x_4, x_5\}
{x1,x2,x3,x4,x5}.
第一次抽取的时候,抽出了
x
1
x_1
x1,然后把它放回去了。
第二次,抽出了
x
4
x_4
x4,又放回去了。
第三次,诶可能又抽取到了
x
1
x_1
x1!
第四次,
x
2
x_2
x2。
第五次,可能还是
x
2
x_2
x2。
这样,我们抽取出的数据其实只有 x 1 , x 2 , x 4 x_1, x_2, x_4 x1,x2,x4。 x 3 , x 5 x_3, x_5 x3,x5 没有被抽到。
ok,那么,按照这样的思路,第一棵树的训练集就是
x
1
,
x
4
,
x
1
,
x
2
,
x
2
x_1, x_4, x_1, x_2, x_2
x1,x4,x1,x2,x2.
然后,我们按照有放回抽样的逻辑,继续给第二棵树抽取训练集,这次抽取到的可能是
x
3
,
x
4
,
x
5
,
x
3
,
x
1
x_3, x_4, x_5, x_3, x_1
x3,x4,x5,x3,x1。
嘿嘿,发现了吗,使用有放回抽样,我们就可以让每个树的训练集都不同,但因为是从同一个原始训练集中抽取得到的,所以又会有所重合。
简言概括,Bagging 的数据抽取方式保证了,它训练出来的每棵树都有所重合,但又不完全相同。 这能够帮助它实现对方差的降低。
ooiiioo 注意(奇怪的拟声词越来越多了? ),虽然上面这个说法听起来好像是,抽取数据训练完第一棵树之后再抽取数据并训练第二棵树,但实际上不是这样的。
在 Bagging 中,所有数据抽取都是在开始训练前(并行)。也就是说,如果我计划训练
M
M
M 棵树,那我会在开始训练之前用有放回抽样抽出
M
M
M 组数据,然后开始并行地训练。
嗷对了,这种方法其实还有一个优势。
我们可以证明,虽然对于每棵树,我们都使用有放回抽样抽取了和原始数据集一样大小的数据集作为训练数据集,但是,原始数据集中依然有一部分数据没有被抽到(也就是不会被作为这棵树的训练集),并且,这部分数据的占比还不少!(证明我放在了下一部分,这一部分我们不提数学())
(就像刚才那个例子, x 3 , x 5 x_3, x_5 x3,x5 就没有被抽取到,也就是说,它们就不会成为第一棵的训练数据。
那这些数据怎么办??
其实,它们完全可以用于测试诶! 因为它们没有被这棵树学习过。
这里先剧透一下,对于每一棵树,最终会有大概
36.8
%
36.8\%
36.8% 的数据没有被它学习过,这些数据就是天然的测试数据,我们就不用再额外寻找测试数据了!!
这些没有被取到的数据被称为袋外数据(out of bag, OOB),我们可以直接在这些袋外数据上进行测试~!
(另外,你可以尝试“注意到”一下,0.368 这个数字很特殊哦…(((哈哈哈哈这里就不剧透过多了(
从上面说过的所有和数据抽取相关的内容出发举个例子,我现在一共有 100 个数据,训练第一棵树的时候,我使用有放回抽样,获得了大小为 100 的训练集;训练第二棵树的时候,又获得了大小为 100 的训练集(注意第二次抽取和第一次抽取是完全独立的);以此类推,并行训练完所有的树。
训练完以后,我发现,诶,(比如对于第一棵树),好像有 37 个数据没有被它抽取到(不在它的训练集里)诶。这些数据就可以用来当作测试数据,测试这棵树的性能。
okay,现在假设我们已经训练完所有的树了,接下来就是推理,或者说测试了。
Bagging 的推理很简单,给定一个样本,让所有训练出来的树分别预测(类别 or 值),再对所有树给出的结果多数表决(分类)或取平均值(回归),就得到了最终的结果。
比如说,我训练了四棵树,有 3 棵对于测试样本的类别预测为 A,剩下的 1 棵对于测试样本的类别预测为 B,那么最终这个样本就会被预测为 A(简单的多数表决~)。
enenen,以上就是 Bagging 算法的基本思路!! 是不是感觉比 Boosting 简单一些()
Bagging 的总体流程可以概括如下图:
我们来小小总结一下,Bagging 作为集成学习的另一分支,它的特点如下:
- 并行训练:Bagging 中每个基学习器都是并行训练的,基学习器之间彼此独立,不涉及到后一个基学习器在前一个基学习器的基础上进行调整的步骤。
- 部分样本训练:Bagging 在训练每棵树的时候只会使用原始训练集中部分的数据进行训练,保证了训练出来的树的多样性。
- 有放回抽取:Bagging 每抽取完一个数据都会把它再放回去,下次抽取依然是从原始的数据集中抽取。这导致,对于每棵树,大概有 36.8 % 36.8\% 36.8% 的原始数据集中的数据不会被作为训练数据。
- 袋外数据:对于每棵树,没有被抽取到训练集中的那 36.8 % 36.8\% 36.8% 的数据可以作为测试数据,评估这棵树在整体数据集上的表现。
其实,Bagging 的数学叙述也比 Boosting 简单,我们来看看…(这是什么生硬的转折啊不是)(()
数学叙述
这一部分我们给出 Bagging 算法的数学叙述,包括一些必要的证明。
首先我们规定一些 notation。
我们规定,原始数据集
D
D
D 的大小为
N
N
N,即
D
=
{
x
1
,
x
2
,
.
.
.
,
x
N
}
D=\{x_1, x_2, ..., x_N\}
D={x1,x2,...,xN};我们要训练
M
M
M 个基学习器(映射)
T
=
{
f
1
,
f
2
,
.
.
.
,
f
M
}
T=\{f_1, f_2, ..., f_M\}
T={f1,f2,...,fM}。
首先是有放回抽样得到训练数据集。对于 M M M 个基学习器,我们都从 D D D 中有放回地抽取 N N N 个数据构成训练数据集。
上一部分我们说到,对于一棵树来说,(在样本量较大的时候)平均来讲会有 36.8 % 36.8\% 36.8% 的数据没有被它抽到。上一部分我们省略了证明,下面我们来证一下。
我们一共有 N N N 个数据,那么,对于其中任意一个数据 x i x_i xi,它在某次抽取中被抽到的概率就是 1 N \frac 1 N N1,不被抽到的概率就是 1 − 1 N 1-\frac 1 N 1−N1.
well,因为最终需要
N
N
N 个数据,所以我们一共抽取
N
N
N 次。
这样,
x
i
x_i
xi 在这
N
N
N 次都没有被抽到的概率就可以表示为:
(
1
−
1
N
)
N
(1-\frac 1 N)^N
(1−N1)N
我们考虑最极端的情况,也就是 N N N 趋于无穷大时候的情况。至于这么考虑的道理,后面会揭晓的,嘿嘿。
也就是说,我们想要得到下面这个式子的值:
lim
N
→
∞
(
1
−
1
N
)
N
\lim_{N \to \infty} (1-\frac 1 N)^N
N→∞lim(1−N1)N
weeeeell…
如果你学过高数或者数列的话,你可能见过这个式子,并且知道它的收敛于
1
e
\frac 1 e
e1。这是一个很妙的结论,在这里我给出一个证明。
首先我们先取个 ln \ln ln 把指数变成对数。
lim N → ∞ ( 1 − 1 N ) N = lim N → ∞ exp ( N ln ( 1 − 1 N ) ) \begin{align} & \lim_{N \to \infty} \left( 1 - \frac{1}{N} \right)^N \\ & = \lim_{N \to \infty} \exp \left( N \ln \left( 1 - \frac{1}{N} \right) \right) \\ \end{align} N→∞lim(1−N1)N=N→∞limexp(Nln(1−N1))
然后,我们使用一个近似,当
x
→
0
x \to 0
x→0 时,
ln
(
1
+
x
)
→
x
\ln (1+x) \to x
ln(1+x)→x.
这个近似可以通过泰勒展开得到,在这里不详细说明了。
因为 N → ∞ N\to\infty N→∞,所以 1 N → 0 \frac 1 N\to0 N1→0,所以 ln ( 1 − 1 N ) → − 1 N \ln (1-\frac 1 N) \to -\frac 1 N ln(1−N1)→−N1.
那么,我们可以进一步化简这个式子了…
=
lim
N
→
∞
exp
(
N
⋅
(
−
1
N
)
)
=
lim
N
→
∞
exp
(
−
1
)
=
exp
(
−
1
)
=
1
e
\begin{align} & = \lim_{N \to \infty} \exp \left( N \cdot \left( -\frac{1}{N} \right) \right) \\ & = \lim_{N \to \infty} \exp \left( -1 \right) \\ & = \exp(-1) \\ & = \frac{1}{e} \end{align}
=N→∞limexp(N⋅(−N1))=N→∞limexp(−1)=exp(−1)=e1
很好!最终我们得到,这个式子收敛于 1 e \frac 1 e e1,也就是大约 0.368 0.368 0.368,或者说 36.8 % 36.8\% 36.8%.
这是说,当 N N N 足够大的时候,有放回地从原始数据集中抽取 N N N 个样本,某个样本始终没有被抽到的概率约为 36.8 % 36.8\% 36.8%。
好的,从这个结论出发…
我们一共有 N N N 个数据,每个数据大约有 36.8 % 36.8\% 36.8% 的概率不被抽到,那么整个数据集就会有大约 N ∗ 1 e N* \frac 1 e N∗e1 的数据不被抽到(期望),也就是大约 36.8 % 36.8\% 36.8% 的数据不被抽到。
也就是说,当 N N N 足够大的时候,在一次有放回抽样中,大约有 36.8 % 36.8\% 36.8% 的样本不会被抽到,或者说一次有放回抽样得到的数据集中通常包含 63.2 % 63.2\% 63.2% 原数据集中的数据。
very nice! 这为有放回抽样提供了理论支持!! 这告诉我们,在最极端的情况下,对于每一棵树,它的训练集中(平均)也只包含了原始数据集的 63.2 % 63.2\% 63.2%。这保证了树之间的多样性,对这些树进行集成,能够比较好地降低方差。
emmm 不过,别忘了我们现在讨论的情况——
N
→
∞
N \to \infty
N→∞.
你可能会想,嗯在这种情况下确实,每棵树的训练集中都会随机地有将近 40% 的原始数据没有被选择,确实能保证树的多样性。但是,如果不是这种情况呢,如果
N
N
N 并不是很大呢?那会不会出现其它的情况,比如每棵树的训练集中都只有很少的原始数据没有被选择到,导致每棵树的训练集很相似…
好好好,其实看一下函数图像什么就都解决了,so 我画了一个:
从图上不难看出,从 N = 6 N=6 N=6 开始,后面就几乎是一条平行于 x x x 轴的直线了,也就说,只要数据量多于 6 个,就问题不大。
实际情况中,数据量显然会多于 6 个呀。。所以没什么问题,有放回抽取是一个非常好的方法!
呃好像这篇的数学内容里有趣的部分到这里就结束了。。。?emm 不过我们还是接着把剩下的数学叙述说完。
豪德,现在 assume(这是我们的一个梗 )我们已经训练完了这
M
M
M 个模型。接下来我们来预测一些新样本…
(和前面我们讲的很多个模型一样)
对于分类问题,我们把
M
M
M 个基学习器给出的最多的类别作为最终的输出值,即:
y
t
=
arg max
c
∑
m
=
1
M
I
(
f
m
(
x
t
)
=
c
)
y_t=\argmax_c \sum_{m=1}^M \mathbb{I}(f_m(x_t)=c)
yt=cargmaxm=1∑MI(fm(xt)=c)
其中 c c c 代表类别; M M M 是基学习器的个数; I \mathbb{I} I 是指示函数,当括号内为真时,函数的值为 1,否则为 0; f m ( x t ) f_m(x_t) fm(xt) 为第 m m m 个基学习器给出的预测(类别)。
对于回归问题,我们把
M
M
M 个基学习器输出的值的平均值作为最终的输出值,即:
y
t
=
1
M
∑
m
=
1
M
f
m
(
x
t
)
y_t=\frac 1 M \sum_{m=1}^M f_m(x_t)
yt=M1m=1∑Mfm(xt)
en,拿到对新数据的预测之后,我们就可以计算损失了。对于分类问题就是交叉熵损失,对于回归问题就是平方损失。
这两种损失的计算在前面的文章当中已经讲过很多遍了,这里就不再单独展开啦~
好耶!现在我们已经把 Bagging 讲完了!
Bagging 其实可以看作一种,或者说一类思想,也可以看作一个基础版本。从它出发,我们可以得到很多变种。随机森林时其中最有代表性也是最被大家所熟知的一种,so 我们接下来来聊聊随机森林!
特例:随机森林
随机森林,Bagging 家族最经典的代表。
不知道你发没发现,虽然前面我们一直 assume Bagging 中的基学习器是决策树,但是我们好像一直没提到决策树的特征选择问题诶()
eee 这也好解释,在 Bagging 中训练决策树的时候,我们默认的都是使用最佳分裂特征。
但是…增加模型的多样性,是不是也可以从分裂特征的角度考虑呢?
关于分裂特征的更多内容:【初中生讲机器学习】13. 决策树算法一万字详解!一篇带你看懂!
更进一步,如果我们像选择数据一样,每次都从所有的分裂特征中选出一部分,再从这一部分中选出最佳分裂特征,是不是也是一种值得的尝试呢?
emmmm 怎么一不小心把随机森林的做法给说出来了()
好吧好吧不卖关子了,,,随机森林的做法就是上面我说到的:在每个分裂点(注意是每个分裂点,而不是每棵树),都从所有的分裂特征中随机选取一部分,形成候选特征集合,然后再从候选特征集合中选出最佳分裂特征。
换言之,随机森林给出的每个分裂点的最佳分裂特征不一定是实际的最佳分裂特征,因为它是从随机选出的候选特征集合中选择分裂特征,而不是从所有特征中选择分裂特征。
所以其实,你可以把随机森林看作加入了特征选择随机性的 Bagging(就这么简单(
eaaa 除此之外随机森林和 Bagging 完全一样,没有什么好说的。
好耶!那其实随机森林也说完了,嘿嘿。
嗯,那我们来总结一下这一篇吧!
Bagging 是集成学习的分支之一,通常以深层决策树作为基学习器,通过组合多个基学习器来降低它们的方差。
Bagging 的多样性(随机性)主要来源于它的有放回抽取策略。这种策略保证了每棵树的训练数据集都是不同的,但又有一定的重合,可以比较有效的避免过拟合。
随机森林在 Bagging 的基础上引入了特征选择的随机性。对于每个分裂节点,它都在原始的所有特征中随机选取一部分作为候选特征子集,再从候选特征子集中选出最优分裂特征。这种做法可以进一步提高基学习器的多样性,防止模型过拟合。
en!! 以上就是 Bagging 和随机森林的全部内容!
啊哈哈哈哈那这篇就到这里啦!感觉是整个系列的最简单的一篇文章((
下一篇可能会接着贝叶斯网络讲马尔可夫网络,嘿嘿,keeeep follow!
这篇文章详细讲解了 Bagging 类算法(及其特例,随机森林)的核心思想,并给出了数学叙述,希望对你有所帮助!⭐
欢迎三连!!一起加油!🎇
——Geeker_LStar