集成学习:Bagging&Boosting思想以及随机森林&GBDT方法介绍
前言
面对一个机器学习问题,通常有两种策略。一种是尝试各种模型,选择最合适的模型做重点调参优化,来达到我们的效果,另外一种就是不花费过多精力在一个模型上,而是多训练几个不太相关的模型,然后综合考量各个模型的结果作最终决策。这两种方法都有体现集成学习的思想,前一种是 b o o s t i n g boosting boosting,而后一种则是 b a g g i n g bagging bagging的思想。本文整理了集成学习的学习资料,并对它们对应的常用的算法模型进行了介绍,希望能对大家有帮助。
一、 B a g g i n g Bagging Bagging& B o o s t i n g Boosting Boosting介绍
1.1 Bagging
B a g g i n g Bagging Bagging方法是一个集体决策的过程,每个个体都进行单独学习,学习的内容可以相同也可以不同,也可以部分重叠,但由于个体之间存在差异性导致每个个体做出的判断也不会完全一致,在最终做决策时,通过投票或者加权的方式做出最终集体决策。 B a g g i n g Bagging Bagging方法在训练过程中各基分类器之间无强依赖,可以进行并行训练。
1.2 Boosting
B o o s t i n g Boosting Boosting的基本思路是将基分类器层层叠加,每一层在训练的时候,对前一层基分类器分错的样本给予更高的权重,测试时根据各层分类器的结果的加权得到最终结果。 B o o s t i n g Boosting Boosting在学习的过程中会针对判断错误的样本数据进行加强学习,以减少类似的错误发生,不断循环往复直到犯错的次数减少到很低的程度。 B o o s t i n g Boosting Boosting方法训练基分类器时采用串行的方式,各个基分类器之间有依赖。
B a g g i n g Bagging Bagging方法采用分而治之的策略,通过对训练样本多次采样,分别训练出不同的模型作综合来减少集成分类器的方差,而 B o o s t i n g Boosting Boosting则通过逐步聚焦于基分类器分错的样本,减小集成分类器的偏差。
二、集成学习的步骤
集成学习一般可分为以下3个步骤:
- 找到误差互相独立的基分类器;
- 训练基分类器;
- 合并基分类器的结果。
合并基分类器的方法有 v o t i n g voting voting和 s t a c k i n g stacking stacking两种。前者是投票的方式,将获得最多选票的结果作为最终的结果,后者是用串行的方式把前一个基分类器的结果输出到下一个分类器,将所有基分类器的输出结果相加作为最终的输出。(或者用更复杂的算法融合,比如把各类基分类器的输出作为特征,使用逻辑回归作为融合模型进行最后的结果预测)
A
d
a
b
o
o
s
t
Adaboost
Adaboost可以明显地看到
B
o
o
s
t
i
n
g
Boosting
Boosting的思想,对分类正确的样本降低了权重,对分类错误的样本升高或者保持权重不变,在最后进行模型融合的过程中,也根据错误率对基分类器进行加权融合。另一个流行的模型是梯度提升决策树(GBDT),其核心思想是每一棵树学的是之前所有树结论和的残差,这个残差就是一个加预测值之后能得真实值得累加量。
B
o
o
s
t
i
n
g
Boosting
Boosting的本质实际上是一个加法模型,通过改变训练样本权重学习多个分类器并进行一些线性组合。而
A
d
a
b
o
o
s
t
Adaboost
Adaboost就是加法模型+指数损失函数+前项分布算法,从弱分类器出发反复训练,在其中不断调整数据权重或者是概率分布,同时提高前一轮被弱分类器误分的样本的权值,最后用分类器进行投票表决(但是分类器的重要性不同)。与Adaboost相比,GBDT回归树的损失函数为平方损失,不过也可以用指数损失函数定义分类问题。
随机森林则属于
B
a
g
g
i
n
g
Bagging
Bagging的代表, 放回抽样, 每个学习器随机选择部分特征去优化,它改变了决策树容易过拟合的问题,这主要是由两个操作所优化的,一是Boostrap从袋内有放回的抽取样本值,二是每次随机抽取一定数量的特征(通常为sqr(n))来构建基分类器。
三、学习模型中的基分类器
正如上面所说,集成学习就是集多个基分类器结果所成,基分类器得选择是集成学习主要步骤中的第一步,也是非常重要的一步。最常用的基分类器是决策树
主要原因是:
- 决策树可以较为方便地将样本得权重整合到训练过程中,而不需要使用过采样的方法来调整样本权重;
- 决策树的表达能力和泛化能力,可以通过调节树的层数来做折中;
- 数据样本的扰动对于决策树的影响较大,因此不同子样本集合生成的决策树基分类器随机性较大,这样的"不稳定学习器"更适合作为基分类器,此外,在决策树节点分裂的时候,随机地选择一个特征子集,从中找出最优分裂属性,很好地引入了随机性。
除了决策树外,神经网络模型也适合作为基分类器,主要由于神经网络模型也比较"不稳定",而且还可以通过调整神经元数量、连接方式、网络层数、初始权重等方式引入随机性。但是要注意的是, B a g g i n g Bagging Bagging的主要好处是集成后的分类器的方差,比基分类器的方差小。 B a g g i n g Bagging Bagging所采用的基分类器最好是本身对样本分布较为敏感的(即所谓不稳定的分类器),这样 B a g g i n g Bagging Bagging才有用武之地。线性分类器或者KNN都是较为稳定的分类器,本身方差就不大,所以以它们为基分类器使用 B a g g i n g Bagging Bagging并不能在原有基分类器的基础上获得更好的表现,甚至可能因为 B a g g i n g Bagging Bagging的采样导致它们在训练中更难收敛,从而增大了集成分类器的偏差。
四、Random Forest & GBDT
4.1 随机森林(Random forest)
指的是利用多棵树对样本进行训练并预测的一种分类器。该分类器最早由
L
e
o
B
r
e
i
m
a
n
Leo Breiman
LeoBreiman和
A
d
e
l
e
C
u
t
l
e
r
Adele Cutler
AdeleCutler提出。
要理解随机森林,需要先知道决策树是什么,下面这张图很清晰地写出了一个通过一个决策树得到决策的过程。
决策树预测时,在树的内部节点处用某一属性值进行判断,根据判断结果决定进入哪个分支节点,直到到达叶节点处,得到分类结果。这是一种基于
i
f
−
t
h
e
n
−
e
l
s
e
if-then-else
if−then−else规则的有监督学习算法,决策树的这些规则通过训练得到,而不是人工制定的。构建完决策树,将所有这些树的结果进行投票表决或其他方式,就得到了最终的结果。
随机森林的构建步骤如下:
- 假如有 N N N个样本,则有放回的随机选择 N N N个样本(每次随机选择一个样本,然后返回继续选择)。这选择好了的 N N N个样本用来训练一个决策树,作为决策树根节点处的样本。
- 当每个样本有 M M M个属性时,在决策树的每个节点需要分裂时,随机从这 M M M个属性中选取出 m m m个属性,满足条件 m < < M m << M m<<M。然后从这 m m m个属性中采用某种策略(比如说信息增益)来选择1个属性作为该节点的分裂属性。
- 决策树形成过程中每个节点都要按照步骤2来分裂(很容易理解,如果下一次该节点选出来的那一个属性是刚刚其父节点分裂时用过的属性,则该节点已经达到了叶子节点,无须继续分裂了)。一直到不能够再分裂为止。注意整个决策树形成过程中没有进行剪枝。
- 按照步骤1~3建立大量的决策树,这样就构成了随机森林了。
4.1.1 随机森林如何处理缺失值?
首先,给缺失值预设一些估计值,比如数值型特征,选择其余数据的中位数或众数作为当前的估计值;
然后,根据估计的数值,建立随机森林,把所有的数据放进随机森林里面跑一遍。记录每一组数据在决策树中一步一步分类的路径,然后来判断哪组数据和缺失数据路径最相似,引入一个相似度矩阵,来记录数据之间的相似度,比如有N组数据,相似度矩阵大小就是N*N,如果缺失值是类别变量,通过权重投票得到新估计值,如果是数值型变量,通过加权平均得到新的估计值,如此迭代,直到得到稳定的估计值。
4.1.2 随机森林如何评估特征重要性?
衡量变量重要性的方法有两种,Decrease GINI 和 Decrease Accuracy:
-
D
e
c
r
e
a
s
e
G
I
N
I
Decrease GINI
DecreaseGINI:
对于分类问题(将某个样本划分到某一类),也就是离散变量问题, C A R T CART CART使用 G i n i Gini Gini值作为评判标准。定义为 G i n i = 1 − ∑ ( P ( i ) ∗ P ( i ) ) Gini=1-∑(P(i)*P(i)) Gini=1−∑(P(i)∗P(i)), P ( i ) P(i) P(i)为当前节点上数据集中第 i i i类样本的比例。例如:分为2类,当前节点上有100个样本,属于第一类的样本有70个,属于第二类的样本有30个,则 G i n i = 1 − 0.7 × 07 − 0.3 × 03 = 0.42 Gini=1-0.7×07-0.3×03=0.42 Gini=1−0.7×07−0.3×03=0.42,可以看出,类别分布越平均, G i n i Gini Gini值越大,类分布越不均匀, G i n i Gini Gini值越小。在寻找最佳的分类特征和阈值时,评判标准为: a r g m a x ( G i n i − G i n i L − G i n i R ) argmax(Gini-Gini_L-Gini_R) argmax(Gini−GiniL−GiniR),即寻找最佳的特征 f f f和阈值 t h th th,使得当前节点的 G i n i Gini Gini值减去左子节点的 G i n i Gini Gini和右子节点的 G i n i Gini Gini值最大。
对于回归问题,相对更加简单,直接使用 a r g m a x ( V a r − V a r L − V a r R ) argmax(Var-Var_L-Var_R) argmax(Var−VarL−VarR)作为评判标准,即当前节点训练集的方差 V a r Var Var减去减去左子节点的方差 V a r L Var_L VarL和右子节点的方差 V a r R Var_R VarR值最大。 -
D
e
c
r
e
a
s
e
A
c
c
u
r
a
c
y
Decrease Accuracy
DecreaseAccuracy:
对于一棵树 T b ( x ) Tb(x) Tb(x),我们用 O O B OOB OOB样本可以得到测试误差1;然后随机改变 O O B OOB OOB样本的第 j j j列:保持其他列不变,对第 j j j列进行随机的上下置换,得到误差2。至此,我们可以用误差1-误差2来刻画变量 j j j的重要性。基本思想就是,如果一个变量 j j j足够重要,那么改变它会极大的增加测试误差;反之,如果改变它测试误差没有增大,则说明该变量不是那么的重要。
4.1.3 什么是OOB?随机森林中OOB是如何计算的,它有什么优缺点?
B
a
g
g
i
n
g
Bagging
Bagging方法中
B
o
o
t
s
t
r
a
p
Bootstrap
Bootstrap每次约有
1
/
3
1/3
1/3的样本不会出现在
B
o
o
t
s
t
r
a
p
Bootstrap
Bootstrap所采集的样本集合中,当然也就没有参加决策树的建立,把这
1
/
3
1/3
1/3的数据称为袋外数据
o
o
b
oob
oob (out of bag),它可以用于取代测试集误差估计方法。
袋外数据(oob)误差的计算方法如下:
对于已经生成的随机森林,用袋外数据测试其性能,假设袋外数据总数为O,用这O个袋外数据作为输入,带进之前已经生成的随机森林分类器,分类器会给出O个数据相应的分类,因为这O条数据的类型是已知的,则用正确的分类与随机森林分类器的结果进行比较,统计随机森林分类器分类错误的数目,设为X,则袋外数据误差大小=X/O;
- 优点:这已经经过证明是无偏估计的,所以在随机森林算法中不需要再进行交叉验证或者单独的测试集来获取测试集误差的无偏估计。
- 缺点:当数据量较小时,自助法产生的数据集改变了初始数据集的分布,这会引入估计偏差。
4.1.4 随机森林的优缺点
优点:
- 可以处理很高维度(特征很多)的数据,并且不用降维,无需做特征选择;
- 可以判断特征的重要程度;
- 可以判断出不同特征之间的相互影响;
- 不容易过拟合;
- 训练速度比较快,容易做成并行方法;
- 实现起来比较简单;
- 对于不平衡的数据集来说,它可以平衡误差;
- 如果有很大一部分的特征遗失,仍可以维持准确度。
缺点:
- 在某些噪音较大的分类或回归问题上会过拟合;
- 对于有不同取值的属性的数据,取值划分较多的属性会对随机森林产生更大的影响,所以随机森林在这种数据上产出的属性权值是不可信的。
4.1.5 随机森林的实现方法以及应用场景
随机森林可以在很多地方使用:
- 离散值的分类
- 连续值的回归
- 无监督学习聚类
- 异常点检测
easyai上面介绍了使用四种平台测试随机森林算法实现的内存占用、运行速度和分类准确性对比,结果如图:
作者最常用的是scikit-learn,下面对sklearn里面调用随机森林的参数和属性进行介绍:
class sklearn.ensemble.RandomForestClassifier(n_estimators=10, criterion='gini', max_depth=None, min_samples_split=2,
min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features=’auto’, max_leaf_nodes=None, min_impurity_decrease=0.0,
bootstrap=True, oob_score=False, n_jobs=1, random_state=None, verbose=0, warm_start=False, class_weight=None)
参数:
n_estimators : integer, optional (default=10)
随机森林里(决策)树的数目
criterion : string, optional (default=”gini”)
衡量分裂质量的性能(函数)
max_features : int, float, string or None, optional (default=”auto”)
寻找最佳分割时需要考虑的特征数目
注意:寻找分割点不会停止,直到找到最少一个有效的节点划分区,即使它需要有效检查超过max_features的特征。i n t int int:考虑每一次分割处的max_feature特征,如果是float,那么max_features就是一个百分比,那么(max_feature*n_features)特征整数值是在每个分割处考虑的。
a u t o auto auto:么max_features=sqrt(n_features),即n_features的平方根值。
l o g 2 log_2 log2:那么max_features=log2(n_features)
N o n e None None:那么max_features=n_features
max_depth : integer or None, optional (default=None)
(决策)树的最大深度。如果值为None,那么会扩展节点,直到所有的叶子是纯净的,或者直到所有叶子包含少于min_sample_split的样本。
min_samples_split : int, float, optional (default=2)
分割内部节点所需要的最小样本数量int:考虑min_samples_split作为最小的数字;
float:min_samples_split是一个百分比,并且把ceil(min_samples_split*n_samples)作为每一个分割最小的样本数量。
min_samples_leaf : int, float, optional (default=1)
需要在叶子结点上的最小样本数量:int:考虑min_samples_leaf作为最小的数字。
float:min_samples_leaf为一个百分比,并且ceil(min_samples_leaf*n_samples)是每一个节点的最小样本数量。
min_weight_fraction_leaf : float, optional (default=0.0)
一个叶子节点所需要的权重总和(所有的输入样本)的最小加权分数。当sample_weight没有提供时,样本具有相同的权重
max_leaf_nodes : int or None, optional (default=None)
以最优的方法使用max_leaf_nodes来生长树
min_impurity_decrease : float, optional (default=0.0)
如果节点的分裂导致的不纯度的下降程度大于或者等于这个节点的值,那么这个节点将会被分裂
bootstrap : boolean, optional (default=True)
建立决策树时,是否使用有放回抽样
oob_score : bool (default=False) bool
是否使用袋外样本来估计泛化精度
n_jobs : integer, optional (default=1)
用于拟合和预测的并行运行的工作(作业)数量。如果值为-1,那么工作数量被设置为核的数量
random_state : int, RandomState instance or None, optional (default=None)
随机数生成器使用的种子
verbose : int, optional (default=0)
控制决策树建立过程的冗余度
warm_start : bool, optional (default=False)
当被设置为True时,重新使用之前呼叫的解决方案,用来给全体拟合和添加更多的估计器,反之,仅仅只是为了拟合一个全新的森林
属性:
estimators_ : list of DecisionTreeClassifier
模型的子估计器的集合
classes_ : array of shape = [n_classes] or a list of such arrays
类别标签(单一输出问题),或者类别标签的数组序列(多输出问题)
n_classes_ : int or list
类别的数量(单输出问题),或者一个序列,包含每一个输出的类别数量(多输出问题)
n_features_ : int
训练模型的特征数量
n_outputs_ : int
训练模型的输出数量
feature_importances_: array of shape = [n_features]
特征的重要性(值越高,特征越重要)
oob_score_ : float
使用袋外估计获得的训练数据集的得分
oob_decision_function_ : array of shape = [n_samples, n_classes]
在训练集上用袋外估计计算的决策函数。如果n_estimators很小的话,那么在有放回抽样中,一个数据点也不会被忽略是可能的。在这种情况下,oob_decision_function_ 可能包括NaN
4.2 梯度提升决策树(Gradient Boosting Decision Tree, GBDT)
GBDT是Boosting中非常流行的模型,它体现了”从错误中学习“的理念,基于决策树预测的残差进行迭代学习。
4.2.1 GBDT的原理
本文上面有整理Bagging和Boosting这两大集成学习的框架,相比于Bagging中各个弱分类器可以独立地进行训练,Boosting中的弱分类器需要依次生成。在每一轮迭代中,基于已生成的弱分类器集合(即当前模型)的预测结果,新的弱分类器会重点关注那些还没有被正确预测的样本。Gradient boosting是Boosting中的一大类算法,其基本思想是根据当前模型损失函数的负梯度信息来训练新加入的弱分类器,然后将训练好的弱分类器以累加的形式结合到现有模型中,下图描述了GBDT的算法流程,在每一轮迭代中,首先计算出当前模型在所有样本上的负梯度,然后以该值为目标训练一个新的弱分类器进行拟合并计算出该分类器的权重,最终实现对模型的更新。
算法步骤解释:
1、初始化,估计使损失函数极小化的常数值,它是只有一个根节点的树,即ganma是一个常数值。
2、
(a)计算损失函数的负梯度在当前模型的值,将它作为残差的估计
(b)估计回归树叶节点区域,以拟合残差的近似值
(c)利用线性搜索估计叶节点区域的值,使损失函数极小化
(d)更新回归树
3、得到输出的最终模型 f(x)
以下图所示例子来解释GBDT的训练过程。模型的任务是预测一个人的年龄,训练集只有A、B、C、D四个人,他们的年龄分别是14、16、24、26,特征包括了”月购物金额“”上网时长“”上网历史“等。下面开始训练第一棵树,训练的过程跟传统决策树相同,简单起见,我们只进行一次分枝。训练好第一棵树后,求得每个样本预测值与真实值之间的残差。可以看到,A、B、C、D的残差分别是-1,1,-1,1。这时我们就用每个样本的残差训练下一颗树 ,直到残差收敛到某个值域以下,或者树的总数达到某个上限为止。由于GBDT是利用残差训练的,在预测的过程中,我们也需要把所有树的预测值加起来,得到最终的结果。
4.2.2 梯度提升和梯度下降的区别和联系
两种算法都是在每一轮的迭代中,利用损失函数相对于模型的负梯度方向的信息来对当前模型进行更新,只不过在梯度下降中,模型是以参数化形式表示,从而模型的更新等价于参数的更新。而在梯度提升中,模型并不需要进行参数化表示,而是直接定义在函数空间中,从而大大扩展了可以使用的模型种类。
4.2.3 GBDT的优点和局限性
优点:
- 预测阶段的计算速度快,树与树之间可并行化计算。
- 在分布稠密的数据集上,泛化能力和表达能力都很好,这使得GBDT在Kaggle的众多竞赛中,经常名列榜首。
- 采用决策树作为弱分类器使得GBDT模型具有较好的解释性和鲁棒性,能够自动发现特征间的高阶关系,并且也不需要对数据进行特殊的预处理如归一化等。
局限性:
- GBDT在高维稀疏的数据集上,表现不如支持向量机或者神经网络。
- GBDT在处理文本分类特征问题上,相对于其他模型的优势不如它在处理数值特征时明显。
- 训练过程需要串行训练,只能在决策树内部采用一些局部并行的手段提高训练速度。
4.2.4 GBDT模型参数介绍以及调参技巧
参考文献
随机森林 – Random forest
sklearn随机森林分类类RandomForestClassifier
七月在线
统计学习方法
百面机器学习——算法工程师带你去面试
easyai