机器学习之集成学习 bagging与随机森林

Bagging与随机森林算法原理小结

    在集成学习原理小结中,我们讲到了集成学习有两个流派,一个是boosting派系,它的特点是各个弱学习器之间有依赖关系。另一种是bagging流派,它的特点是各个弱学习器之间没有依赖关系,可以并行拟合。本文就对集成学习中Bagging与随机森林算法做一个总结。

    随机森林是集成学习中可以和梯度提升树GBDT分庭抗礼的算法,尤其是它可以很方便的并行训练,在如今大数据大样本的的时代很有诱惑力。

1.  bagging的原理

    在集成学习原理小结中,我们给Bagging画了下面一张原理图。

    从上图可以看出,Bagging的弱学习器之间的确没有boosting那样的联系。它的特点在“随机采样”。那么什么是随机采样?

    随机采样(bootsrap)就是从我们的训练集里面采集固定个数的样本,但是每采集一个样本后,都将样本放回。也就是说,之前采集到的样本在放回后有可能继续被采集到。对于我们的Bagging算法,一般会随机采集和训练集样本数m一样个数的样本。这样得到的采样集和训练集样本的个数相同,但是样本内容不同。如果我们对有m个样本训练集做T次的随机采样,,则由于随机性,T个采样集各不相同。

    注意到这和GBDT的子采样是不同的。GBDT的子采样是无放回采样,而Bagging的子采样是放回采样。

    对于一个样本,它在某一次含m个样本的训练集的随机采样中,每次被采集到的概率是 1m 1m。不被采集到的概率为 11m 1−1m。如果m次采样都没有被采集中的概率是 (11m)m (1−1m)m。当 m m→∞时, (11m)m1e0.368 (1−1m)m→1e≃0.368。也就是说,在bagging的每轮随机采样中,训练集中大约有36.8%的数据没有被采样集采集中。

    对于这部分大约36.8%的没有被采样到的数据,我们常常称之为袋外数据(Out Of Bag, 简称OOB)。这些数据没有参与训练集模型的拟合,因此可以用来检测模型的泛化能力。

    bagging对于弱学习器没有限制,这和Adaboost一样。但是最常用的一般也是决策树和神经网络。

    bagging的集合策略也比较简单,对于分类问题,通常使用简单投票法,得到最多票数的类别或者类别之一为最终的模型输出。对于回归问题,通常使用简单平均法,对T个弱学习器得到的回归结果进行算术平均得到最终的模型输出。

    由于Bagging算法每次都进行采样来训练模型,因此泛化能力很强,对于降低模型的方差很有作用。当然对于训练集的拟合程度就会差一些,也就是模型的偏倚会大一些。

2.  bagging算法流程

    上一节我们对bagging算法的原理做了总结,这里就对bagging算法的流程做一个总结。相对于Boosting系列的Adaboost和GBDT,bagging算法要简单的多。

    输入为样本集 D={(x,y1),(x2,y2),...(xm,ym)} D={(x,y1),(x2,y2),...(xm,ym)},弱学习器算法, 弱分类器迭代次数T。

    输出为最终的强分类器 f(x) f(x)

    1)对于t=1,2...,T:

      a)对训练集进行第t次随机采样,共采集m次,得到包含m个样本的采样集 Dm Dm

      b)用采样集 Dm Dm训练第m个弱学习器 Gm(x) Gm(x)

    2) 如果是分类算法预测,则T个弱学习器投出最多票数的类别或者类别之一为最终类别。如果是回归算法,T个弱学习器得到的回归结果进行算术平均得到的值为最终的模型输出。

3. 随机森林算法

    理解了bagging算法,随机森林(Random Forest,以下简称RF)就好理解了。它是Bagging算法的进化版,也就是说,它的思想仍然是bagging,但是进行了独有的改进。我们现在就来看看RF算法改进了什么。   

    首先,RF使用了CART决策树作为弱学习器,这让我们想到了梯度提示树GBDT。第二,在使用决策树的基础上,RF对决策树的建立做了改进,对于普通的决策树,我们会在节点上所有的n个样本特征中选择一个最优的特征来做决策树的左右子树划分,但是RF通过随机选择节点上的一部分样本特征,这个数字小于n,假设为 nsub nsub,然后在这些随机选择的 nsub nsub个样本特征中,选择一个最优的特征来做决策树的左右子树划分。这样进一步增强了模型的泛化能力。    

    如果 nsub=n nsub=n,则此时RF的CART决策树和普通的CART决策树没有区别。 nsub nsub越小,则模型约健壮,当然此时对于训练集的拟合程度会变差。也就是说 nsub nsub越小,模型的方差会减小,但是偏倚会增大。在实际案例中,一般会通过交叉验证调参获取一个合适的 nsub nsub的值。

    除了上面两点,RF和普通的bagging算法没有什么不同, 下面简单总结下RF的算法。

    输入为样本集 D={(x,y1),(x2,y2),...(xm,ym)} D={(x,y1),(x2,y2),...(xm,ym)},弱分类器迭代次数T。

    输出为最终的强分类器 f(x) f(x)

    1)对于t=1,2...,T:

      a)对训练集进行第t次随机采样,共采集m次,得到包含m个样本的采样集 Dm Dm

      b)用采样集 Dm Dm训练第m个决策树模型 Gm(x) Gm(x),在训练决策树模型的节点的时候, 在节点上所有的样本特征中选择一部分样本特征, 在这些随机选择的部分样本特征中选择一个最优的特征来做决策树的左右子树划分

    2) 如果是分类算法预测,则T个弱学习器投出最多票数的类别或者类别之一为最终类别。如果是回归算法,T个弱学习器得到的回归结果进行算术平均得到的值为最终的模型输出。

4. 随机森林的推广

    由于RF在实际应用中的良好特性,基于RF,有很多变种算法,应用也很广泛,不光可以用于分类回归,还可以用于特征转换,异常点检测等。下面对于这些RF家族的算法中有代表性的做一个总结。

 4.1 extra trees

    extra trees是RF的一个变种, 原理几乎和RF一模一样,仅有区别有:

    1) 对于每个决策树的训练集,RF采用的是随机采样bootstrap来选择采样集作为每个决策树的训练集,而extra trees一般不采用随机采样,即每个决策树采用原始训练集。

    2) 在选定了划分特征后,RF的决策树会基于信息增益,基尼系数,均方差之类的原则,选择一个最优的特征值划分点,这和传统的决策树相同。但是extra trees比较的激进,他会随机的选择一个特征值来划分决策树。

    从第二点可以看出,由于随机选择了特征值的划分点位,而不是最优点位,这样会导致生成的决策树的规模一般会大于RF所生成的决策树。也就是说,模型的方差相对于RF进一步减少,但是偏倚相对于RF进一步增大。在某些时候,extra trees的泛化能力比RF更好。

4.2 Totally Random Trees Embedding

    Totally Random Trees Embedding(以下简称 TRTE)是一种非监督学习的数据转化方法。它将低维的数据集映射到高维,从而让映射到高维的数据更好的运用于分类回归模型。我们知道,在支持向量机中运用了核方法来将低维的数据集映射到高维,此处TRTE提供了另外一种方法。

    TRTE在数据转化的过程也使用了类似于RF的方法,建立T个决策树来拟合数据。当决策树建立完毕以后,数据集里的每个数据在T个决策树中叶子节点的位置也定下来了。比如我们有3颗决策树,每个决策树有5个叶子节点,某个数据特征 x x划分到第一个决策树的第2个叶子节点,第二个决策树的第3个叶子节点,第三个决策树的第5个叶子节点。则x映射后的特征编码为(0,1,0,0,0,     0,0,1,0,0,     0,0,0,0,1), 有15维的高维特征。这里特征维度之间加上空格是为了强调三颗决策树各自的子编码。

    映射到高维特征后,可以继续使用监督学习的各种分类回归算法了。

4.3 Isolation Forest

    Isolation Forest(以下简称IForest)是一种异常点检测的方法。它也使用了类似于RF的方法来检测异常点。

    对于在T个决策树的样本集,IForest也会对训练集进行随机采样,但是采样个数不需要和RF一样,对于RF,需要采样到采样集样本个数等于训练集个数。但是IForest不需要采样这么多,一般来说,采样个数要远远小于训练集个数?为什么呢?因为我们的目的是异常点检测,只需要部分的样本我们一般就可以将异常点区别出来了。

    对于每一个决策树的建立, IForest采用随机选择一个划分特征,对划分特征随机选择一个划分阈值。这点也和RF不同。

    另外,IForest一般会选择一个比较小的最大决策树深度max_depth,原因同样本采集,用少量的异常点检测一般不需要这么大规模的决策树。

    对于异常点的判断,则是将测试样本点 x x拟合到T颗决策树。计算在每颗决策树上该样本的叶子节点的深度 ht(x) ht(x)。,从而可以计算出平均高度h(x)。此时我们用下面的公式计算样本点 x x的异常概率:

s(x,m)=2h(x)c(m) s(x,m)=2−h(x)c(m)

    其中,m为样本个数。 c(m) c(m)的表达式为:

c(m)=2ln(m1)+ξ2m1m,ξ c(m)=2ln⁡(m−1)+ξ−2m−1m,ξ为欧拉常数

    s(x,m)的取值范围是[0,1],取值越接近于1,则是异常点的概率也越大。

5. 随机森林小结

    RF的算法原理也终于讲完了,作为一个可以高度并行化的算法,RF在大数据时候大有可为。 这里也对常规的随机森林算法的优缺点做一个总结。

    RF的主要优点有:

    1) 训练可以高度并行化,对于大数据时代的大样本训练速度有优势。个人觉得这是的最主要的优点。

    2) 由于可以随机选择决策树节点划分特征,这样在样本特征维度很高的时候,仍然能高效的训练模型。

    3) 在训练后,可以给出各个特征对于输出的重要性

    4) 由于采用了随机采样,训练出的模型的方差小,泛化能力强。

    5) 相对于Boosting系列的Adaboost和GBDT, RF实现比较简单。

    6) 对部分特征缺失不敏感。

    RF的主要缺点有:

    1)在某些噪音比较大的样本集上,RF模型容易陷入过拟合。

    2) 取值划分比较多的特征容易对RF的决策产生更大的影响,从而影响拟合的模型的效果



考虑一个简单例子:在二分类任务中,假定三个分类器在三个测试样本上的表现如下图,其中√表示分类正确,×表示分类错误,集成学习的结果通过投票法产生,即“少数服从多数”。如下图,在(a)中,每个分类器都只有66.6%的精度,但集成学习却达到了100%;在(b)中,三个分类器没有差别,集成之后性能没有提高;在(c)中,每个分类器的精度都只有33.3%,集成学习的结果变得更糟。这个简单地例子显示出:要获得好的集成,个体学习器应“好而不同”,即个体学习器要有一定的“准确性”,即学习器不能太差,并且要有“多样性”,即学习器间具有差异。

 

根据个体学习器的生成方式,目前的集成学习方法大致可分为两大类,即个体学习器之间存在强依赖关系,必须串行生成的序列化方法,以及个体学习器间不存在强依赖关系,可同时生成的并行化方法;前者的代表是Boosting,后者的代表是Bagging和“随机森林”(Random Forest)

Bagging与随机森林

要得到泛化性能强的集成,集成中的个体学习器应尽可能相互独立,虽然这在现实任务中很难做到,但我们可以设法使基学习器尽可能具有较大的差异。

在我的实验中,使用“自助采样法”:给定包含m个样本的数据集,我们先随机取出一个样本放入采样集中,再把该样本放回初始数据集,使得下次采样时该样本仍有可能被选中,这样,经过m次随机操作,我们得到含m个样本的采样集,初始训练集中有的样本在采样集里多次出现,有的则从未出现。

按照这种方法,我们可以采样出T个含m个训练样本的采样集,然后基于每个采样集训练处一个基学习器,再将这些基学习器进行结合,这就是Bagging的基本流程。在对预测输出进行结合时,Bagging通常对分类任务使用简单投票法,对回归任务使用简单平均法。


随机森林是Bagging的一个扩展。随机森林在以决策树为基学习器构建Bagging集成的基础上,进一步在决策树的训练过程中引入了随机属性选择(即引入随机特征选择)。传统决策树在选择划分属性时时在当前节点的属性集合(假定有d个属性)中选择一个最优属性;而在随机森林中,对基决策树的每个节点,先从该节点的属性集合中随机选择一个包含k个属性的子集,然后再从这个子集中选择一个最优属性用于划分。这里的参数k控制了随机性的引入程度:若令k=d,则基决策树的构建与传统决策树相同;若令k=1,则是随机选择一个属性进行划分。

在这篇文章中,我们只讲随机森林的分类部分。随机森林用于分类时,即采用n个决策树分类,将分类结果用简单投票法得到最终分类,提高分类准确率。

对于决策树不太了解的童鞋,可以看我的上一篇博客:决策树原理及Python代码实现

简单来说,随机森林就是对决策树的集成,但有两点不同:

(1)采样的差异性:从含m个样本的数据集中有放回的采样,得到含m个样本的采样集,用于训练。这样能保证每个决策树的训练样本不完全一样。

(2)特征选取的差异性:每个决策树的n个分类特征是在所有特征中随机选择的(n是一个需要我们自己调整的参数)

随机森林需要调整的参数有:

(1)    决策树的个数

(2)    特征属性的个数

(3)    递归次数(即决策树的深度)

 

下面,讲一下如何用代码实现随机森林。

代码实现流程:

(1)    导入文件并将所有特征转换为float形式

(2)    将数据集分成n份,方便交叉验证

(3)    构造数据子集(随机采样),并在指定特征个数(假设m个,手动调参)下选取最优特征

(4)    构造决策树

(5)    创建随机森林(多个决策树的结合)

(6)    输入测试集并进行测试,输出预测结果

 

(1)    导入文件并将所有特征转换为float形式

[python]  view plain  copy
  1. #加载数据  
  2. def loadCSV(filename):  
  3.     dataSet=[]  
  4.     with open(filename,'r') as file:  
  5.         csvReader=csv.reader(file)  
  6.         for line in csvReader:  
  7.             dataSet.append(line)  
  8.     return dataSet  
  9.   
  10. #除了判别列,其他列都转换为float类型  
  11. def column_to_float(dataSet):  
  12.     featLen=len(dataSet[0])-1  
  13.     for data in dataSet:  
  14.         for column in range(featLen):  
  15.             data[column]=float(data[column].strip())  
(2)    将数据集分成n份,方便交叉验证

[python]  view plain  copy
  1. #将数据集分成N块,方便交叉验证  
  2. def spiltDataSet(dataSet,n_folds):  
  3.     fold_size=int(len(dataSet)/n_folds)  
  4.     dataSet_copy=list(dataSet)  
  5.     dataSet_spilt=[]  
  6.     for i in range(n_folds):  
  7.         fold=[]  
  8.         while len(fold) < fold_size:   #这里不能用if,if只是在第一次判断时起作用,while执行循环,直到条件不成立  
  9.             index=randrange(len(dataSet_copy))  
  10.             fold.append(dataSet_copy.pop(index))  #pop() 函数用于移除列表中的一个元素(默认最后一个元素),并且返回该元素的值。  
  11.         dataSet_spilt.append(fold)  
  12.     return dataSet_spilt  

(3)    构造数据子集(随机采样),并在指定特征个数(假设m个,手动调参)下选取最优特征
[python]  view plain  copy
  1. #构造数据子集  
  2. def get_subsample(dataSet,ratio):  
  3.     subdataSet=[]  
  4.     lenSubdata=round(len(dataSet)*ratio)  
  5.     while len(subdataSet) < lenSubdata:  
  6.         index=randrange(len(dataSet)-1)  
  7.         subdataSet.append(dataSet[index])  
  8.     #print len(subdataSet)  
  9.     return subdataSet  
  10.   
  11. #选取任意的n个特征,在这n个特征中,选取分割时的最优特征  
  12. def get_best_spilt(dataSet,n_features):  
  13.     features=[]  
  14.     class_values=list(set(row[-1for row in dataSet))  
  15.     b_index,b_value,b_loss,b_left,b_right=999,999,999,None,None  
  16.     while len(features) < n_features:  
  17.         index=randrange(len(dataSet[0])-1)  
  18.         if index not in features:  
  19.             features.append(index)  
  20.     #print 'features:',features  
  21.     for index in features:  
  22.         for row in dataSet:  
  23.             left,right=data_spilt(dataSet,index,row[index])  
  24.             loss=spilt_loss(left,right,class_values)  
  25.             if loss < b_loss:  
  26.                 b_index,b_value,b_loss,b_left,b_right=index,row[index],loss,left,right  
  27.     #print b_loss  
  28.     #print type(b_index)  
  29.     return {'index':b_index,'value':b_value,'left':b_left,'right':b_right}  

(4)    构造决策树

[python]  view plain  copy
  1. #构造决策树  
  2. def build_tree(dataSet,n_features,max_depth,min_size):  
  3.     root=get_best_spilt(dataSet,n_features)  
  4.     sub_spilt(root,n_features,max_depth,min_size,1)   
  5.     return root  

(5)    创建随机森林(多个决策树的结合)

[python]  view plain  copy
  1. #创建随机森林  
  2. def random_forest(train,test,ratio,n_feature,max_depth,min_size,n_trees):  
  3.     trees=[]  
  4.     for i in range(n_trees):  
  5.         subTrain=get_subsample(train,ratio)  
  6.         tree=build_tree(subTrain,n_features,max_depth,min_size)  
  7.         #print 'tree %d: '%i,tree  
  8.         trees.append(tree)  
  9.     #predict_values = [predict(trees,row) for row in test]  
  10.     predict_values = [bagging_predict(trees, row) for row in test]  
  11.     return predict_values  

(6)    输入测试集并进行测试,输出预测结果
[python]  view plain  copy
  1. #预测测试集结果  
  2. def predict(tree,row):  
  3.     predictions=[]  
  4.     if row[tree['index']] < tree['value']:  
  5.         if isinstance(tree['left'],dict):  
  6.             return predict(tree['left'],row)  
  7.         else:  
  8.             return tree['left']  
  9.     else:  
  10.         if isinstance(tree['right'],dict):  
  11.             return predict(tree['right'],row)  
  12.         else:  
  13.             return tree['right']  
  14.    # predictions=set(predictions)  

对以上代码的一点总结:

训练部分:假设我们取dataset中的m个feature来构造决策树,首先,我们遍历m个feature中的每一个feature,再遍历每一行,通过spilt_loss函数(计算分割代价)来选取最优的特征及特征值,根据是否大于这个特征值进行分类(分成left,right两类),循环执行上述步骤,直至不可分或者达到递归限值(用来防止过拟合),最后得到一个决策树tree。

测试部分:对测试集的每一行进行判断,决策树tree是一个多层字典,每一层为一个二分类,将每一行按照决策树tree中的分类索引index一步一步向里层探索,直至不出现字典时探索结束,得到的值即为我们的预测值。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值