Weka算法Classifier-tree-J48源码分析(四)总结

一、ClassifyInstance

首先先说一下构造好的分类树是如何对一个新的Instance进行区分。

直观上,会对树进行一个检索,从根节点根据属性的不同,最终走到叶子节点,得到具体的分类。

但Weka在实现上,是遍历了这个Instance属于不同的class的可能性,并从中选出了一个最大的,代码如下:

  public double classifyInstance(Instance instance)
    throws Exception {

    double maxProb = -1;
    double currentProb;
    int maxIndex = 0;
    int j;

    for (j = 0; j < instance.numClasses(); j++) {
      currentProb = getProbs(j, instance, 1);
      if (Utils.gr(currentProb,maxProb)) {
	maxIndex = j;
	maxProb = currentProb;
      }
    }

    return (double)maxIndex;
  }

而getProbs函数关键代码如下:

    if (m_isLeaf) {
      return weight * localModel().classProb(classIndex, instance, -1);
    } else {
      int treeIndex = localModel().whichSubset(instance);
      if (treeIndex == -1) {
	double[] weights = localModel().weights(instance);
	for (int i = 0; i < m_sons.length; i++) {
	  if (!son(i).m_isEmpty) {
	    prob += son(i).getProbs(classIndex, instance,
				    weights[i] * weight);
	  }

如果是一个叶子节点,则直接从本节点的分布就能确定当前instance属于相关class的可能性,否则就要取出treeIndex进行判断,这里的treeIndex==-1代表这个Instance属于不同的branch,换句话说,本节点的Model不能对此Instance给出一个确定的划分。

在分类树中这种情况理论上是不会出现的,weka在这里其实是用treeIndex==-1来处理了相关属性缺失的情况。

whichSubset代码如下:

  public final int whichSubset(Instance instance)
       throws Exception {

    if (instance.isMissing(m_attIndex))
      return -1;
    else{
      if (instance.attribute(m_attIndex).isNominal())
	return (int)instance.value(m_attIndex);
      else
	if (Utils.smOrEq(instance.value(m_attIndex),m_splitPoint))
	  return 0;
	else
	  return 1;
    }
  }

如果属性缺失,则直接返回-1,如果是离散值,则根据属性进行选择,如果是连续值,则通过训练时得到的分裂点进行判断。

二、总结

接下来可以回答第二篇博客开头时提到的4个问题了。

1、如何控制分类树的精度。

答:使用minNoObj参数来控制分类树的精度,节点停止分裂的条件有5个:

(1)所有的instances已经属于同一个分类(selectModel里)

(2)instances数量小于2*minNoObj(selectModel里)

(3)一个分裂产生的信息增益石0(selectModel里)

(4)对离散值进行分裂节点的计算时,超过一个的Bag里的instance数量小于minNoObj(spliter里)

(5)对连续值进行分裂计算时,有效instances数量小于2*minNoObj(spliter里)

2、如何处理缺失的值(MissingValue)

答:对缺失值得处理分两种,其一是训练阶段的缺失值处理,方法是直接忽略掉这条记录。在分类阶段对缺失值得处理是,忽略该属性,使其在不同的branch上进行计算,最后将概率结果进行合并。

3、如何对连续值进行离散化。

答:Spliter首先对连续值进行排序,之后从前到后遍历每一个值当做分裂点,对分裂结果计算信息增益率最大的作为最终分裂点构建不同的branch。

4、如何进行分类树的剪枝。

答:略,参见第二篇博客的collapse方法和prune方法。

关于J48差不多也就说到这里了,通过分析源码可以看到Weka的实现和原始的C4.5算法还是有相当多的不一样的地方。下一篇将对RandomForest算法进行分析。

时间: 2024-10-12 03:26:48

Weka算法Classifier-tree-J48源码分析(四)总结的相关文章

Nouveau源码分析(四):NVIDIA设备初始化之nouveau_drm_load (1)

Nouveau源码分析(四) probe函数成功返回之后,DRM模块就会调用struct drm_driver的load函数,对应nouveau的nouveau_drm_load. 这个函数虽然看起来不是特别长,但每一个调用的函数展开后就会变得非常长了! // /drivers/gpu/drm/nouveau/nouveau_drm.c 364 static int 365 nouveau_drm_load(struct drm_device *dev, unsigned long flags)

baksmali和smali源码分析(四)

baksmali 首先执行的第一个main 函数     public static void main(String[] args) throws IOException {         Locale locale = new Locale("en", "US");         Locale.setDefault(locale);         CommandLineParser parser = new PosixParser();         C

mybatis源码分析(四) mybatis与spring事务管理分析

mybatis源码分析(四) mybatis与spring事务管理分析 一丶从jdbc的角度理解什么是事务 从mysql获取一个连接之后, 默认是自动提交, 即执行完sql之后, 就会提交事务. 这种事务的范围是一条sql语句. 将该连接设置非自动提交, 可以执行多条sql语句, 然后由程序决定是提交事务, 还是回滚事务. 这也是我们常说的事务. Connection connection = dataSource.getConnection(); // connection.setTransa

ABP源码分析四十六:ABP ZERO中的Ldap模块

通过AD作为用户认证的数据源.整个管理用户认证逻辑就在LdapAuthenticationSource类中实现. LdapSettingProvider:定义LDAP的setting和提供DefautValue.主要提供配置访问AD数据库的账号信息. LdapSettings/ILdapSettings:通过settingManager获取LDAP settings AbpZeroLdapModuleConfig/IAbpZeroLdapModuleConfig: 提供激活Ldap认证的配置.

ABP源码分析四十七:ABP中的异常处理

ABP 中异常处理的思路是很清晰的.一共五种类型的异常类. AbpInitializationException用于封装ABP初始化过程中出现的异常,只要抛出AbpInitializationException异常就可以,无须做额外处理.这类异常往往是需要维护人员介入分析的. 其他四个异常都在AbpController中被集中处理,处理分为两步:一,通过EventBus触发异常事件,相应的异常处理函数则处理异常.而针对AbpValidationException,UserFriendlyExce

docker 源码分析 四(基于1.8.2版本),Docker镜像的获取和存储

前段时间一直忙些其他事情,docker源码分析的事情耽搁了,今天接着写,上一章了解了docker client 和 docker daemon(会启动一个http server)是C/S的结构,client端发出的命令由docker daemon接收并处理. 我们在运行docker的时候,可能会使用到docker run命令(当然通过Dockerfile运行docker build命令也是一样的)时,如果本地没有你需要的镜像,docker daemon首先会去下载你需要的docker镜像,然后存

ABP源码分析四十一:ZERO的Audit,Setting,Background Job

AuditLog: 继承自Entity<long>的实体类.封装AuditLog的信息. AuditingStore: 实现了IAuditingStore接口,实现了将AuditLog的信息保存到数据库的功能.其通过IRepository<AuditLog, long>实例完成对数据库的操作. BackgroundJobStore :  实现了IBackgroundJobStore接口,通过IRepository<BackgroundJobInfo, long>完成对B

ABP源码分析四十五:ABP ZERO中的EntityFramework模块

AbpZeroDbContext:配置ABP.Zero中定义的entity的Dbset EntityFrameworkModelBuilderExtensions:给PrimitivePropertyConfiguration添加了扩展方法用于创建Index. AbpZeroDbModelBuilderExtensions:给DbModelBuilder添加了扩展方法用于表的重命名. AbpZeroEntityFrameworkModule:很明显Abp Zero模块中的EntityFramew

ABP源码分析四十:ZERO的Application和Tenant

ABP的Zero模块以数据库为数据源实现了ABP框架中的tenant management (multi-tenancy), role management, user management, session, authorization (permission management), setting management, language management, audit logging等核心功能.ABP中的这些功能具体实现都依赖外部的持久层,所以ABP框架中仅仅定义了接口和一些空的实现

YARN源码分析(四)-----Journalnode

前言 最近在排查公司Hadoop集群性能问题时,发现Hadoop集群整体处理速度非常缓慢,平时只需要跑几十分钟的任务时间一下子上张到了个把小时,起初怀疑是网络原因,后来证明的确是有一部分这块的原因,但是过了没几天,问题又重现了,这次就比较难定位问题了,后来分析hdfs请求日志和Ganglia的各项监控指标,发现namenode的挤压请求数持续比较大,说明namenode处理速度异常,然后进而分析出是因为写journalnode的editlog速度慢问题导致的,后来发现的确是journalnode