为什么80%的码农都做不了架构师?>>>   

这次介绍一下Id3源码,这次用Weka的源码介绍一下。首先Id3是继承于Classifier的:

public class Id3 extends Classifier

Id3[]成员变量是递归保存树的变量,数据中每一个元素都是当前结点的子结点。

/** The node's successors. */

private Id3[] m_Successors;

Attribute是属性类,m_Attribute是分裂属性

/** Attribute used for splitting. */

private Attribute m_Attribute;

如果当前结果是叶子结点,m_ClassValue是类别,到底double代表什么,以前讲过了,一会再讲

/** Class value if node is leaf. */

private double m_ClassValue;

Distribution表示的是这个结点属于某个类别的概率,如m_Distribution[0] == 0.1表示当前结点属于类别0的概率为0.1

/** Class distribution if node is leaf. */

private double[] m_Distribution;

数据集的类别,以前也讲过了

/** Class attribute of dataset. */

private Attribute m_ClassAttribute;

以前也讲过,继承自Classifier类的类都要实现buildClassifier函数。

public void buildClassifier(Instances data) throws Exception {

// can classifier handle the data?

getCapabilities().testWithFail(data);

// remove instances with missing class

data = new Instances(data);

data.deleteWithMissingClass();

makeTree(data);

}

getCapabilities().testWithFail(data)是判断是否ID3能处理选择的数据集,比如什么连续属性,类别索引没有设置等等。

而data.deleteWithMissingClass则是删除有缺失样本的函数,具体代码如下:

for (int i = 0; i < numInstances(); i++) {

if (!instance(i).isMissing(attIndex)) {

newInstances.addElement(instance(i));

}

}

m_Instances = newInstances;

简单一点,不用为上面的东西分心,关注makeTree(data)就行了:

// Compute attribute with maximum information gain.

double[] infoGains = new double[data.numAttributes()];

Enumeration attEnum = data.enumerateAttributes();

while (attEnum.hasMoreElements()) {

Attribute att = (Attribute) attEnum.nextElement();

infoGains[att.index()] = computeInfoGain(data, att);

}

m_Attribute = data.attribute(Utils.maxIndex(infoGains));

infoGains保存每个属性的信息增益(IG),枚举每个属性,用computeInfoGain函数计算信息增益值。Util.maxIndex返回信息增益最大的下标,这个属性作为分裂属性保存在m_Attribute成员变量中。

// Make leaf if information gain is zero.

if (Utils.eq(infoGains[m_Attribute.index()], 0)) {

m_Attribute = null;

m_Distribution = new double[data.numClasses()];

Enumeration instEnum = data.enumerateInstances();

while (instEnum.hasMoreElements()) {

Instance inst = (Instance) instEnum.nextElement();

m_Distribution[(int) inst.classValue()]++;

}

Utils.normalize(m_Distribution);

m_ClassValue = Utils.maxIndex(m_Distribution);

m_ClassAttribute = data.classAttribute();

}

当信息增益等于0时为叶子结点(这为什么再讲,就没完了)。

m_Attribute = null,已经不用再分裂了,所以为null。刚才也说过m_Distribution保存的是当前结点属于类别的概率,所以数组大小于data.numClasses()。枚举当前结点中的每一个样本,inst.classValue()就是inst样本的类别值,请注意不要以为类别都是”good”,”bad”之类的值,而是第一个类别就是0,第二个类别就是1的double型。

m_Distribution[(int) inst.classValue()]++;也就是将每个样本的相应的下标加1,比如当前叶子结点有10个样本,9个属于第一个类别,1个属于第五个类别,则m_Distribution[0]=9,m_Distribution[4]=1。

Utils.normalize(m_Distribution);简单地理解为归一化吧,刚在例子也就是m_Distribution[0]=9,m_Distribution[4]=0.1。(提醒一下,这个例子应该是不会发生的,包括开始的那个例子,为什么就不解释了)

m_ClassValue = Utils.maxIndex(m_Distribution);属于哪个类别的概率最高,那当然就是哪个类别,在刚才失败的例子中也就是m_ClassValue == 0。

m_ClassAtrribute也就是类别属性。

// Otherwise create successors.

else {

Instances[] splitData = splitData(data, m_Attribute);

m_Successors = new Id3[m_Attribute.numValues()];

for (int j = 0; j < m_Attribute.numValues(); j++) {

m_Successors[j] = new Id3();

m_Successors[j].makeTree(splitData[j]);

}

}

如果信息增益不是0那么分裂当前结点,在splitData(data, m_Attribute)函数中,data被分裂成m_Attribute离散值个子结点,比如m_Attribute有三种取值”green”,”red”,”blue”,则splitData将data分成3部分到splitData中。

在例子中当前结点有3个子结点,则m_Attribute.numValues()==3,递归地makeTree。(再讲清楚点,也就是每一个子树都是一个决策树,所以new Id3())

这里有一个问题,如果在例中,当前结点的green子结点没有样本,那么:

// Check if no instances have reached this node.

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

m_Attribute = null;

m_ClassValue = Instance.missingValue();

m_Distribution = new double[data.numClasses()];

return;

}

这就没什么好解释的了。

对于分类一个样本:

if (m_Attribute == null) {

return m_ClassValue;

} else {

return m_Successors[(int) instance.value(m_Attribute)]

.classifyInstance(instance);

}

当然也是递归了,如果已经到达叶子结点了,那直接返回类别值。不是叶子结点,那么根据样本属性值到相应的子结点,再调用classifyInstance(instance)。

还有distributionForInstance也差不多,不作解释了:

if (m_Attribute == null) {

return m_Distribution;

} else {

return m_Successors[(int) instance.value(m_Attribute)]

.distributionForInstance(instance);

}

computeInfoGain和computeEntropy两个函数也不解释了,不过还是应该看一下,有时候还能用的着(最重要的其实是,这都不懂,也过份了点吧)。

分裂结点的函数:

private Instances[] splitData(Instances data, Attribute att) {

Instances[] splitData = new Instances[att.numValues()];

for (int j = 0; j < att.numValues(); j++) {

splitData[j] = new Instances(data, data.numInstances());

}

Enumeration instEnum = data.enumerateInstances();

while (instEnum.hasMoreElements()) {

Instance inst = (Instance) instEnum.nextElement();

splitData[(int) inst.value(att)].add(inst);

}

for (int i = 0; i < splitData.length; i++) {

splitData[i].compactify();

}

return splitData;

}

将data分裂成att.numValues()个子结点,inst.value(att)就是根据inst样本att属性值将inst样本分成相应的子结点中。(确切点,也不是子结点,一个Instances数组元素)

转载于:https://my.oschina.net/piorcn/blog/518346

Weka开发[8]-ID3源码介绍相关推荐

  1. Weka开发[11]—J48源代码介绍

    为什么80%的码农都做不了架构师?>>>    这次介绍一下J48的源码,分析J48的源码似乎真还是有用的,同学改造J48写过VFDT,我自己用J48进行特征选择(当然很失败). J ...

  2. [转]Framework源码查看

    http://weblogs.asp.net/scottgu/archive/2008/01/16/net-framework-library-source-code-now-available.as ...

  3. [1]elasticsearch源码编译

    本文是elasticsearch源码分析系列文档的第一篇,本篇简单介绍了elasticsearch源码在本机的编译环境搭建 用到的工具有:IntelliJ Idea,JDK1.8,gradle3.5, ...

  4. Weka 开发[1]-Instances类

    先google一下,把Weka软件下载下来,安装完成之后,在Weka的安装目录中有一个weka.jar的包. 把包添加到工程中后,就可以调用weka中的函数了. 再介绍一点weka的基本知识,在wek ...

  5. MultiRow发现之旅(六)- 使用MultiRow开发票据应用(附源码)

    前文回顾 MultiRow发现之旅(一)- 高效模板设计器 MultiRow发现之旅(二)- 详解属性管理器 MultiRow发现之旅(三)- 模板管理器和Table MultiRow发现之旅(四)- ...

  6. 微信小程序:二开版优化新紫色UI云开发新款壁纸小程序源码

    这是一款由旧版https://airymz.com/3387.html进行优化二开的一个新版本 本壁纸表情包头像小程序采用(dcloud云开发)所以无需服务器与域名 无需服务器.无需域名.云开发直接上 ...

  7. 二开版优化新紫色UI云开发新款壁纸小程序源码支持用户投稿在线审核

    本壁纸表情包头像小程序采用(dcloud云开发)所以无需服务器与域名 无需服务器.无需域名.云开发直接上线 特点:支持用户投稿,后台审核后会发订阅消息给用户提示作品审核状态,增加用户粘性,支持后端修改 ...

  8. 基于微信小程序云开发的投票小程序源码,图文投票微信小程序源码

    功能介绍 投票活动十分火,商家,企业,机构偶尔都会来一场投票活动评选,本小程序支持图文投票,简单方便.随时随地完成投票,可以方便设定投票模式(按天按全程,投票数限定). 本代码前后端完整代码包投票列表 ...

  9. 抖音seo源码二次开发,短视频seo源码二次开发

    抖音seo源码二次开发,短视频seo源码二次开发 开发逻辑及部分代码展示 抖音seo系统前端采用vue 与React技术语言,后端采用jave后台技术语言. 抖音seo是什么技术逻辑呢?seo是搜索引 ...

最新文章

  1. Springcloud Feign原理
  2. iOS UITableView的方法解析
  3. Python视频处理库:scikit-video
  4. 如何把OpenCV Python获取的图像传递到C层处理
  5. php-fpm 配置文件位置,php
  6. 第五周 Leetcode 99. Recover Binary Search Tree (HARD)
  7. 蓝桥杯 迷宫与陷阱 BFS
  8. oracle 行数大于一时,oracle – PL / SQL ORA-01422:精确的提取返回超过请求的行数
  9. android uboot获取mac地址,uboot生成随机的MAC地址
  10. 原生App vs 移动Web App : 你如何选择
  11. Arcis矢量化边界问题处理
  12. 弘辽科技:拼多多运营做好竞品分析。
  13. 推荐7款珍藏已久的手机APP,非常实用
  14. 中国移动通信互联网短信网关接口协议及相关下载
  15. PDF删除水印与添加水印方法介绍
  16. 分布式服务框架Dubbo/Dubbox入门示例
  17. 霍尔开关在行车记录仪中起速度检测作用
  18. 无线通信网络优化的自动路测系统设计(Matlab代码实现)
  19. Android Adapter的使用
  20. 全程复制粘贴,在家用手机就可以做自媒体,每月稳定4000多

热门文章

  1. spring boot2 坑 - 解决cros跨域问题
  2. eclipse中svn插件的工程不能与svn资源库同步的解决方法
  3. Android WebView重定向问题的解决方案
  4. 读取和写入文件的最简单方法
  5. Homebrew:无法符号链接,/ usr / local / bin不可写[关闭]
  6. 如何以编程方式确定Java中的操作系统?
  7. 子集数据帧中的丢包因子级别
  8. 如何安全地创建嵌套目录?
  9. Shiro 单点登录
  10. 批量修改文件名称的方法