首页 > 代码库 > Weka算法Classifier-meta-AdaBoostM1源码分析(二)

Weka算法Classifier-meta-AdaBoostM1源码分析(二)


三、基分类器

AdaBoostM1使用的默认基分类器是weka.classifiers.trees.DecisionStump,名字直译过来就是决策桩(这什么名字?!),其分类方法类似于ID3算法的节点分裂算法,如果是枚举型的,遍历所有属性,选出其中一个属性,使使用该属性进行分类后的熵增益最大,如果是数值型的,选择一个节点做二分,使分类后方差最小。

但和决策树不同的是,并不做递归的树生长,只做一次节点选择并分裂(所以叫桩而不是树)。

这个基分类器大体思路就是这样,代码较简单并且没有什么巧妙的算法思想,故不做具体分析。


四、buildClassifierWithWeight

上篇文章分析主流程的时候,可以看到最后主流程最后把训练过程委派给了buildClassifierWithWeight和buildClassifierUsingResampling,先来分析一下buildClassifierWithWeight

 protected void buildClassifierWithWeights(Instances data) 
    throws Exception {

    Instances trainData, training;
    double epsilon, reweight;
    Evaluation evaluation;
    int numInstances = data.numInstances();
    Random randomInstance = new Random(m_Seed);

    // //初始化
    m_Betas = new double [m_Classifiers.length];
    m_NumIterationsPerformed = 0;

    // 从直观认识上讲,算法训练模型的时候,不应该改变训练数据或者把训练集弄脏,因此需要做一个Instances的深度拷贝。
    training = new Instances(data, 0, numInstances);
    
    // 主循环,boosting使用的基分类器数量就是m_Classifiers数组长度。
    for (m_NumIterationsPerformed = 0; m_NumIterationsPerformed < m_Classifiers.length; 
	 m_NumIterationsPerformed++) {
      if (m_Debug) {
	System.err.println("Training classifier " + (m_NumIterationsPerformed + 1));
      }
      // 这里可以设置一个百分数,代表权重分位数,低于该分位数的实例会被过滤掉,这里是体现了boosting的“每次迭代着重考虑之前分错的实例”这种思想。
      if (m_WeightThreshold < 100) {
	trainData = http://www.mamicode.com/selectWeightQuantile(training, >可以看到,此函数并没有对训练集根据权重进行重抽样,因为基分类器自身就是权重敏感的分类器。

但是从设计的角度来吐个槽的话,个人认为这并不是一个非常好的设计,AdaBoostM1类作为一个基分类器的wrapper,必须对整个训练及分类结果负责,并不能因为基分类器“仅仅实现了权重敏感接口”就完全信任其权重敏感的操作,再从算法本身的角度来讲,实现“权重敏感”的逻辑本身就是AdaBoostM1算法的一部分,不应委派给基分类器去做。


五、buildClassifierUsingResampling

protected void buildClassifierUsingResampling(Instances data) 
    throws Exception {

    Instances trainData, sample, training;
    double epsilon, reweight, sumProbs;
    Evaluation evaluation;
    int numInstances = data.numInstances();
    Random randomInstance = new Random(m_Seed);
    int resamplingIterations = 0;

    // 初始化所有基分类器的权重数组,迭代次数等。
    m_Betas = new double [m_Classifiers.length];
    m_NumIterationsPerformed = 0;
    // 深度拷贝训练集
    training = new Instances(data, 0, numInstances);
    sumProbs = training.sumOfWeights();
    for (int i = 0; i < training.numInstances(); i++) {
      training.instance(i).setWeight(training.instance(i).
				      weight() / sumProbs);//初始化权重为均值。
    }
    
    // 主循环
    for (m_NumIterationsPerformed = 0; m_NumIterationsPerformed < m_Classifiers.length; 
	 m_NumIterationsPerformed++) {
      if (m_Debug) {
	System.err.println("Training classifier " + (m_NumIterationsPerformed + 1));
      }

      // 低权重过滤
      if (m_WeightThreshold < 100) {
	trainData = http://www.mamicode.com/selectWeightQuantile(training, >

六、总结

训练好了分类器之后,在针对具体instance分类时,会根据mBeta对各基分类器得到的结果进行算数加权,进而得到最终结果,相关代码叫见到不再分析。


总结实在不知道该写些啥,简单说两点吧

1、Weka的AdaBoostM1基本按照标准算法实现得来,唯一的不同之处就是部分权重resampling会委派给基分类器进行实现。

2、基分类器一定要选择弱分类器。



Weka算法Classifier-meta-AdaBoostM1源码分析(二)