Weka开发[20]——IB1源代码分析

转自 Koala++'s blog

      首先先解释一下算法名字,很多人很奇怪为什么叫IB1,IBK,IB Instance-Based的缩写,但按Jiawei Han书上所写,KNN其实是Instance-based learning(也被称为Lazing learning)中一种,他还讲解了基于案例的推理(Case-based reasoning)。算法其实是KNN,但是作者论文的名字是Instance-based Learning Algorithms。

我先介绍一下IB1,IB1就是只找一个邻居。我们还是先看buildClassifier。

public void buildClassifier(Instances instances) throws Exception {

 

    if (instances.classAttribute().isNumeric()) {

       throw new Exception("IB1: Class is numeric!");

    }

    if (instances.checkForStringAttributes()) {

       throw new UnsupportedAttributeTypeException(

              "IB1: Cannot handle string attributes!");

    }

    // Throw away training instances with missing class

    m_Train = new Instances(instances, 0, instances.numInstances());

    m_Train.deleteWithMissingClass();

 

    m_MinArray = new double[m_Train.numAttributes()];

    m_MaxArray = new double[m_Train.numAttributes()];

    for (int i = 0; i < m_Train.numAttributes(); i++) {

       m_MinArray[i] = m_MaxArray[i] = Double.NaN;

    }

       

    Enumeration enu = m_Train.enumerateInstances();

    while (enu.hasMoreElements()) {

       updateMinMax((Instance) enu.nextElement());

    }

}

       是的,KNN也有buildClassifier,听起来蛮奇怪的。第二个if,IB1不能对字符串属性进行学习,因为这种属性不好定义距离,比如a和ab是0.5还是1呢?然类别缺失的样本抛弃。m_MinArray和m_MaxArray分别保存每一个属性的最小值和最大值。最下面是对样本进行循环,找出最大值,最小值,updataMinMax代码如下:

private void updateMinMax(Instance instance) {

 

    for (int j = 0; j < m_Train.numAttributes(); j++) {

       if ((m_Train.attribute(j).isNumeric()) && 

           (!instance.isMissing(j))) {

           if (Double.isNaN(m_MinArray[j])) {

              m_MinArray[j] = instance.value(j);

              m_MaxArray[j] = instance.value(j);

           } else {

               if (instance.value(j) < m_MinArray[j]) {

                  m_MinArray[j] = instance.value(j);

               } else {

                  if (instance.value(j) > m_MaxArray[j]) {

                      m_MaxArray[j] = instance.value(j);

                  }

               }

           }

       }

    }
}

Double.isNaN(m_MinArray[j])判断是不是m_MinArraym_MaxArray已经赋值过了,else,如果可以更新minmax更新。

再看一下classifyInstance函数:

public double classifyInstance(Instance instance) throws Exception {

 

    if (m_Train.numInstances() == 0) {

       throw new Exception("No training instances!");

    }

 

    double distance, minDistance = Double.MAX_VALUE, classValue = 0;

    updateMinMax(instance);

    Enumeration enu = m_Train.enumerateInstances();

    while (enu.hasMoreElements()) {

       Instance trainInstance = (Instance) enu.nextElement();

       if (!trainInstance.classIsMissing()) {

           distance = distance(instance, trainInstance);

           if (distance < minDistance) {

              minDistance = distance;

              classValue = trainInstance.classValue();

           }

       }

    }

 

    return classValue;

}


因为要进化归范化,所以对这个分类的样本再次调用updateMinMax。然后对训练样本进行循环,用distance计算与每一个样本的距离,如果比前面的距离小,则记录,最后返回与测试样本距离最小的样本的类别值。因为要进化归范化,所以对这个分类的样本再次调用updateMinMax。然后对训练样本进行循环,用distance计算与每一个样本的距离,如果比前面的距离小,则记录,最后返回与测试样本距离最小的样本的类别值。

        因为要进化归范化,所以对这个分类的样本再次调用updateMinMax。然后对训练样本进行循环,用distance计算与每一个样本的距离,如果比前面的距离小,则记录,最后返回与测试样本距离最小的样本的类别值。

private double distance(Instance first, Instance second) {

    double diff, distance = 0;

 

    for (int i = 0; i < m_Train.numAttributes(); i++) {

       if (i == m_Train.classIndex()) {

           continue;

       }

       if (m_Train.attribute(i).isNominal()) {

              // If attribute is nominal

           if (first.isMissing(i) || second.isMissing(i)

                  || ((int) first.value(i) != (int) second.value(i))) {

              distance += 1;

           }

       } else {

           // If attribute is numeric

           if (first.isMissing(i) || second.isMissing(i)) {

              if (first.isMissing(i) && second.isMissing(i)) {

                  diff = 1;

              } else {

                  if (second.isMissing(i)) {

                     diff = norm(first.value(i), i);

                  } else {

                     diff = norm(second.value(i), i);

                  }

                  if (diff < 0.5) {

                     diff = 1.0 - diff;

                  }

              }

           } else {

              diff = norm(first.value(i), i) - norm(second.value(i), i);

           }

           distance += diff * diff;

       }

    }

 

    return distance;

}


        和Jiawei Han书里面说的一样,对离散属性来说,两个样本任一在对应属性上为缺失值,距离为1,不相等相然还是为1。对于连续属性,如果两个都是缺失值,距离为1,其中之一在对应属性上为缺失值,把另一个不为缺失值的属性值规范化,距离为1-diff,意思就是设到可能的最远(当然那个缺失值比m_MinArraym_MaxArray还小还大,这就不对了)。如果两个都有值,就把距离相加,最后平方。

为了完整性,将norm列出来:

private double norm(double x, int i) {

 

    if (Double.isNaN(m_MinArray[i])

           || Utils.eq(m_MaxArray[i], m_MinArray[i])) {

       return 0;

    } else {

       return (x - m_MinArray[i]) / (m_MaxArray[i] - m_MinArray[i]);

    }

}


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值