多分类器组合算法简单的来讲常用的有voting,bagging和boosting,其中就效果来说Boosting略占优势,而AdaBoostM1算法又相当于Boosting算法的“经典款”。
Voting思想是使用多分类器进行投票组合,并按照少数服从多数(大多数情况)来决定最终的分类,缺点是少数服从多数的规则往往只能避免达到最差的情况却也很难达到最少的情况。
Bagging思想是有放回的随机抽样来训练多个分类器,最后使用voting来进行投票决策,经典算法如RandomForest(之前也有博客分析过),缺点是要求各基分类器同构,并且从精度上来讲Bagging并不是一个明显提高精度的算法,而是一个防止过拟合的算法。
Boosting是使用级联训练分类器,使得“下一级”分类器更加重视“上一级”分错的数据,最后把各分类器结果加权组合来进行决策,缺点是需要级联训练因此算法难于并行化。比较经典的算法如AdaBoostM1、GBDT。
一、算法
算法部分简单说一下,并不做详细的形式化描述及相关理论正确性的证明,参考资料来自于wiki
http://zh.wikipedia.org/wiki/AdaBoost
算法过程:
(1)初始化训练集各实例权重为1/k(假设总共k个用例)
(2)for i=1;i <=m ; i++ (假设总共基分类器的个数是m)
(3)将训练集根据权重进行重采样,得到新训练集
(4)根据新训练集训练基分类器i
(5)评测该基分类器准确率r
(6)如果准确率r小于50%,直接退出,训练失败(这里指的是二值分类情况,多值分类类似扩展)
(7)设置基分类器i权重为log2(1-r/r)
(8)w=1-r/r(因为r>0.5,所以w>1),对于分类错误的实例,原训练集中的权重乘以w(即调高权重)。
(9)归一化训练集权重(缩小一定倍数使和为1)
(10)回到2
可以看到,根据这个算法,第四步训练得到了基分类器,每个基分类器都会在第七部得到一个权重,最后进行分类预测的时候就根据每个基分类器的结果进行加权投票得到最终的结果。
二、实现
在分析每个分类器的时候,我们都从buildClassifier入手,这次也不例外。
public void buildClassifier(Instances data) throws Exception { super.buildClassifier(data);//weka里面有个工具是可以从一个分类器以深度拷贝的方式新建一个分类器,而adaboostm1作为一个多分类器的combine,这个深度拷贝必须要拷贝每一个基分类器,这个就是在super类中实现的。 // 看看这个数据能否用adaboost来分类,从代码来看,只能处理枚举类型,但我认为这个应该是由基分类器能力决定的。 getCapabilities().testWithFail(data); // 预处理 data = new Instances(data); data.deleteWithMissingClass(); // 如果只有一个属性列,当然也就是分类本身的属性,这时没法使用任何复杂分类方法,就只是用mZero模型,mZero模型简单的返回枚举值中出现最多的值。 if (data.numAttributes() == 1) { System.err.println( "Cannot build model (only class attribute present in data!), " + "using ZeroR model instead!"); m_ZeroR = new weka.classifiers.rules.ZeroR(); m_ZeroR.buildClassifier(data); return; } else { m_ZeroR = null; } m_NumClasses = data.numClasses(); if ((!m_UseResampling) && (m_Classifier instanceof WeightedInstancesHandler)) { buildClassifierWithWeights(data);//如果基分类器本身就是一个权重敏感的分类器,那么就不需要使用重抽样,否则使用重采样方法,常见的权重敏感的分类器的实现有很多,比如之前介绍过的J48,RandomTree,RandomForest,Bagging等。 } else { buildClassifierUsingResampling(data);//否则使用重抽样的方法。 } }