RandomForest详解
第三次写博客,本人数学基础不是太好,如果有幸能得到读者指正,感激不尽,希望能借此机会向大家学习。这一篇的内容来自于各种书籍,以及自己的一些见解。
预备知识:
这一部分主要是谈一谈bootstrap sampling(自助采样法)、Bagging,以及out-of-bag estimate(包外估计)中涉及到的基础数学公式和定理的推导。
bootstrap sampling(自助采样法)
在训练学习器时,我们希望学习器不仅能很好地拟合训练样本,还可以有较低的泛化误差,因此一般采用留出法和交叉验证法,但是这些方法会受到数据规模的影响,尤其是在原始数据很少的情况下,而留一法又会带来将巨大的计算量。因此可以采用自助采样法(bootstrap sampling)。
假设当前有一个含有m个样本的数据集D,我们对其进行m次“有放回的”随机采样,这样得到了大小为m的新数据集D’。可以肯定的是,新数据集必定含有原始数据集中某个样本的重复采样,可以进行下面的估计。
每一轮采样中,样本x被抽到的概率为1/m,因此,在m轮抽样后,该样本仍未被抽取到的概率为:
因此,原始数据集中有大约36.8%的样本没有被抽到,这些样本就可以用于由新数据集D’训练得到的学习器的“包外估计”【3】。
当数据集很小,以至于训练\测试集不能很好地分开时,这种方法比较适用,也为集成学习提供了很多帮助。但是,由于得到的新数据集或多或少的改变了原始数据集的样本分布,自助采样法可能会引入一些误差,因此,当原始数据集足够大时,尽量选用留出法和交叉验证法。
Bagging
在集成学习中,基学习器的“好坏”非常关键,我们希望基学习器们拥有很强大的性能,同时又希望基学习器之间有一定的差异。如果所有基学习器仅通过同一个训练集进行训练,必定不会产生差异。这时就需要通过原始数据集生成多个不同的样本分布的新训练集,我们可以采用自助采样法(bootstrap sampling)来达到这个目的。
Bagging就是通过在每轮迭代中,首先通过自助采样法生成不同的训练集,之后基于这个“新”训练集对基学习器进行训练。最后,集成学习器的预测结果将由T轮迭代后生成的T个基学习器,进行简单的投票法(其他的结合策略见Ensemble Strategy一文)来决定。
Bagging伪代码如下:
与标准Adaboost只能用于二分类任务不同的是,Bagging可以不经修改的用于多分类、回归等任务。
out-of-bag estimate(包外估计)
由于自助采样法产生的新数据集包含大约63.2%的原始样本,因此每轮迭代中,可以使用剩下的36.8%的原始样本对产生的基学习器进行泛化误差的“包外估计”(out-of-bag estimate),减小过拟合的风险,当基学习器是决策树或神经网络时尤其重要。
还可以利用这些未被选做训练样本的原始样本,对集成学习器的泛化误差进行包外估计。假设,Bagging算法产生了T个基学习器 h t h_t ht,其中每个基学习器是由数据集 D t D_t Dt训练得到的, H o o b ( x ) H^{oob}\left(x\right) Hoob(x)是对样本x的包外预测,即仅考虑那些没有使用x的基学习器在x上的预测,可得
则Bagging的泛化误差的包外估计为
其中 ∣ D ∣ |D| ∣D∣为原始数据集D的大小,Y为y的值域。
推导过程:
主要分为三部分:标准的随机森林、比较多变量CART树、Bagging、以多变量CART树作为基学习器的随机森林和随机森林的一些要点。
标准的随机森林
标准随机森林(RF)是以决策树作为基学习器的,一种基于Bagging的拓展算法,在每一轮决策树训练过程中加入了随机属性选择。具体来说,在训练决策树时,是从当前结点的全部属性集合中选择最优的划分属性,而在RF中,对于决策树的每个结点,显示从当前节点的全部属性集合中随机选择一个包含k个属性的子集,之后再从这个子集中选择一个最优的划分属性。毋庸置疑,参数k控制了随机性的引入程度,k越大基学习器的性能越好,但是基学习器之间的独立性会大打折扣;k越小基学习器之间的相关性会降低,但是基学习器的性能也会下降。因此,在很多文献中,这样选择k
作为标准随机森林(RF)的两种形式之一,上述算法也被称为Forest-RI,其中RI指的是Random Input(随机输入选择),这种方法适用于原始候选属性集大小d足够大,且该算法由于大大减少了在每个结点进行划分属性的候选属性数量,因此运行时间大大减少。
但是当d不足够大时,我们就要考虑标准随机森林的另一种形式,即Forest-RC,其中RC指的是Random Combin(随机组合),这种方法通过在每个结点创建候选属性的线性组合,以增加供每个结点进行划分特征选择的候选属性集大小。具体的方法是:从决策树的每个结点的原始候选属性集合中,随机选择L个属性(L < k),之后将这些属性用区间[-1,1]的均匀分布产生的系数进行线性组合,来生成大小为k的候选属性集合,最后从这个集合中选择最优划分属性(线性组合),这样,每个基学习器与多变量决策树类似。
比较多变量CART树、Bagging、以多变量CART树作为基学习器的随机森林
比较多变量CART树、Bagging、以多变量CART树作为基学习器的随机森林(下图从左至右,其中Bagging中每轮训练样本数为原始数据集的一半)
由上面的几幅图可知,随机森林比其他两种算法产生的分类边界更加smooth,并且有类似于最大间隔分类器的分类边界。
在数据集比较复杂时,我们来对Bagging、以多变量CART树作为基学习器的随机森林(下图从左至右,其中Bagging中每轮训练样本数为原始数据集的一半)进行比较。
由上面几幅图可以看出,随机森林比Bagging更加具有鲁棒性。
当数据中再加入一些噪声后,可以得到下面几幅图。
可以看出,随机森林生成的决策边界中,正例中包含一部分被错误标记为负例的噪声样本,因此随机森林还有通过投票修正噪声的优点。
随机森林的一些要点
- Bagging的特点
Bagging主要关注降低方差,因此当基学习器为决策树和神经网络等易受样本扰动的学习器时,Bagging的效果更好,因为这些学习器普遍具有较高的方差。当然也可以在生成基学习器的过程中,使用包外样本提高基学习器的泛化能力。 - 随机森林的多样性
随机森林的多样性不仅来自于样本扰动,还来自于属性扰动,这就使得最终的集成学习器的泛化性能可通过基学习器之间独立性的增加而提升。 - 随机森林的特点
随机森林的起始性能往往比较差,特别是只有一个基学习器时,这是因为基学习器的训练过程中加入了属性扰动,导致基学习器的性能降低。但是,随着基学习器的个数增加,随机森林产生的集成学习器的性能会得到很大的提升,即最终泛化误差会收敛到最小。 - 随机森林的泛化误差
理论证明,当树的数目足够大时,随机森林的泛化误差的上界收敛于下面的表达式
其中 ρ ˉ \bar{\rho} ρˉ是树之间的平均相关系数,s是度量树型分类器的“强度”的量。一组分类器的强度是指分类器的平均性能,而性能以分类器的余量(M)用概率算法度量:
其中 Y θ ^ \hat{Y_{\theta}} Yθ^是根据模随机向量 θ \theta θ构建的分类器对X做出的预测类。余量越大,分类器正确预测给定的样本X的可能性就越大。由泛化误差上界的定义公式可知,随着树的相关性增加或组合分类器的强度降低,泛化误差的上界趋于增加。因此,随机化有助于减少决策树之间的相关性,从而改善组合分类器的泛化误差。
参考资料
【1】《机器学习》
【2】《机器学习实战》
【3】《数据挖掘》
【4】《机器学习技法》
代码实现及对比
下面是我自己实现的代码,这段代码主要实现了Bagging和RandomForest两种集成学习方法,采用CART作为基学习器,由于IRIS数据集作为训练集,因此在之前的CART代码上进行了修改,具体的可以看下面的代码细节,下面对这两个算法的结果进行简要分析。
代码细节
"""
@author: Ἥλιος
@CSDN:https://blog.csdn.net/qq_40793975/article/details/80988486
"""
import numpy as np
import random
import time
# 加载IRIS数据集
def load_IRISdata(filename):
labelMap = {
"Iris-setosa": 1, "Iris-versicolor": 2, "Iris-virginica": 3} # 标记映射
with open(filename) as fr:
dataMat = []
labelMat = []
for data in fr.readlines():
data = [i for i in data.strip().split(",")]
dataMat.append([float(i) for i in data[:-1]])
labelMat.append(data[-1])
dataMat = np.mat(dataMat)
for i in range(np.size(dataMat, axis=0)):
labelMat[i] = labelMap[labelMat[i]]
labelMat = np.mat(labelMat).T
return dataMat, labelMat
allDataMat, allLabel