Java实现的决策树算法完整实例

本文实例讲述了Java实现的决策树算法。分享给大家供大家参考,具体如下:

决策树算法是一种逼近离散函数值的方法。它是一种典型的分类方法,首先对数据进行处理,利用归纳算法生成可读的规则和决策树,然后使用决策对新数据进行分析。本质上决策树是通过一系列规则对数据进行分类的过程。

决策树构造可以分两步进行。第一步,决策树的生成:由训练样本集生成决策树的过程。一般情况下,训练样本数据集是根据实际需要有历史的、有一定综合程度的,用于数据分析处理的数据集。第二步,决策树的剪枝:决策树的剪枝是对上一阶段生成的决策树进行检验、校正和修下的过程,主要是用新的样本数据集(称为测试数据集)中的数据校验决策树生成过程中产生的初步规则,将那些影响预衡准确性的分枝剪除。

java实现代码如下:

package demo;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class DicisionTree {
  public static void main(String[] args) throws Exception {
    System.out.print("我们测试结果:");
    String[] attrNames = new String[] { "AGE", "INCOME", "STUDENT",
        "CREDIT_RATING" };
    // 读取样本集
    Map<Object, List<Sample>> samples = readSamples(attrNames);
    // 生成决策树
    Object decisionTree = generateDecisionTree(samples, attrNames);
    // 输出决策树
    outputDecisionTree(decisionTree, 0, null);
  }
  /**
   * 读取已分类的样本集,返回Map:分类 -> 属于该分类的样本的列表
   */
  static Map<Object, List<Sample>> readSamples(String[] attrNames) {
    // 样本属性及其所属分类(数组中的最后一个元素为样本所属分类)
    Object[][] rawData = new Object[][] {
        { "<30 ", "High ", "No ", "Fair   ", "0" },
        { "<30 ", "High ", "No ", "Excellent", "0" },
        { "30-40", "High ", "No ", "Fair   ", "1" },
        { ">40 ", "Medium", "No ", "Fair   ", "1" },
        { ">40 ", "Low  ", "Yes", "Fair   ", "1" },
        { ">40 ", "Low  ", "Yes", "Excellent", "0" },
        { "30-40", "Low  ", "Yes", "Excellent", "1" },
        { "<30 ", "Medium", "No ", "Fair   ", "0" },
        { "<30 ", "Low  ", "Yes", "Fair   ", "1" },
        { ">40 ", "Medium", "Yes", "Fair   ", "1" },
        { "<30 ", "Medium", "Yes", "Excellent", "1" },
        { "30-40", "Medium", "No ", "Excellent", "1" },
        { "30-40", "High ", "Yes", "Fair   ", "1" },
        { ">40 ", "Medium", "No ", "Excellent", "0" } };
    // 读取样本属性及其所属分类,构造表示样本的Sample对象,并按分类划分样本集
    Map<Object, List<Sample>> ret = new HashMap<Object, List<Sample>>();
    for (Object[] row : rawData) {
      Sample sample = new Sample();
      int i = 0;
      for (int n = row.length - 1; i < n; i++)
        sample.setAttribute(attrNames[i], row[i]);
      sample.setCategory(row[i]);
      List<Sample> samples = ret.get(row[i]);
      if (samples == null) {
        samples = new LinkedList<Sample>();
        ret.put(row[i], samples);
      }
      samples.add(sample);
    }
    return ret;
  }
  /**
   * 构造决策树
   */
  static Object generateDecisionTree(
      Map<Object, List<Sample>> categoryToSamples, String[] attrNames) {
    // 如果只有一个样本,将该样本所属分类作为新样本的分类
    if (categoryToSamples.size() == 1)
      return categoryToSamples.keySet().iterator().next();
    // 如果没有供决策的属性,则将样本集中具有最多样本的分类作为新样本的分类,即投票选举出分类
    if (attrNames.length == 0) {
      int max = 0;
      Object maxCategory = null;
      for (Entry<Object, List<Sample>> entry : categoryToSamples
          .entrySet()) {
        int cur = entry.getValue().size();
        if (cur > max) {
          max = cur;
          maxCategory = entry.getKey();
        }
      }
      return maxCategory;
    }
    // 选取测试属性
    Object[] rst = chooseBestTestAttribute(categoryToSamples, attrNames);
    // 决策树根结点,分支属性为选取的测试属性
    Tree tree = new Tree(attrNames[(Integer) rst[0]]);
    // 已用过的测试属性不应再次被选为测试属性
    String[] subA = new String[attrNames.length - 1];
    for (int i = 0, j = 0; i < attrNames.length; i++)
      if (i != (Integer) rst[0])
        subA[j++] = attrNames[i];
    // 根据分支属性生成分支
    @SuppressWarnings("unchecked")
    Map<Object, Map<Object, List<Sample>>> splits =
    /* NEW LINE */(Map<Object, Map<Object, List<Sample>>>) rst[2];
    for (Entry<Object, Map<Object, List<Sample>>> entry : splits.entrySet()) {
      Object attrValue = entry.getKey();
      Map<Object, List<Sample>> split = entry.getValue();
      Object child = generateDecisionTree(split, subA);
      tree.setChild(attrValue, child);
    }
    return tree;
  }
  /**
   * 选取最优测试属性。最优是指如果根据选取的测试属性分支,则从各分支确定新样本
   * 的分类需要的信息量之和最小,这等价于确定新样本的测试属性获得的信息增益最大
   * 返回数组:选取的属性下标、信息量之和、Map(属性值->(分类->样本列表))
   */
  static Object[] chooseBestTestAttribute(
      Map<Object, List<Sample>> categoryToSamples, String[] attrNames) {
    int minIndex = -1; // 最优属性下标
    double minValue = Double.MAX_VALUE; // 最小信息量
    Map<Object, Map<Object, List<Sample>>> minSplits = null; // 最优分支方案
    // 对每一个属性,计算将其作为测试属性的情况下在各分支确定新样本的分类需要的信息量之和,选取最小为最优
    for (int attrIndex = 0; attrIndex < attrNames.length; attrIndex++) {
      int allCount = 0; // 统计样本总数的计数器
      // 按当前属性构建Map:属性值->(分类->样本列表)
      Map<Object, Map<Object, List<Sample>>> curSplits =
      /* NEW LINE */new HashMap<Object, Map<Object, List<Sample>>>();
      for (Entry<Object, List<Sample>> entry : categoryToSamples
          .entrySet()) {
        Object category = entry.getKey();
        List<Sample> samples = entry.getValue();
        for (Sample sample : samples) {
          Object attrValue = sample
              .getAttribute(attrNames[attrIndex]);
          Map<Object, List<Sample>> split = curSplits.get(attrValue);
          if (split == null) {
            split = new HashMap<Object, List<Sample>>();
            curSplits.put(attrValue, split);
          }
          List<Sample> splitSamples = split.get(category);
          if (splitSamples == null) {
            splitSamples = new LinkedList<Sample>();
            split.put(category, splitSamples);
          }
          splitSamples.add(sample);
        }
        allCount += samples.size();
      }
      // 计算将当前属性作为测试属性的情况下在各分支确定新样本的分类需要的信息量之和
      double curValue = 0.0; // 计数器:累加各分支
      for (Map<Object, List<Sample>> splits : curSplits.values()) {
        double perSplitCount = 0;
        for (List<Sample> list : splits.values())
          perSplitCount += list.size(); // 累计当前分支样本数
        double perSplitValue = 0.0; // 计数器:当前分支
        for (List<Sample> list : splits.values()) {
          double p = list.size() / perSplitCount;
          perSplitValue -= p * (Math.log(p) / Math.log(2));
        }
        curValue += (perSplitCount / allCount) * perSplitValue;
      }
      // 选取最小为最优
      if (minValue > curValue) {
        minIndex = attrIndex;
        minValue = curValue;
        minSplits = curSplits;
      }
    }
    return new Object[] { minIndex, minValue, minSplits };
  }
  /**
   * 将决策树输出到标准输出
   */
  static void outputDecisionTree(Object obj, int level, Object from) {
    for (int i = 0; i < level; i++)
      System.out.print("|-----");
    if (from != null)
      System.out.printf("(%s):", from);
    if (obj instanceof Tree) {
      Tree tree = (Tree) obj;
      String attrName = tree.getAttribute();
      System.out.printf("[%s = ?]\n", attrName);
      for (Object attrValue : tree.getAttributeValues()) {
        Object child = tree.getChild(attrValue);
        outputDecisionTree(child, level + 1, attrName + " = "
            + attrValue);
      }
    } else {
      System.out.printf("[CATEGORY = %s]\n", obj);
    }
  }
  /**
   * 样本,包含多个属性和一个指明样本所属分类的分类值
   */
  static class Sample {
    private Map<String, Object> attributes = new HashMap<String, Object>();
    private Object category;
    public Object getAttribute(String name) {
      return attributes.get(name);
    }
    public void setAttribute(String name, Object value) {
      attributes.put(name, value);
    }
    public Object getCategory() {
      return category;
    }
    public void setCategory(Object category) {
      this.category = category;
    }
    public String toString() {
      return attributes.toString();
    }
  }
  /**
   * 决策树(非叶结点),决策树中的每个非叶结点都引导了一棵决策树
   * 每个非叶结点包含一个分支属性和多个分支,分支属性的每个值对应一个分支,该分支引导了一棵子决策树
   */
  static class Tree {
    private String attribute;
    private Map<Object, Object> children = new HashMap<Object, Object>();
    public Tree(String attribute) {
      this.attribute = attribute;
    }
    public String getAttribute() {
      return attribute;
    }
    public Object getChild(Object attrValue) {
      return children.get(attrValue);
    }
    public void setChild(Object attrValue, Object child) {
      children.put(attrValue, child);
    }
    public Set<Object> getAttributeValues() {
      return children.keySet();
    }
  }
}

运行结果:

更多关于java算法相关内容感兴趣的读者可查看本站专题:《Java数据结构与算法教程》、《Java操作DOM节点技巧总结》、《Java文件与目录操作技巧汇总》和《Java缓存操作技巧汇总》

希望本文所述对大家java程序设计有所帮助。

(0)

相关推荐

  • java字符串相似度算法

    本文实例讲述了java字符串相似度算法.分享给大家供大家参考.具体实现方法如下: 复制代码 代码如下: public class Levenshtein {     private int compare(String str, String target) {         int d[][]; // 矩阵         int n = str.length();         int m = target.length();         int i; // 遍历str的      

  • 关于各种排列组合java算法实现方法

    一.利用二进制状态法求排列组合,此种方法比较容易懂,但是运行效率不高,小数据排列组合可以使用 复制代码 代码如下: import java.util.Arrays; //利用二进制算法进行全排列//count1:170187//count2:291656 public class test {    public static void main(String[] args) {        long start=System.currentTimeMillis();        count

  • java实现的n*n矩阵求值及求逆矩阵算法示例

    本文实例讲述了java实现的n*n矩阵求值及求逆矩阵算法.分享给大家供大家参考,具体如下: 先来看看运行结果: java版的写出来了,用的跟c语言相同的算法,然后看看能不能以后加个框做成程序: import java.math.*; import java.util.*; import java.text.*; public class matrix { static int map1[][]=new int [110][110]; static int just[][]=new int [11

  • Java矩阵连乘问题(动态规划)算法实例分析

    本文实例讲述了Java矩阵连乘问题(动态规划)算法.分享给大家供大家参考,具体如下: 问题描述:给定n个矩阵:A1,A2,...,An,其中Ai与Ai+1是可乘的,i=1,2...,n-1.确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少.输入数据为矩阵个数和每个矩阵规模,输出结果为计算矩阵连乘积的计算次序和最少数乘次数. 问题解析:由于矩阵乘法满足结合律,故计算矩阵的连乘积可以有许多不同的计算次序.这种计算次序可以用加括号的方式来确定.若一个矩阵连乘积的计算次序完全确

  • Java基于栈方式解决汉诺塔问题实例【递归与非递归算法】

    本文实例讲述了Java基于栈方式解决汉诺塔问题.分享给大家供大家参考,具体如下: /** * 栈方式非递归汉诺塔 * @author zy * */ public class StackHanoi { /** * @param args */ public static void main(String[] args) { System.out.println("我们测试结果:"); System.out.println("递归方式:"); hanoiNormal(

  • java 二维数组矩阵乘法的实现方法

    复制代码 代码如下: public interface IMatrixMultiple {     public int[][] mmltiple(int[][]a ,int [][]b); } ?public class MatrixMultiple implements IMatrixMultiple { @Override    public int[][] mmltiple(int[][] a, int[][] b) {         int [][] result = new int

  • java实现任意矩阵Strassen算法

    本例输入为两个任意尺寸的矩阵m * n, n * m,输出为两个矩阵的乘积.计算任意尺寸矩阵相乘时,使用了Strassen算法.程序为自编,经过测试,请放心使用.基本算法是: 1.对于方阵(正方形矩阵),找到最大的l, 使得l = 2 ^ k, k为整数并且l < m.边长为l的方形矩阵则采用Strassen算法,其余部分以及方形矩阵中遗漏的部分用蛮力法. 2.对于非方阵,依照行列相应添加0使其成为方阵. StrassenMethodTest.java package matrixalgorit

  • Java实现的求逆矩阵算法示例

    本文实例讲述了Java实现的求逆矩阵算法.分享给大家供大家参考,具体如下: package demo; public class MatrixInverse { public static double Det(double [][]Matrix,int N)//计算n阶行列式(N=n-1) { int T0; int T1; int T2; double Num; int Cha; double [][] B; if(N>0) { Cha=0; B=new double[N][N]; Num=

  • java实现的AES加密算法完整实例

    本文实例讲述了java实现的AES加密算法.分享给大家供大家参考,具体如下: import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import android.util.Base64; /** * @author vipin.cb , vipin.cb@experionglobal.com <br> * Sep 27, 2013

  • java 矩阵乘法的mapreduce程序实现

    java 矩阵乘法的mapreduce程序实现 map函数:对于矩阵M中的每个元素m(ij),产生一系列的key-value对<(i,k),(M,j,m(ij))> 其中k=1,2.....知道矩阵N的总列数;对于矩阵N中的每个元素n(jk),产生一系列的key-value对<(i , k) , (N , j ,n(jk)>, 其中i=1,2.......直到i=1,2.......直到矩阵M的总列数. map package com.cb.matrix; import stati

  • Java分治法与二分搜索算法实例分析

    本文实例讲述了Java分治法与二分搜索算法.分享给大家供大家参考,具体如下: 1.分治法 分治法的基本思想是将一个规模为n的问题分解为k个规模较小的子问题,这些子问题相互独立且与原问题相同.递归的解这些子问题,然后将各子问题的解合并得到原问题的解. 分治法所能解决的问题一般具有以下几个特征: 1) 该问题的规模缩小到一定的程度就可以容易地解决 2) 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质. 3) 利用该问题分解出的子问题的解可以合并为该问题的解: 4) 该问题所分解

随机推荐