c4.5算法 java_Weka J48决策树算法(C4.5)源码学习 | 学步园

本文通过阅读Weka的源代码,详细介绍了如何使用Java实现C4.5决策树算法,即J48。首先,介绍了决策树学习算法的基础知识,如熵、信息增益和信息增益率。接着,逐步解析了J48的代码流程,从J48.buildClassifier开始,涉及C45ModelSelection、C45Split等关键类的方法。最后,讨论了C4.5决策树的剪枝过程及其错误率计算。

代码下载:

Use WEKA in your Java Code:

1901041.html

1901041.html

J48 C4.5决策树

TODO: J48 的分类效率分析。

题记: 之前虽然对 J48 用得比较多,是由于它能方便的区别特征的好坏。 工作了,希望自己能更深入, 如是开始了这个算法学习系列。 希望和大家共同进步。

个人对看算法源代码也没有很好的流程,计划先采用 按类Class 做架构介绍;再深入代码具体逻辑的方式展开。 欢迎大家提出好的算法源码阅读流程。

另外,求推荐LR 的比较好的实现代码 ~(^o^)~

一、 准备工作。

下载 weka  的工具包,将 weka.jar 和 weka-src.jar 导入eclipse 项目的依赖包,即可查看 到源码。

也可以将weka-src.jar 解压,在对应的文件夹下建立一个单独的eclipse 项目,这样可以自己修改代码。

相关论文参考: Ross Quinlan (1993). C4.5: Programs for Machine Learning. Morgan Kaufmann Publishers, San Mateo, CA.

因为还是对 E文 不友好,个人看了 统计学习方法 的对应章节就算是把理论先过完啦。

熵用来计算随机量的分布不确定性,或者其表达能力。计算公式:

1355055345_7361.jpg

信息增益 Information Gain 又称为 互信息 Multi Information, 体现了新的属性的出现对类别不确定的弱化的能力。计算公式:

1355055603_8655.jpg

信息增益率在分类问题中体现为:特征A对类别C的 信息增益与特征A的熵之比。能在一定程度上修正某个属性ai由于分布很广而Gain更大的影响;但是也可能导致过分修正而选择那些属性分布很窄的项。可以采用两步判别法:信息增益超过平均值的属性,其次再比较信息增益率。

C4.5 决策树的学习算法:

1355059857_7196.jpg

二、代码流解析:

模型的学习程序从 J48.java 开始。

J48.buildClassifier(ins):  选取 C45 决策树模型为例:

modSelection =newC45ModelSelection(m_minNumObj, instances);

m_root = newC45PruneableClassifierTree(modSelection, !m_unpruned, m_CF,

m_subtreeRaising, !m_noCleanup);

m_root.buildClassifier(instances);

将C45Pruneable*.buildClassifier(ins) 继续展开:

data.deleteWithMissingClass();

buildTree(data, m_subtreeRaising || !m_cleanup);

collapse();

if(m_pruneTheTree) {

prune();

}

if(m_cleanup) {

cleanup(newInstances(data,0));

}

对基类ClassifierTree.buildTree()继续展开:

调用 modSelection.selectModel(ins);

modSelection.split(ins).  // 分割数据

m_sons[i] = getNewTree(localInstances[i]);  // 构建子树

将 C45ModelSelection.selectModel(ins) 继续展开:

if(Utils.sm(checkDistribution.total(),2* m_minNoObj)

|| Utils.eq(checkDistribution.total(), checkDistribution.perClass(checkDistribution.maxClass())))

returnnoSplitModel;

multiValue = !(attribute.isNumeric() || attribute.numValues() 

currentModel = newC45Split[data.numAttributes()];

sumOfWeights = data.sumOfWeights();

// For each attribute.

for(i =0; i 

// Apart from class attribute.

if(i != (data).classIndex()) {

// Get models for current attribute.

currentModel[i] = newC45Split(i, m_minNoObj, sumOfWeights);

currentModel[i].buildClassifier(data);

// ... 省略代码部分: 更新 averageInfoGain的总和

} else

currentModel[i] = null;

}

averageInfoGain = averageInfoGain / (double) validModels;

// Find "best" attribute to split on.

minResult = 0;

for(i =0; i 

// Use 1E-3 here to get a closer approximation to the original implementation.

if((currentModel[i].infoGain() >= (averageInfoGain - 1E-3))

&& Utils.gr(currentModel[i].gainRatio(), minResult)) {

bestModel = currentModel[i];

minResult = currentModel[i].gainRatio();

}

}

// ... 省略代码: 将全局数据加载到bestModel. Set the split point analogue to C45 if attribute numeric.

if(m_allData !=null)

bestModel.setSplitPoint(m_allData);

returnbestModel;

将C45Split.buildClassifier() 方法继续展开:

按属性为 Enum or Numeric 类型,分别调用handleEnumerateAttribute(ins) or handleNumericAttribute(ins). 这两个方法的具体实现参考下文的讲解。

collapse() 方法: 对比合并树 前后的错误率,不增加则合并。并递归处理孩子节点。

prune() 方法:对C4.5决策树进行减枝。递归地先从孩子节点开始。 当前节点处理的关键代码:

// Compute error if this Tree would be leaf

errorsLeaf = getEstimatedErrorsForDistribution(localModel()

.distribution());

// Compute error for the whole subtree

errorsTree = getEstimatedErrors();

// Decide if leaf is best choice.

if(Utils.smOrEq(errorsLeaf, errorsTree +0.1)

&& Utils.smOrEq(errorsLeaf, errorsLargestBranch + 0.1)) {

// ... 将树设为叶子

}

// Decide if largest branch is better choice than whole subtree.

if(Utils.smOrEq(errorsLargestBranch, errorsTree +0.1)) {

largestBranch = son(indexOfLargestBranch);

m_sons = largestBranch.m_sons;

m_localModel = largestBranch.localModel();

m_isLeaf = largestBranch.m_isLeaf;

newDistribution(m_train);

prune();

}

J48.classifyInstance(data): 使用模型对 测试数据分类。

m_root.classifyInstance(data);

实际调用 ClassifyTree.classifyInstance(ins):

调用getProbs(int classIndex, data, 1)计算测试ins在各个类别下的概率,去最大类别的idx返回。

if(m_isLeaf) {

returnweight * localModel().classProb(classIndex, instance, -1);

} else{

inttreeIndex = localModel().whichSubset(instance);

if(treeIndex == -1) {// contained by multi-classLabel.

double[] weights = localModel().weights(instance);

for(inti =0; i 

if(!son(i).m_isEmpty) {

prob += son(i).getProbs(classIndex, instance,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值