一、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算法进行分析。