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

来源:互联网 发布:java gui图形界面编程 编辑:程序博客网 时间:2024/06/06 06:33

转自 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]);    }}


 

原创粉丝点击