Weka算法Classifier-meta-Bagging源码分析

  Weka算法Classifier-meta-Bagging源码分析

Bagging部分比较简单, 算法 和代码放到一起写了。

一、Bagging算法

严格来看Bagging并不能算是一种分类算法,Bagging和Boosting一样,是一种组合基本分类器的方法,也就是使用多个基分类器来获取更为强大的分类器,其核心思想是有放回的抽样。


Bagging算法的训练流程:

1、从样本集中有放回的抽样M个样本。

2、用这M个样本训练基分类器C。

3、重复这个过程X次,得到若干个基分类器。


Bagging算法的预测流程:

1、对于新传入实例A,用这X个新分类器得到一个分类结果的列表。

2、若待分类属性是数值型(回归),求这个列表的算数平均值作为结果返回。

3、若待分类属性是枚举类型(分类),按这个列表对分类结果进行投票,返回票数最高的。


二、Weka代码实现

(1)基分类器

Weka中的默认基分类器使用的是REPTree,也就是Fast decision tree learner,至于这个具体是个什么,后面我再写文章进行分析。

[cpp]  view plain  copy
  1. public Bagging() {  
  2.   
  3.    m_Classifier = new weka.classifiers.trees.REPTree();  
  4.  }  


(2)构建过程BuildClassifier

整个BuildClassifier都是围绕标m_CalcOutOfBag来展开的,这个m_CalcOutOfBag标识的意思是:是否计算OutofBag的错误比例。

假如我们对训练集M进行抽样,抽样的数量和M的数量是一样的,那么肯定会有一些样本并没有被抽到(为什么?因为是有放回的抽样),这个标识就是用来评测这些没抽到的样本的准确率,如果没有这个标,那么这个准确率到后面就不会被计算了。

[java]  view plain  copy
  1. if (m_CalcOutOfBag && (m_BagSizePercent != 100)) {  
  2.       throw new IllegalArgumentException("Bag size needs to be 100% if "  
  3.           + "out-of-bag error is to be calculated!");  
  4.     }  
  5.   
  6.     int bagSize = data.numInstances() * m_BagSizePercent / 100;  
  7.     Random random = new Random(m_Seed);  
  8.   
  9.     boolean[][] inBag = null;  
  10.     if (m_CalcOutOfBag)  
  11.       inBag = new boolean[m_Classifiers.length][];  
  12.   
  13.     for (int j = 0; j < m_Classifiers.length; j++) {  
  14.       Instances bagData = null;  
  15.   
  16.       // create the in-bag dataset  
  17.       if (m_CalcOutOfBag) {  
  18.         inBag[j] = new boolean[data.numInstances()];  
  19.         // bagData = resampleWithWeights(data, random, inBag[j]);  
  20.         bagData = data.resampleWithWeights(random, inBag[j]);  
  21.       } else {  
  22.         bagData = data.resampleWithWeights(random);  
  23.         if (bagSize < data.numInstances()) {  
  24.           bagData.randomize(random);  
  25.           Instances newBagData = new Instances(bagData, 0, bagSize);  
  26.           bagData = newBagData;  
  27.         }  
  28.       }  
这一部分是抽样,首先如果有m_CalcOutOfBag标,则必须要求抽样比例是100%。

其次算出要抽样的大小。

inBag数组是用来记录Instances中哪些样本被抽到了哪些没被抽到。

data.resampleWithWeight就是进行有放回的抽样。

[java]  view plain  copy
  1. if (m_Classifier instanceof Randomizable) {  
  2.   ((Randomizable) m_Classifiers[j]).setSeed(random.nextInt());  
  3. }  
  4.   
  5. // build the classifier  
  6. m_Classifiers[j].buildClassifier(bagData);  
接着是构建分类树的过程,调用具体classifier的buildClassifier方法。

最后是计算OutOfBag的过程,代码我已写注释。

[java]  view plain  copy
  1. if (getCalcOutOfBag()) { //如果有这个标就计算  
  2.       double outOfBagCount = 0.0//错误的权重和  
  3.       double errorSum = 0.0;//错误的偏差值的和  
  4.       boolean numeric = data.classAttribute().isNumeric();//是否是连续数值  
  5.       for (int i = 0; i < data.numInstances(); i++) {  
  6.         double vote;//代表投票结果  
  7.         double[] votes;//代表投票  
  8.         if (numeric)  
  9.           votes = new double[1];//如果是数值,则取平均数,计算平均数的过程一个数组单元就够了  
  10.         else  
  11.           votes = new double[data.numClasses()];//否则则要进行投票  
  12.   
  13.         // determine predictions for instance  
  14.         int voteCount = 0;  
  15.         for (int j = 0; j < m_Classifiers.length; j++) {  
  16.           if (inBag[j][i])  
  17.             continue;//如果已经被采样,就忽略,因为要计算的是OutOfBag  
  18.   
  19.           voteCount++;//记录有多少样本被计算  
  20.           if (numeric) {  
  21.             votes[0] = m_Classifiers[j].classifyInstance(data.instance(i));//数值型则直接把预测结果累加  
  22.           } else {  
[java]  view plain  copy
  1.         double[] newProbs = m_Classifiers[j].distributionForInstance(data  
  2.             .instance(i));  
  3.         for (int k = 0; k < newProbs.length; k++) {  
  4.           votes[k] += newProbs[k]; //枚举型则要把所有枚举概率进行累加  
  5.         }  
  6.       }  
  7.     }  
  8.   
  9.     // "vote"  
  10.     if (numeric) {  
  11.       vote = votes[0];  
  12.       if (voteCount > 0) {  
  13.         vote /= voteCount; // 数值型取均值  
  14.       }  
  15.     } else {  
  16.       if (Utils.eq(Utils.sum(votes), 0)) {  
  17.       } else {  
  18.         Utils.normalize(votes);//归一化  
  19.       }  
  20.       vote = Utils.maxIndex(votes); // 选出最大的index  
  21.     }  
  22.     outOfBagCount += data.instance(i).weight();//累加权重  
  23.     if (numeric) {  
  24.       errorSum += StrictMath.abs(vote - data.instance(i).classValue())  
  25.           * data.instance(i).weight();//累加错误偏差  
  26.     } else {  
  27.       if (vote != data.instance(i).classValue())  
  28.         errorSum += data.instance(i).weight();//如果是枚举就对出错进行计数  
  29.     }  
  30.   }  
  31.   
  32.   m_OutOfBagError = errorSum / outOfBagCount;//最后取个平均值  
  33. else {  
  34.   m_OutOfBagError = 0;//如果没有那个标就不计算了  
  35. }  


三、根据权重进行无放回抽样的过程

也就是 data.resampleWithWeights(random, inBag[j]);这个方法,感觉看了一下还挺有意思的,就放上来剖析一下。

重载形式有3个,前两个都会调用第三个:

[java]  view plain  copy
  1. public Instances resampleWithWeights(Random random, double[] weights) {  
  2.   
  3.   return resampleWithWeights(random, weights, null);  
  4. }  

[java]  view plain  copy
  1. public Instances resampleWithWeights(Random random, boolean[] sampled) {  
  2.   
  3.   double[] weights = new double[numInstances()];  
  4.   for (int i = 0; i < weights.length; i++) {  
  5.     weights[i] = instance(i).weight();  
  6.   }  
  7.   return resampleWithWeights(random, weights, sampled);  
  8. }  


[java]  view plain  copy
  1. public Instances resampleWithWeights(Random random, double[] weights,  
  2.     boolean[] sampled) {  
  3.   
  4.     if (weights.length != numInstances()) {  
  5.       throw new IllegalArgumentException("weights.length != numInstances.");  
  6.     }  
  7.   
  8.     Instances newData = new Instances(this, numInstances());  
  9.     if (numInstances() == 0) {  
  10.       return newData;  
  11.     }  
  12.   
  13.     // Walker's method, see pp. 232 of "Stochastic Simulation" by B.D. Ripley  
  14.     double[] P = new double[weights.length];  
  15.     System.arraycopy(weights, 0, P, 0, weights.length);  
  16.     Utils.normalize(P);  
  17.     double[] Q = new double[weights.length];  
  18.     int[] A = new int[weights.length];  
  19.     int[] W = new int[weights.length];  
  20.     int M = weights.length;  
  21.     int NN = -1;  
  22.     int NP = M;  
  23.     for (int I = 0; I < M; I++) {  
  24.       if (P[I] < 0) {  
  25.         throw new IllegalArgumentException("Weights have to be positive.");  
  26.       }  
  27.       Q[I] = M * P[I];  
  28.       if (Q[I] < 1.0) {  
  29.         W[++NN] = I;  
  30.       } else {  
  31.         W[--NP] = I;  
  32.       }  
  33.     }  
  34.     if (NN > -1 && NP < M) {  
  35.       for (int S = 0; S < M - 1; S++) {  
  36.         int I = W[S];  
  37.         int J = W[NP];  
  38.         A[I] = J;  
  39.         Q[J] += Q[I] - 1.0;  
  40.         if (Q[J] < 1.0) {  
  41.           NP++;  
  42.         }  
  43.         if (NP >= M) {  
  44.           break;  
  45.         }  
  46.       }  
  47.       // A[W[M]] = W[M];  
  48.     }  
  49.   
  50.     for (int I = 0; I < M; I++) {  
  51.       Q[I] += I;  
  52.     }  
  53.   
  54.     for (int i = 0; i < numInstances(); i++) {  
  55.       int ALRV;  
  56.       double U = M * random.nextDouble();  
  57.       int I = (int) U;  
  58.       if (U < Q[I]) {  
  59.         ALRV = I;  
  60.       } else {  
  61.         ALRV = A[I];  
  62.       }  
  63.       newData.add(instance(ALRV));  
  64.       if (sampled != null) {  
  65.         sampled[ALRV] = true;  
  66.       }  
  67.       newData.instance(newData.numInstances() - 1).setWeight(1);  
  68.     }  
  69.   
  70.     return newData;  
  71.   }  

这个所谓的
[java]  view plain  copy
  1. Walker's method, see pp. 232 of "Stochastic Simulation" by B.D. Ripley  
我找了半天也不知道是个啥算法,代码也没啥注释,大体一看没看懂,等下次有机会再把这个函数的算法补上吧。
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值