机器学习IB1算法的weka源码详细解析(1NN)

  机器学习的1NN最近邻算法,在weka里叫IB1,是因为Instance Base  1 ,也就是只基于一个最近邻的实例的惰性学习算法。

  下面总结一下,weka中对IB1源码的学习总结。

  首先需要把 weka-src.jar 引入编译路径,否则无法跟踪源码。

  1)读取data数据,完成 IB1 分类器的调用,结果预测评估。为了后面的跟踪。

try {
            File file = new File("F:\\tools/lib/data/contact-lenses.arff");

            ArffLoader loader = new ArffLoader();
            loader.setFile(file);
            ins = loader.getDataSet();

            // 在使用样本之前一定要首先设置instances的classIndex,否则在使用instances对象是会抛出异常
            ins.setClassIndex(ins.numAttributes() - 1);

            cfs = new IB1();
            cfs.buildClassifier(ins);

            Instance testInst;
            Evaluation testingEvaluation = new Evaluation(ins);
            int length = ins.numInstances();
            for (int i = 0; i < length; i++) {
                testInst = ins.instance(i);
                // 通过这个方法来用每个测试样本测试分类器的效果
                double predictValue = cfs.classifyInstance(testInst);

                System.out.println(testInst.classValue()+"--"+predictValue);
            }

           // System.out.println("分类器的正确率:" + (1 - testingEvaluation.errorRate()));

        } catch (Exception e) {
            e.printStackTrace();
        }

2)ctrl 点击buildClassifier,进一步跟踪buildClassifier方法的源码,在IB1的类中重写了这个抽象方法,源码为:

public void buildClassifier(Instances instances) throws Exception {

    // can classifier handle the data?
    getCapabilities().testWithFail(instances);

    // remove instances with missing class
    instances = new Instances(instances);
    instances.deleteWithMissingClass();

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

    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());
    }
  }

  (1)if是判断,IB1分类器不能处理属性是字符串和类别是数值型的样本;

  (2)if是判断,删除没有类标签的样本;

  (3)m_MinArray 和 m_MaxArray 分别保存最小和最大值,并且初始化double数组【样本个数】;

  (4)遍历所有的训练样本实例,求最小和最大值;继续跟踪updateMinMax方法;

  3)IB1类的updateMinMax方法的源码如下:

  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);
        }
      }
    }
      }
    }
  }

  (1)过滤掉属性不是数值型和缺失标签的实例;

  (2)若是isNaN,is not a number,是数值型的话,循环遍历样本的每一个属性,求出最大最小值;

  到此为止,训练了IB1模型(有人可能会问lazy的算法难道不是不需要训练模型吗?我认为build分类器是为了初始化 m_Train和求所有实例的每个属性的最大最小值,为了下一步求distance做准备)

下面介绍下预测源码:

  

  4)跟踪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;
  }

  (1)调用方法updateMinMax更新了加入测试实例后的最大最小值;

  (2)计算测试实例到每一个训练实例的距离,distance方法,并且保存距离最小的实例minDistance;

  5)跟踪classifyInstance方法,源码如下:

 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;
  }

  对每一个属性遍历,计算数值属性距离的平方和,norm方法为规范化距离公式,为【0,1】的实数  

  6)跟踪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]);
    }
  }

  规范化距离:(x - m_MinArray[i]) / (m_MaxArray[i] - m_MinArray[i]);

  

具体的算法伪代码,请查找最近邻分类器的论文,我就不贴出来了。

时间: 2024-11-08 05:19:16

机器学习IB1算法的weka源码详细解析(1NN)的相关文章

HashMap 源码详细解析 (JDK1.8)

概要 HashMap 最早出现在 JDK 1.2 中,底层基于散列算法实现.HashMap 允许 null 键和 null 值,在计算哈键的哈希值时,null 键哈希值为 0.HashMap 并不保证键值对的顺序,这意味着在进行某些操作后,键值对的顺序可能会发生变化.另外,需要注意的是,HashMap 是非线程安全类,在多线程环境下可能会存在问题. HashMap 底层是基于散列算法实现,散列算法分为散列再探测和拉链式.HashMap 则使用了拉链式的散列算法,并在 JDK 1.8 中引入了红黑

(干货) Android Volley框架源码详细解析

前言 经常接触Android网络编程的我们,对于Volley肯定不陌生,但我们不禁要问,对于Volley我们真的很了解吗?Volley的内部是怎样实现的?为什么几行代码就能快速搭建好一个网络请求?我们不但要知其然,也要知其所以然,抱着这样的目的,本文主要详细讲述Volley的源码,对内部流程进行详细解析. Part 1.从RequestQueue说起 (1)还记得搭建请求的第一步是什么吗?是新建一个请求队列,比如说这样: RequestQueue queue = Volley.newReques

ArrayList源码详细解析分析

目录[-] 1.概述 2 Arraylist的实现 2.1 底层利用object数组实现 2.2 构造方法 2.3  存储 2.4 删除 3. Arrays.copyOf 4. 关于native 5 Array.newInstance()的意义 6  为什么elementData 要声明为transient变量 7 为何要序列化,不是在内存中吗 8  总结 1.概述 ArrayList是List接口的可变数组的实现.实现了所有可选列表操作,并允许包括 null 在内的所有元素.除了实现 List

OpenStack_Swift源码分析——创建Ring及添加设备源码详细分析

1 创建Ring 代码详细分析 在OpenStack_Swift--Ring组织架构中我们详细分析了Ring的具体工作过程,下面就Ring中增加设备,删除设备,已经重新平衡的实现过程作详细的介绍. 首先看RingBuilder类 def __init__(self, part_power, replicas, min_part_hours): #why 最大 2**32 if part_power > 32: raise ValueError("part_power must be at

OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波

http://blog.csdn.net/chenyusiyuan/article/details/8710462 OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波 2013-03-23 17:44 16963人阅读 评论(28) 收藏 举报 分类: 机器视觉(34) 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] KAZE系列笔记: OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波 OpenCV学习笔记(28)KA

weka源码在eclipse的配置和VerifyError异常的解决

今天把weka源码导入eclipse,打算学习下weka源码,遇到一些问题,网上资料不足,自己总结下,希望为后来人铺路. 1)新建java项目,命名weka3-6 2)把weka-src.jar解压,再把src\main\java\weka文件拽到项目的src目录 3)把weka-src\lib目录的三个jar包引进 运行main函数出现VerifyError异常,如下: java.lang.VerifyError: Expecting a stackmap frame at branch ta

基于Docker的TensorFlow机器学习框架搭建和实例源码解读

概述:基于Docker的TensorFlow机器学习框架搭建和实例源码解读,TensorFlow作为最火热的机器学习框架之一,Docker是的容器,可以很好的结合起来,为机器学习或者科研人员提供便捷的机器学习开发环境,探索人工智能的奥秘,容器随开随用方便快捷.源码解析TensorFlow容器创建和示例程序运行,为热爱机器学者降低学习难度. 默认机器已经装好了Docker(Docker安装和使用可以看我另一篇博文:Ubuntu16.04安装Docker1.12+开发实例+hello world+w

基于LNMP的Zabbbix之Zabbix Agent源码详细安装,但不给图

基于LNMP的Zabbbix之Zabbix Server源码详细安装:http://www.cnblogs.com/losbyday/p/5828547.html wget http://jaist.dl.sourceforge.net/project/zabbix/ZABBIX%20Latest%20Stable/3.0.3/zabbix-3.0.3.tar.gz tar zxf zabbix-3.0.3.tar.gz cd zabbix-3.0.3 ./configure --prefix=

iOS下使用SHA1WithRSA算法加签源码

首先了解一下几个相关概念,以方便后面遇到的问题的解决: RSA算法:1977年由Ron Rivest.Adi Shamirh和LenAdleman发明的,RSA就是取自他们三个人的名字.算法基于一个数论:将两个大素数相乘非常容易,但要对这个乘积的结果进行因式分解却非常困难,因此可以把乘积公开作为公钥.该算法能够抵抗目前已知的所有密码攻击.RSA算法是一种非对称算法,算法需要一对密钥,使用其中一个加密,需要使用另外一个才能解密.我们在进行RSA加密通讯时,就把公钥放在客户端,私钥留在服务器. PE