首页 > 代码库 > 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,至于这个具体是个什么,后面我再写文章进行分析。
public Bagging() { m_Classifier = new weka.classifiers.trees.REPTree(); }
整个BuildClassifier都是围绕标m_CalcOutOfBag来展开的,这个m_CalcOutOfBag标识的意思是:是否计算OutofBag的错误比例。
假如我们对训练集M进行抽样,抽样的数量和M的数量是一样的,那么肯定会有一些样本并没有被抽到(为什么?因为是有放回的抽样),这个标识就是用来评测这些没抽到的样本的准确率,如果没有这个标,那么这个准确率到后面就不会被计算了。
if (m_CalcOutOfBag && (m_BagSizePercent != 100)) { throw new IllegalArgumentException("Bag size needs to be 100% if " + "out-of-bag error is to be calculated!"); } int bagSize = data.numInstances() * m_BagSizePercent / 100; Random random = new Random(m_Seed); boolean[][] inBag = null; if (m_CalcOutOfBag) inBag = new boolean[m_Classifiers.length][]; for (int j = 0; j < m_Classifiers.length; j++) { Instances bagData = http://www.mamicode.com/null;>这一部分是抽样,首先如果有m_CalcOutOfBag标,则必须要求抽样比例是100%。其次算出要抽样的大小。
inBag数组是用来记录Instances中哪些样本被抽到了哪些没被抽到。
data.resampleWithWeight就是进行有放回的抽样。
if (m_Classifier instanceof Randomizable) { ((Randomizable) m_Classifiers[j]).setSeed(random.nextInt()); } // build the classifier m_Classifiers[j].buildClassifier(bagData);接着是构建分类树的过程,调用具体classifier的buildClassifier方法。最后是计算OutOfBag的过程,代码我已写注释。
if (getCalcOutOfBag()) { //如果有这个标就计算 double outOfBagCount = 0.0; //错误的权重和 double errorSum = 0.0;//错误的偏差值的和 boolean numeric = data.classAttribute().isNumeric();//是否是连续数值 for (int i = 0; i < data.numInstances(); i++) { double vote;//代表投票结果 double[] votes;//代表投票 if (numeric) votes = new double[1];//如果是数值,则取平均数,计算平均数的过程一个数组单元就够了 else votes = new double[data.numClasses()];//否则则要进行投票 // determine predictions for instance int voteCount = 0; for (int j = 0; j < m_Classifiers.length; j++) { if (inBag[j][i]) continue;//如果已经被采样,就忽略,因为要计算的是OutOfBag voteCount++;//记录有多少样本被计算 if (numeric) { votes[0] = m_Classifiers[j].classifyInstance(data.instance(i));//数值型则直接把预测结果累加 } else {double[] newProbs = m_Classifiers[j].distributionForInstance(data .instance(i)); for (int k = 0; k < newProbs.length; k++) { votes[k] += newProbs[k]; //枚举型则要把所有枚举概率进行累加 } } } // "vote" if (numeric) { vote = votes[0]; if (voteCount > 0) { vote /= voteCount; // 数值型取均值 } } else { if (Utils.eq(Utils.sum(votes), 0)) { } else { Utils.normalize(votes);//归一化 } vote = Utils.maxIndex(votes); // 选出最大的index } outOfBagCount += data.instance(i).weight();//累加权重 if (numeric) { errorSum += StrictMath.abs(vote - data.instance(i).classValue()) * data.instance(i).weight();//累加错误偏差 } else { if (vote != data.instance(i).classValue()) errorSum += data.instance(i).weight();//如果是枚举就对出错进行计数 } } m_OutOfBagError = errorSum / outOfBagCount;//最后取个平均值 } else { m_OutOfBagError = 0;//如果没有那个标就不计算了 }三、根据权重进行无放回抽样的过程
也就是 data.resampleWithWeights(random, inBag[j]);这个方法,感觉看了一下还挺有意思的,就放上来剖析一下。
重载形式有3个,前两个都会调用第三个:
public Instances resampleWithWeights(Random random, double[] weights) { return resampleWithWeights(random, weights, null); }public Instances resampleWithWeights(Random random, boolean[] sampled) { double[] weights = new double[numInstances()]; for (int i = 0; i < weights.length; i++) { weights[i] = instance(i).weight(); } return resampleWithWeights(random, weights, sampled); }
public Instances resampleWithWeights(Random random, double[] weights, boolean[] sampled) { if (weights.length != numInstances()) { throw new IllegalArgumentException("weights.length != numInstances."); } Instances newData = http://www.mamicode.com/new Instances(this, numInstances());>
这个所谓的Walker's method, see pp. 232 of "Stochastic Simulation" by B.D. Ripley我找了半天也不知道是个啥算法,代码也没啥注释,大体一看没看懂,等下次有机会再把这个函数的算法补上吧。
Weka算法Classifier-meta-Bagging源码分析