ID3决策树---Java
1)熵与信息增益:
2)以下是实现代码:
//import java.awt.color.ICC_ColorSpace;
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
//import java.util.Iterator;
import java.util.List;
//import java.util.Locale.Category;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
class decisionTree{ private static Map<String, Map<String, Integer>> featureValuesAndCounts=new HashMap<String, Map<String,Integer>>();
private static ArrayList<String[]> dataSet=new ArrayList<String[]>();
private static ArrayList<String> features=new ArrayList<String>();
private static Set<String> category=new HashSet<String>();
//public static DecisionNode root=new DecisionNode();
//private static ArrayList<ArrayList<String>> featureValue=new ArrayList<ArrayList<String>>();
public static void GetDataSet()
{
File file = new File("C:\\Users\\hfz\\workspace\\decisionTree\\src\\loan.txt");
try{
BufferedReader br = new BufferedReader(new FileReader(file));//
String s = null;
s=br.readLine();//读取第一行的内容,即是各特征的名称
String[] tempFeatures=s.split(",");
for (String string1 : tempFeatures) {
features.add(string1);
}
s=br.readLine(); //开始读取特征值
String[] tt=null;
int flag=s.length();
while(flag!=0){//英文文档读到结尾得到的值是null,而中文文档读到结尾得到的值却是""
tt=s.split(",");
dataSet.add(tt); //将特征值存入
category.add(tt[tt.length-1]);//category为集合类型,用于存储类型值 s=br.readLine();
if (s!=null) {
flag = s.length();
}
else{
flag=0;
} } for (int j = 0; j < features.size(); j++) {//逻辑上模拟列优先的方式读取二维数组形式的数据集,就是首先读取一个特征名称,再遍历数据集
Map<String, Integer> ttt=new HashMap<String, Integer>();//将某特征的各个特征值存入Map中,然后再度第二个特征,再遍历数据集。。。
for (int i = 0; i < dataSet.size(); i++) {
String currentFeatureValue=dataSet.get(i)[j];
if(!(ttt.containsKey(currentFeatureValue)))
ttt.put(currentFeatureValue, 1);
else {
ttt.replace(currentFeatureValue, ttt.get(currentFeatureValue)+1);
} }
featureValuesAndCounts.put(features.get(j), ttt);//嵌套形式的Map,第一层的key是特征名称,value是一个新的Map
// 新Map中key是特征的各个值,value是特征值在数据集中出现的次数。 } br.close();
} catch(Exception e){
e.printStackTrace();
}
}
public static DecisionNode treeGrowth(ArrayList<String[]> dataset,String currentFeatureName,
String currentFeatureValue,ArrayList<String> current_features,
Map<String,Map<String,Integer>> current_featureValuesCounts){
/*
dataset:用于split方法,从dataset数据集中去除掉具有某个特征值的对应的若干实例,生成一个新的新的数据集
currentFeatureName:当前的特征名称,用于叶子节点,赋值给叶子节点的featureName字段
currentFeatureValue:当前特征名称对应的特征值,也用于叶子节点,赋值给featureValue字段
current_features:当前数据集中包含的所有特征名称,用于findBestAttribute方法,找到信息增益最大的的属性
current_featureValuesCounts:当前数据集中所有特征的各个特征值出现的次数,用于findBestAttribute方法,用于计算条件熵,进而计算信息增益。
*/
ArrayList<String> classList=new ArrayList<String>();
int flag=0;
for (String[] string : dataset) {
//测试数据集中类型值的数量,flag表示数据集中的类型数量
if (classList.contains(string[string.length-1])) { }
else {
classList.add(string[string.length-1]);
flag++;//如果flag>1表示数据集
} }
if(1==flag){//如果只有一个类结果,则返回此叶子节点
DecisionNode d=new DecisionNode();
d.init(currentFeatureName,classList.get(0),currentFeatureValue);
return d;
}
if (dataset.get(0).length==1) {//如果数据集已经没有属性了只剩下类结果,则返回占比最大的类结果,也是叶子节点
DecisionNode d=new DecisionNode();
d.init(currentFeatureName,classify(classList),currentFeatureValue);
return d;
} /*
DecisionNode是一个自定义的递归型的数据类型,类中一个children字段是DecisionNode类型的数组,
正好用这种类型来存储递归算法产生的结果(决策树),也就是用这种结构来存储一棵树。
*/
//程序运行到这里就说明此节点不是叶子节点
DecisionNode root2=new DecisionNode();//那么root2就是一个决策属性节点(非叶子节点)了,非叶子节点就有孩子节点,下面就是计算它的孩子节点 int bestFeatureIndex=findBestAttribute(dataset,current_features,current_featureValuesCounts);
String bestFeatureLabel=current_features.get(bestFeatureIndex);
//root.testCondition=bestFeatureLabel;
ArrayList<String> feature_values=new ArrayList<String>();
for (Entry<String, Integer> featureEntry : current_featureValuesCounts.get(bestFeatureLabel).entrySet()) {
feature_values.add(featureEntry.getKey()); }
//给非叶子节点,也就是特征节点仅仅赋特征名称值
root2.init(currentFeatureName,currentFeatureValue);//java中不能是使用像C++中默认参数的函数,只能通过重载来实现同样的目的。
for (String values : feature_values) {
//DecisionNode tempRoot=new DecisionNode(); ArrayList<String[]> subDataSet = splitDataSet(dataset, bestFeatureIndex, values);//生成子数据集,即去除了包含values的实例,
// 接下来就是计算对此数据集利用决策树进行决策,又需要调用treeGrow方法
//所以,接下来需要得到对应这个子数据集的特征名称以及每个特征值在数据集中出现的次数
ArrayList<String> currentAttibutes=new ArrayList<>();
Iterator item1=current_features.iterator();
while(item1.hasNext()){
currentAttibutes.add(item1.next().toString());//这个子数据集的特征名称
} Map<String,Map<String,Integer>> currentAttributeValuesCounts=new HashMap<String, Map<String, Integer>>();
//ArrayList<String[]> subDataSet = splitDataSet(dataset, bestFeatureIndex, values);
currentAttibutes.remove(bestFeatureLabel);
for (int j = 0; j < currentAttibutes.size(); j++) {
Map<String, Integer> ttt=new HashMap<String, Integer>();
for (int i = 0; i <subDataSet.size(); i++) {
String currentFeatureValueXX=subDataSet.get(i)[j];
if(!(ttt.containsKey(currentFeatureValueXX)))
ttt.put(currentFeatureValueXX, 1);
else {
ttt.replace(currentFeatureValueXX, ttt.get(currentFeatureValueXX)+1);
} }
currentAttributeValuesCounts.put(currentAttibutes.get(j), ttt);//每个特征值在数据集中出现的次数 } root2.add(treeGrowth(subDataSet, bestFeatureLabel, values, currentAttibutes, currentAttributeValuesCounts)); } return root2; } public static void main(String[] agrs){
decisionTree.GetDataSet();
DecisionNode dd=decisionTree.treeGrowth(dataSet,"oo","xx",features,featureValuesAndCounts);
System.out.print(dd); } public static double calEntropy(ArrayList<String[]> dataset){//熵表示随机变量X不确定性的度量,在决策树中计算的熵就是决策结果这个变量的熵。
int sampleCounts=dataset.size();
Map<String, Integer> categoryCounts=new HashMap<String, Integer>();
for (String[] strings : dataset) { if(categoryCounts.containsKey(strings[strings.length-1]))
categoryCounts.replace(strings[strings.length-1], categoryCounts.get(strings[strings.length-1])+1);
else {
categoryCounts.put(strings[strings.length-1],1);
} }
double shannonEnt=0.0;
for (Integer value: categoryCounts.values()) {
double probability=value.doubleValue()/sampleCounts;
shannonEnt-=probability*(Math.log10(probability)/Math.log10(2)); }
return shannonEnt;
} public static int findBestAttribute(ArrayList<String[]> dataset,ArrayList<String> currentFeatures,
Map<String,Map<String,Integer>> currentFeatureValuesCounts){
double baseEntroy=calEntropy(dataset);//计算基础熵,就是在不划分出某个特征的情况下。
double bestInfoGain=0.0;
int bestFeatureIndex=-1; for (int i = 0; i <currentFeatures.size(); i++) {//遍历当前数据集的每个特征,计算每个特征的信息增益
double conditionalEntroy=0.0;
Map<String,Integer> tempFeatureCounts=currentFeatureValuesCounts.get(currentFeatures.get(i));
//Map类型有一个entrySet方法,此方法返回一个Map.Entry类型的集合,其中集合中的每个元素就是一个键值对,利用增强型的for循环可以遍历Map中
//key(entry.getkey)和value(entry.getValue)
for (Entry<String, Integer> entry : tempFeatureCounts.entrySet()) {
//计算条件熵,就是根据某个具体特征值划分出新的数据集,计算新的数据集的基础熵,再乘以权值,累加得到某个特征的条件熵。
conditionalEntroy+=(entry.getValue().doubleValue()/dataset.size())*calEntropy(splitDataSet(dataset, i, entry.getKey()));
}
if (baseEntroy-conditionalEntroy>bestInfoGain) {
bestInfoGain=baseEntroy-conditionalEntroy;
bestFeatureIndex=i; }
}
if (-1==bestFeatureIndex){
System.out.print("cannot find best attribute!");
return -1;
}
else {
return bestFeatureIndex;//返回信息增益最大的特征的索引,在当前特征(currentFeatures)中的索引。
}
}
public static String classify(ArrayList<String> dataset) { Map<String, Integer> categoryCount = new HashMap<String, Integer>();
for (String s1 : dataset) {
if (categoryCount.containsKey(s1)) {
categoryCount.replace(s1, categoryCount.get(s1) + 1);
} else {
categoryCount.put(s1, 1);
}
}
int maxCounts=-1;
String maxCountsCategory=null;
for (Entry<String,Integer> entry:categoryCount.entrySet()){//利用Map.Entry得到Map中的Value最大的键值对。
if (entry.getValue()>maxCounts){
maxCounts=entry.getValue();
maxCountsCategory=entry.getKey();
}
}
return maxCountsCategory; } public static ArrayList<String[]> splitDataSet(ArrayList<String[]> dataset,int featureIndex,String featureValue
){
ArrayList<String[]> tempDataSet=new ArrayList<String[]>();
for (String[] strings : dataset) {
if (strings[featureIndex].equals(featureValue)) { String[] xx=strings.clone();//数组的clone方法实现的是浅拷贝,实质就是以下的过程
/*
for (int i = featureIndex; i < strings.length-1; i++) {
xx[i]=strings[i];//就是把引用的值(地址)复制了一份,指向了同一个对象。
} */
for (int i = featureIndex; i < strings.length-1; i++) {//xx中各个元素的值与strings中各个元素的值完全相等。
xx[i]=xx[i+1];//只是复制了引用的值而已,跟引用指向的对象没一点关系。Java将基本类型和引用类型变量都看成是值而已·
}
//最最最需要注意的一点,以上代码不能以下面这种形式实现
/*
for (int i = featureIndex; i < strings.length-1; i++) {//
strings[i]=strings[i+1];//这样会改变strings指向的对象,进而影响到dataset,改变了函数的参数dataset,
这样就在函数内“无意间”修改了dataset的值,集合类型,其实所有引用类型都是,以参数形式传入函数的话,可能会“无意间”就被修改了
}
*/
String[] tempStrings=new String[xx.length-1];
for (int i = 0; i < tempStrings.length; i++) {
tempStrings[i]=xx[i]; }
tempDataSet.add(tempStrings);
} }
return tempDataSet;
} }
class DecisionNode{
public String featureName;
public String result;
public String featureValue;
public List<DecisionNode> children=new ArrayList<DecisionNode>();
public void add(DecisionNode node){
children.add(node);
}
public void init(String featureName,String result,String featureValue){
this.featureName=featureName;
this.result=result;
this.featureValue=featureValue;
}
public void init(String featureName,String featureValue){
this.featureName=featureName;
this.featureValue=featureValue;
}
}
参考:
http://www.blogjava.net/zhenandaci/archive/2009/03/24/261701.html
http://my.oschina.net/xinyi/blog/116014
http://www.cnblogs.com/zhangchaoyang/articles/2196631.html
http://blog.csdn.net/u011067360/article/details/21861989?utm_source=tuicool
ID3决策树---Java的更多相关文章
- ID3决策树预测的java实现
刚才写了ID3决策树的建立,这个是通过决策树来进行预测.这里主要用到的就是XML的遍历解析,比较简单. 关于xml的解析,参考了: http://blog.csdn.net/soszou/articl ...
- ID3算法Java实现
ID3算法java实现 1 ID3算法概述 1.1 信息熵 熵是无序性(或不确定性)的度量指标.假如事件A的全概率划分是(A1,A2,...,An),每部分发生的概率是(p1,p2,...,pn).那 ...
- Python3实现机器学习经典算法(三)ID3决策树
一.ID3决策树概述 ID3决策树是另一种非常重要的用来处理分类问题的结构,它形似一个嵌套N层的IF…ELSE结构,但是它的判断标准不再是一个关系表达式,而是对应的模块的信息增益.它通过信息增益的大小 ...
- ID3决策树的Java实现
package DecisionTree; import java.io.*; import java.util.*; public class ID3 { //节点类 public class DT ...
- 归纳决策树ID3(Java实现)
先上问题吧,我们统计了14天的气象数据(指标包括outlook,temperature,humidity,windy),并已知这些天气是否打球(play).如果给出新一天的气象指标数据:sunny,c ...
- java编写ID3决策树
说明:每个样本都会装入Data样本对象,决策树生成算法接收的是一个Array<Data>样本列表,所以构建测试数据时也要符合格式,最后生成的决策树是树的根节点,通过里面提供的showTre ...
- C4.5决策树--Java
ID3是以信息增益作为划分训练数据集的特征,即认为信息增益大的特征是对分类结果影响更大,但是信息增益的方法偏向于选择取值较多的特征,因此引入了C4.5决策树,也就是使用信息增益率(比)来作为划分数据集 ...
- python ID3决策树实现
环境:ubuntu 16.04 python 3.6 数据来源:UCI wine_data(比较经典的酒数据) 决策树要点: 1. 如何确定分裂点(CART ID3 C4.5算法有着对应的分裂计算方式 ...
- ID3决策树
决策树 优点:计算复杂度不高,输出结果易于理解,对中间值的缺少不敏感,可以处理不相关特征数据 缺点:过拟合 决策树的构造 熵:混乱程度,信息的期望值 其中p(xi)是选择分类的概率 熵就是计算所有类别 ...
随机推荐
- 问题记录:android.os.NetworkOnMainThreadException异常
在MainActivity的主线程中访问网络将会发生异常 查阅资料后发现 Android4.0 以后不允许在主线程进行网络连接
- wpf程序热键的一个类
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServi ...
- 浅谈Objective-C编译器指令
------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS ...
- 菜鸟学习Spring——60s配置XML方法实现简单AOP
一.概述. 上一篇博客讲述了用注解的形式实现AOP现在讲述另外一种AOP实现的方式利用XML来实现AOP. 二.代码演示. 准备工作参照上一篇博客<菜鸟学习Spring--60s使用annota ...
- eth0: error fetching interface information: Device not found
转载,原文出处:http://zh888.blog.51cto.com/1684752/775447 亲测有效,感谢作者!!! ----------------------------分割线----- ...
- ios中怎么获得当前版本号
NSString *version = [NSBundle mainBundle].infoDictionary[(__bridge NSString *)kCFBundleVersionKey];
- C++ json库jsoncpp 吐槽
Explain 最近在做游戏接入SDK时用到C++的json库jsoncpp,jsoncpp 是一款优秀的json库,但恶心的一点是它采用Assert作为错误处理方法,而assert在linux下通过 ...
- CPU制造工艺 级选来决定cpu等级
CPU制造工艺 编辑 CPU制造工艺又叫做CPU制程,它的先进与否决定了CPU的性能优劣.CPU的制造是一项极为复杂的过程,当今世上只有少数几家厂商具备研发和生产CPU的能力.CPU的发展史也可以看作 ...
- python 实现求和、计数、最大最小值、平均值、中位数、标准偏差、百分比。
import sys class Stats: def __init__(self, sequence): # sequence of numbers we will process # conver ...
- SQL Server数据库学习笔记-E-R模型
实体(Entities)联系(Relationships)模型简称E-R模型也称E-R方法,是由P.P.Chen于1976年首先提出的.还有一个关键元素Attributes-属性,它提供不受任何数据库 ...