/** * 显示决策树 * * @param node 待显示的节点 * @param blankNum 行空格符,用于显示树型结构 */ private void showDecisionTree(AttrNode node, int blankNum) { System.out.println(); for (int i = 0; i < blankNum; i++) { System.out.print("\t"); } System.out.print("--"); // 显示分类的属性值 if (node.getParentAttrValue() != null && node.getParentAttrValue().length() > 0) { System.out.print(node.getParentAttrValue()); } else { System.out.print("--"); } System.out.print("--"); if (node.getChildDataIndex() != null && node.getChildDataIndex().size() > 0) { String i = node.getChildDataIndex().get(0); System.out.print("类别:" + data[Integer.parseInt(i)][attrNames.length - 1]); System.out.print("["); for (String index : node.getChildDataIndex()) { System.out.print(index + ", "); } System.out.print("]"); } else { // 递归显示子节点 System.out.print("【" + node.getAttrName() + "】"); for (AttrNode childNode : node.getChildAttrNode()) { showDecisionTree(childNode, 2 * blankNum); } } }
/** 利用源数据构造决策树 */ private void buildDecisionTree( AttrNode node, String parentAttrValue, String[][] remainData, ArrayList<String> remainAttr, boolean isID3) { node.setParentAttrValue(parentAttrValue); String attrName = ""; double gainValue = 0; double tempValue = 0; // 如果只有1个属性则直接返回 if (remainAttr.size() == 1) { System.out.println("attr null"); return; } // 选择剩余属性中信息增益最大的作为下一个分类的属性 for (int i = 0; i < remainAttr.size(); i++) { // 判断是否用ID3算法还是C4.5算法 if (isID3) { // ID3算法采用的是按照信息增益的值来比 tempValue = computeGain(remainData, remainAttr.get(i)); } else { // C4.5算法进行了改进,用的是信息增益率来比,克服了用信息增益选择属性时偏向选择取值多的属性的不足 tempValue = computeGainRatio(remainData, remainAttr.get(i)); } if (tempValue > gainValue) { gainValue = tempValue; attrName = remainAttr.get(i); } } node.setAttrName(attrName); ArrayList<String> valueTypes = attrValue.get(attrName); remainAttr.remove(attrName); AttrNode[] childNode = new AttrNode[valueTypes.size()]; String[][] rData; for (int i = 0; i < valueTypes.size(); i++) { // 移除非此值类型的数据 rData = removeData(remainData, attrName, valueTypes.get(i)); childNode[i] = new AttrNode(); boolean sameClass = true; ArrayList<String> indexArray = Lists.newArrayList(); for (int k = 1; k < rData.length; k++) { indexArray.add(rData[k][0]); // 判断是否为同一类的 if (!rData[k][attrNames.length - 1].equals(rData[1][attrNames.length - 1])) { // 只要有1个不相等,就不是同类型的 sameClass = false; break; } } if (!sameClass) { // 创建新的对象属性,对象的同个引用会出错 ArrayList<String> rAttr = Lists.newArrayList(); for (String str : remainAttr) { rAttr.add(str); } buildDecisionTree(childNode[i], valueTypes.get(i), rData, rAttr, isID3); } else { // 如果是同种类型,则直接为数据节点 childNode[i].setParentAttrValue(valueTypes.get(i)); childNode[i].setChildDataIndex(indexArray); } } node.setChildAttrNode(childNode); }