Weka源码学习-J48(一)-决策树的剪枝

#J48.class 1 /**
 2    * Generates the classifier.
 3    *
 4    * @param instances the data to train the classifier with
 5    * @throws Exception if classifier can‘t be built successfully
 6    */
 7   @Override
 8   public void buildClassifier(Instances instances) throws Exception {
 9
10     ModelSelection modSelection;
11
12     if (m_binarySplits) {//是否为二分树
13       modSelection = new BinC45ModelSelection(m_minNumObj, instances,
14         m_useMDLcorrection, m_doNotMakeSplitPointActualValue);
15     } else {
16       modSelection = new C45ModelSelection(m_minNumObj, instances,
17         m_useMDLcorrection, m_doNotMakeSplitPointActualValue);
18     }
19     if (!m_reducedErrorPruning) {//构造相应的树
20       m_root = new C45PruneableClassifierTree(modSelection, !m_unpruned, m_CF,
21         m_subtreeRaising, !m_noCleanup, m_collapseTree);
22     } else {
23       m_root = new PruneableClassifierTree(modSelection, !m_unpruned,
24         m_numFolds, !m_noCleanup, m_Seed);
25     }
26     m_root.buildClassifier(instances);//在树上真正构建模型
27     if (m_binarySplits) {
28       ((BinC45ModelSelection) modSelection).cleanup();
29     } else {
30       ((C45ModelSelection) modSelection).cleanup();
31     }
32   }
#C45PruneableClassifierTree.class 1 /**
 2    * Method for building a pruneable classifier tree.
 3    *
 4    * @param data the data for building the tree
 5    * @throws Exception if something goes wrong
 6    */
 7   public void buildClassifier(Instances data) throws Exception {
 8
 9     // can classifier tree handle the data?
10     getCapabilities().testWithFail(data);//testWithFail检测传入的data是否能用该分类器进行分类,例如C45只能对要分类的属性的取值是离散值的Instances进行分类
11
12     // remove instances with missing class
13     data = new Instances(data);
14     data.deleteWithMissingClass();//清理instances里面的无效行(相应分类属性为空的行)
15
16    buildTree(data, m_subtreeRaising || !m_cleanup);
17    if (m_collapseTheTree) {
18      collapse();
19    }
20    if (m_pruneTheTree) {
21      prune();
22    }
23    if (m_cleanup) {
24      cleanup(new Instances(data, 0));
25    }
26   }
#ClassifierTree.class 1 /**
 2    * Builds the tree structure.
 3    *
 4    * @param data the data for which the tree structure is to be generated.
 5    * @param keepData is training data to be kept?
 6    * @throws Exception if something goes wrong
 7    */
 8   public void buildTree(Instances data, boolean keepData) throws Exception {
 9
10     Instances[] localInstances;
11
12     if (keepData) {//根据传入参数来判断是否应该持有数据
13       m_train = data;
14     }
15     m_test = null;
16     m_isLeaf = false;
17     m_isEmpty = false;
18     m_sons = null;
19     m_localModel = m_toSelectModel.selectModel(data);//根据m_toSelectModel来选择一个模型并把传入的数据集按相应的规则分成不同的subSet
20     if (m_localModel.numSubsets() > 1) {//判断subSet的数量,大于1
21       localInstances = m_localModel.split(data);//根据localModel将data分成不同的subInstances
22       data = null;
23       m_sons = new ClassifierTree[m_localModel.numSubsets()];//为每一个subInstances建立新的ClassifierTree节点作为自己的孩子节点
24       for (int i = 0; i < m_sons.length; i++) {
25         m_sons[i] = getNewTree(localInstances[i]);//调用getNewTree函数来为每一个subInstances构造新的tree
26         localInstances[i] = null;
27       }
28     } else {//subSet的数量等于1,那么它是叶子节点
29       m_isLeaf = true;
30       if (Utils.eq(data.sumOfWeights(), 0)) {
31         m_isEmpty = true;
32       }
33       data = null;
34     }
35   }
#C45PruneableClassifierTree.class 1 /**
 2    * Collapses a tree to a node if training error doesn‘t increase.
 3    */
 4   public final void collapse(){
 5
 6     double errorsOfSubtree;//该节点孩子节点的误差总和
 7     double errorsOfTree;//该节点的误差
 8     int i;
 9
10     if (!m_isLeaf){
11       errorsOfSubtree = getTrainingErrors();//估计孩子节点错误的总和
12       errorsOfTree = localModel().distribution().numIncorrect();//估计当前节点的错误,即获得当前训练集上的一个分布,然后找出该分布里数量最多的那个属性的数量,认为是“正确的”,则其余的就是错误的。
13       if (errorsOfSubtree >= errorsOfTree-1E-3){//如果该节点孩子节点并不能提高这颗分类树的准确度,则把这些孩子节点删除。
14
15     // Free adjacent trees
16     m_sons = null;
17     m_isLeaf = true;
18
19     // Get NoSplit Model for tree.
20     m_localModel = new NoSplit(localModel().distribution());
21       }else//否则就在每个孩子上递归此方法
22     for (i=0;i<m_sons.length;i++)
23       son(i).collapse();
24     }
25   }

#C45PruneableClassifierTree.class
 1 /**
 2    * Prunes a tree using C4.5‘s pruning procedure.
 3    *
 4    * @throws Exception if something goes wrong
 5    */
 6   public void prune() throws Exception {
 7
 8     double errorsLargestBranch;//如果该节点有孩子节点,那么该节点的孩子节点中分到的数据最多的节点的分类错误的用例数
 9     double errorsLeaf;//如果该节点是叶子节点,该节点分类错误的用例数
10     double errorsTree;//该节点目前情况下,分类错误用例数
11     int indexOfLargestBranch;////分到最多数据的孩子节点在son数组中的index
12     C45PruneableClassifierTree largestBranch;
13     int i;
14
15     if (!m_isLeaf){//如果当前节点不是叶子节点,则先对其所有孩子节点进行剪枝。
16
17       // Prune all subtrees.
18       for (i=0;i<m_sons.length;i++)
19     son(i).prune();
20
21       // Compute error for largest branch
22       indexOfLargestBranch = localModel().distribution().maxBag();
23       if (m_subtreeRaising) {///m_subtreeRaising代表可否使用该树的子树去替代该树,如果可以,就去计算最大的子树的错误数量
24     errorsLargestBranch = son(indexOfLargestBranch).
25       getEstimatedErrorsForBranch((Instances)m_train);//估计错误数量,根据分布做一个统计(还要加一个基于m_CF的修正),如果不是叶子节点则递归的进行统计。
26       } else {///否则就简单的标Double.Max_Value
27     errorsLargestBranch = Double.MAX_VALUE;
28       }
29
30       // Compute error if this Tree would be leaf
31       errorsLeaf =
32     getEstimatedErrorsForDistribution(localModel().distribution());////如果该节点是叶子节点,该节点分类错误的用例数
33
34       // Compute error for the whole subtree
35       errorsTree = getEstimatedErrors();//估计该节点目前情况下,分类错误用例数
36
37       // Decide if leaf is best choice.
38       if (Utils.smOrEq(errorsLeaf,errorsTree+0.1) &&
39       Utils.smOrEq(errorsLeaf,errorsLargestBranch+0.1)){//如果当前节点作为叶子节点的错误量比目前情况低,并且比最大的子树的错误量也低,那么就把当前节点作为叶子节点。
40
41     // Free son Trees
42     m_sons = null;
43     m_isLeaf = true;
44
45     // Get NoSplit Model for node.
46     m_localModel = new NoSplit(localModel().distribution());
47     return;//直接返回
48       }
49
50       // Decide if largest branch is better choice
51       // than whole subtree.
52       if (Utils.smOrEq(errorsLargestBranch,errorsTree+0.1)){//如果当前节点的错误用例数大于最大子树,则用最大子树替代当前节点。
53     largestBranch = son(indexOfLargestBranch);
54     m_sons = largestBranch.m_sons;
55     m_localModel = largestBranch.localModel();
56     m_isLeaf = largestBranch.m_isLeaf;
57     newDistribution(m_train);
58     prune();
59       }
60     }
61   }
#PruneableClassifierTree.class

 1 /**
 2    * Method for building a pruneable classifier tree.
 3    *
 4    * @param data the data to build the tree from
 5    * @throws Exception if tree can‘t be built successfully
 6    */
 7   public void buildClassifier(Instances data)
 8        throws Exception {
 9
10     // can classifier tree handle the data?
11     getCapabilities().testWithFail(data);
12
13     // remove instances with missing class
14     data = new Instances(data);
15     data.deleteWithMissingClass();
16
17    Random random = new Random(m_seed);
18    data.stratify(numSets);
19    buildTree(data.trainCV(numSets, numSets - 1, random),
20          data.testCV(numSets, numSets - 1), !m_cleanup);//训练集和测试集一起传入
21    if (pruneTheTree) {
22      prune();
23    }
24    if (m_cleanup) {
25      cleanup(new Instances(data, 0));
26    }
27   }
#ClassifierTree.class 

 1  /**
 2    * Builds the tree structure with hold out set
 3    *
 4    * @param train the data for which the tree structure is to be generated.
 5    * @param test the test data for potential pruning
 6    * @param keepData is training Data to be kept?
 7    * @throws Exception if something goes wrong
 8    */
 9   public void buildTree(Instances train, Instances test, boolean keepData)
10     throws Exception {
11
12     Instances[] localTrain, localTest;
13     int i;
14
15     if (keepData) {
16       m_train = train;
17     }
18     m_isLeaf = false;
19     m_isEmpty = false;
20     m_sons = null;
21     m_localModel = m_toSelectModel.selectModel(train, test);
22     m_test = new Distribution(test, m_localModel);
23     if (m_localModel.numSubsets() > 1) {
24       localTrain = m_localModel.split(train);
25       localTest = m_localModel.split(test);//selectModel时把test传进去
26       train = null;
27       test = null;
28       m_sons = new ClassifierTree[m_localModel.numSubsets()];
29       for (i = 0; i < m_sons.length; i++) {
30         m_sons[i] = getNewTree(localTrain[i], localTest[i]);
31         localTrain[i] = null;
32         localTest[i] = null;
33       }
34     } else {
35       m_isLeaf = true;
36       if (Utils.eq(train.sumOfWeights(), 0)) {
37         m_isEmpty = true;
38       }
39       train = null;
40       test = null;
41     }
42   }
#PruneableClassifierTree.class 1  /**
 2    * Prunes a tree.
 3    *
 4    * @throws Exception if tree can‘t be pruned successfully
 5    */
 6   public void prune() throws Exception {
 7
 8     if (!m_isLeaf) {
 9
10       // Prune all subtrees.
11       for (int i = 0; i < m_sons.length; i++)
12     son(i).prune();
13
14       // Decide if leaf is best choice.
15       if (Utils.smOrEq(errorsForLeaf(),errorsForTree())) {
16
17     // Free son Trees
18     m_sons = null;
19     m_isLeaf = true;
20
21     // Get NoSplit Model for node.
22     m_localModel = new NoSplit(localModel().distribution());
23       }
24     }
25   }

剪枝过程:根据已有数据集的分布,判断该树、该树的最大子树、以及该树作为叶子节点时的正确率,在此基础上进行剪枝。

时间: 2024-08-08 04:58:08

Weka源码学习-J48(一)-决策树的剪枝的相关文章

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

FireMonkey 源码学习(5)

(5)UpdateCharRec 该函数的源码分析如下: procedure TTextLayoutNG.UpdateCharRec(const ACanvas: TCanvas; NeedBitmap: Boolean; var NewRec: PCharRec; HasItem: Boolean; const CharDic: TCharDic; const AFont: TFont; const Ch: UCS4Char; const NeedPath: Boolean = False);

jquery源码学习

jQuery 源码学习是对js的能力提升很有帮助的一个方法,废话不说,我们来开始学习啦 我们学习的源码是jquery-2.0.3已经不支持IE6,7,8了,因为可以少学很多hack和兼容的方法. jquery-2.0.3的代码结构如下 首先最外层为一个闭包, 代码执行的最后一句为window.$ = window.jquery = jquery 让闭包中的变量暴露倒全局中. 传参传入window是为了便于压缩 传入undefined是为了undifined被修改,他是window的属性,可以被修

Hadoop源码学习笔记(1) ——第二季开始——找到Main函数及读一读Configure类

Hadoop源码学习笔记(1) ——找到Main函数及读一读Configure类 前面在第一季中,我们简单地研究了下Hadoop是什么,怎么用.在这开源的大牛作品的诱惑下,接下来我们要研究一下它是如何实现的. 提前申明,本人是一直搞.net的,对java略为生疏,所以在学习该作品时,会时不时插入对java的学习,到时也会摆一些上来,包括一下设计模式之类的.欢迎高手指正. 整个学习过程,我们主要通过eclipse来学习,之前已经讲过如何在eclipse中搭建调试环境,这里就不多述了. 在之前源码初

HSQLDB源码学习——数据库安装启动及JDBC连接

HSQLDB 是一个轻量级的纯Java开发的开放源代码的关系数据库系统.因为HSQLDB的轻量(占用空间小),使用简单,支持内存运行方式等特点,HSQLDB被广泛用于开发环境和某些中小型系统中. 在http://sourceforge.net/projects/hsqldb/files/下载了HSQLDB 1.8.0版本.把下载的zip文件解压缩至任意目录例如c:\hsqldb1.8便完成安装. hsqldb有四种运行模式: 一.内存(Memory-Only)模式:所有数据都在内存里操作.应用程

lodash源码学习(10)

_.delay(func, wait, [args]) 延迟wait毫秒之后调用该函数,添加的参数为函数调用时的参数 //delay.js var baseDelay = require('./_baseDelay'),//baseDelay方法 baseRest = require('./_baseRest'),//创建使用rest参数方法 toNumber = require('./toNumber');//转化为数字 /** * * @param {Function} func 需要延迟执

lodash源码学习(2)

继续学习lodash,依然是数组的方法 “Array” Methods _.indexOf(array, value, [fromIndex=0]) 获取value在数组 array所在的索引值 使用 SameValueZero方式比较(第一个全等===的元素). 如果 fromIndex 值是负数, 则从array末尾起算 该方法依赖于strictIndexOf和baseIndexOf方法,先看它们的源码 //_strictIndexOf.js /** * _.indexOf的专业版本,对元素

jQuery源码学习感想

还记得去年(2015)九月份的时候,作为一个大四的学生去参加美团霸面,结果被美团技术总监教育了一番,那次问了我很多jQuery源码的知识点,以前虽然喜欢研究框架,但水平还不足够来研究jQuery源码,那时我不明白他们为何要求那么高,现在才知道,原来没那么高,他问的都是jQuery最基本的框架架构,不过对于不知道的来说,再简单我也是不知道,那时写了一篇博文去吐槽了一下,那时候也是我自己真正激发自己的时候,那时候我说我一定要搞好自己的jQuery基础,没想到那么快就实现了,一个月的源码学习时间就结束

Redis源码学习-Lua脚本

Redis源码学习-Lua脚本 1.Sublime Text配置 我是在Win7下,用Sublime Text + Cygwin开发的,配置方法请参考<Sublime Text 3下C/C++开发环境搭建>. 要注意的是:在Cygwin中安装Lua解析器后,SublimeClang插件就能识别出可饮用的Lua头文件了,因为Build System中我们已经配置过"-I", "D:\\cygwin64\\usr\\include",而新安装的Lua头文件会