⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 decisiontreerulesview.java

📁 一个数据挖掘软件ALPHAMINERR的整个过程的JAVA版源代码
💻 JAVA
字号:
/*
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 2 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program; if not, write to the Free Software
 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
/*
 * Created on 2005-1-14
 *
 * $Author$
 * $Date$
 * $Revision$
 *
 */
package eti.bi.alphaminer.patch.standard.operation.result.view;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.io.File;
import java.util.ArrayList;
import javax.swing.BorderFactory;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;
import weka.classifiers.trees.J48;
import weka.classifiers.trees.j48.ClassifierSplitModel;
import weka.classifiers.trees.j48.ClassifierTree;
import weka.classifiers.trees.j48.Distribution;
import weka.core.Utils;
import com.prudsys.pdm.Core.CategoricalAttribute;
import com.prudsys.pdm.Core.MiningAttribute;
import eti.bi.alphaminer.operation.result.ResultView;
import eti.bi.alphaminer.operation.result.datamodel.SortingDataGridModel;
import eti.bi.alphaminer.operation.result.export.ExcelExporter;
import eti.bi.common.Locale.Resource;
import eti.bi.exception.AppException;
import eti.bi.exception.SysException;
import eti.bi.util.NumberFormatter;

/**
 * 
 * Take J48 classifier and the target MiningAttribute as inputs. Build all the
 * rules recursively from the classifier. Calculate the supporting records
 * (number of recors in the bag) and confidence rate (number of correct reocrds
 * in the class / supporting records. Output a JPanel (JTable) showing these
 * infor.
 * 
 * Note: Need first call J48.toString() to build the tree node label before
 * executing this class. Also there are many aspects can be improved. See
 * comments below.
 * 
 * @author TWang On Jan 26, 2005.
 * 
 */
public class DecisionTreeRulesView extends ResultView {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	// JTable that shows the data
	private JTable m_DataTable;
	private String[] m_DataTableHeader = { Resource.srcStr("DECISIONTREE_RULE_NO"),
			Resource.srcStr("DECISIONTREE_RULE"), Resource.srcStr("DECISIONTREE_CLASS"),
			Resource.srcStr("DECISIONTREE_CONFIDENCE"), Resource.srcStr("DECISIONTREE_SUPPORT") };
	private Object[][] m_DataTableContent;
	private Class[] m_DataTableType;
	// JScrollPane that contains JTable
	private JScrollPane m_ScrollPane;
	private J48 m_J48Classifier;
	// The target attribute's classes.
	private ArrayList m_ClassValues;
	private int m_RowNum;
	private int m_ColoumNum;
	private ArrayList<String> m_RuleLists;
	private ArrayList<Double> m_ConfLists;
	private ArrayList<Double> m_SuppLists;
	private ArrayList m_ClassNameLists;
	public final String SMALLER_THAN = "<";
	public final String SMALLER_THAN_EQUAL_TO = "<=";
	public final String LARGER_THAN = ">";
	public final String LARGER_THAN_EQUAL_TO = ">=";
	public final String CONNECTOR = " AND ";
	public final String CONNECTOR_COLOR = "<font color=CC0033> AND </font>";

	public DecisionTreeRulesView(J48 a_classifier, MiningAttribute a_TargetMiningAttribute) throws SysException {
		super(Resource.srcStr("DECISIONTREE_VIEW_RULE"));
		m_ViewType = ResultView.TYPE_TABLE;
		if (a_classifier == null) {
			throw new SysException("The J48 Classifier in the DecisionOperator is NULL.");
		}
		m_J48Classifier = a_classifier;
		if (!(a_TargetMiningAttribute instanceof CategoricalAttribute)) {
			throw new SysException("The target attribute is not categorical.");
		}
		m_ClassValues = ((CategoricalAttribute) a_TargetMiningAttribute).getValues();
		m_ScrollPane = new JScrollPane();
		m_RuleLists = new ArrayList<String>();
		m_ConfLists = new ArrayList<Double>();
		m_SuppLists = new ArrayList<Double>();
		m_ClassNameLists = new ArrayList();
		this.setLayout(new BorderLayout());
		this.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
		this.add(m_ScrollPane, BorderLayout.CENTER);
		createDataTable();
		m_ScrollPane.setPreferredSize(new Dimension(200, 70));
		m_ScrollPane.getViewport().add(m_DataTable);
		m_ScrollPane.getViewport().setBackground(Color.WHITE);
	}

	public void createDataTable() {
		// Generate the rule recursively
		ClassifierTree classifierTree = m_J48Classifier.getRoot();
		StringBuffer ruleContent = new StringBuffer();
		generateRules(classifierTree, ruleContent);
		preprocessRules(m_RuleLists);
		m_RowNum = m_RuleLists.size();
		m_ColoumNum = m_DataTableHeader.length;
		// Create JTable class type according to the table header
		m_DataTableType = new Class[m_ColoumNum];
		m_DataTableType[0] = Integer.class;
		m_DataTableType[1] = String.class;
		m_DataTableType[2] = String.class;
		m_DataTableType[3] = Double.class;
		m_DataTableType[4] = Double.class;
		// Create JTable content
		m_DataTableContent = new Object[m_RowNum][m_ColoumNum];
		for (int i = 0; i < m_RowNum; i++) {
			// The first element is Index
			m_DataTableContent[i][0] = new Integer(i + 1);
			m_DataTableContent[i][1] = m_RuleLists.get(i);
			// m_DataTableContent[i][1] = new
			// JLabel("<html>"+createOneRule(i)+"</html>");
			m_DataTableContent[i][2] = m_ClassNameLists.get(i);
			m_DataTableContent[i][3] = m_ConfLists.get(i);
			m_DataTableContent[i][4] = m_SuppLists.get(i);
		}
		// Create Table
		m_DataTable = new JTable();
		// m_DataTable.setModel(new DataGridModel(m_DataTableContent,
		// m_DataTableHeader, m_DataTableType));
		SortingDataGridModel model = new SortingDataGridModel(m_DataTableContent, m_DataTableHeader, m_DataTableType);
		m_DataTable.setModel(model);
		// JLabelRenderer labelRender = new JLabelRenderer();
		// m_DataTable.setDefaultRenderer(JLabel.class, labelRender);
		// Commet it if no label rendering twang.
		// m_DataTable.getColumn("Rule").setCellRenderer(new JLabelRenderer());
		model.addMouseListenerToHeader(m_DataTable);
		setColumnWidth();
	}

	/**
	 * Preprocess items before outputing to table. Only reduce redundent items
	 * in one direction (e.g., <, <= OR >, >=). TWang. On June 1, 2005.
	 * 
	 * @param a_RulesList
	 */
	private void preprocessRules(ArrayList<String> a_RulesList) {
		ArrayList done = new ArrayList();
		for (int i = 0; i < a_RulesList.size(); i++) {
			processRule(i, a_RulesList, this.SMALLER_THAN, done);
			processRule(i, a_RulesList, this.LARGER_THAN, done);
		}
	}

	/**
	 * Process the i-th rule. The rule must in the format of "ABC < xx AND DEF <
	 * yy ...".
	 * 
	 * @param a_index
	 * @param a_RulesList
	 * @param a_Comparator
	 */
	@SuppressWarnings("unchecked")
	private void processRule(int a_index, ArrayList<String> a_RulesList, String a_Comparator, ArrayList a_Done) {
		String rule = a_RulesList.get(a_index);
		String prefix = null;
		String postfix = null;
		String postfix_new = null;
		String comparator = a_Comparator;
		ArrayList done = a_Done;
		StringBuffer newRule = new StringBuffer("");
		int itemIndex;
		String[] items = rule.split(this.CONNECTOR);
		done.clear();
		itemIndex = -1;
		/**
		 * process the j-th item. Find all compatible items. Convert to one
		 * item. Make sure all non-compatible items are in place. Compatible
		 * items are: same prefix with < or <= ; OR same prefix with > or >=
		 */
		for (int j = 0; j < items.length; j++) {
			itemIndex = j;
			int comparatorIndex = items[j].indexOf(comparator);
			int comparatorLength = comparator.length();
			if (comparatorIndex != -1) {
				prefix = items[j].substring(0, comparatorIndex);
				if (done.contains(prefix + "" + comparator)) {
					continue;
				} else {
					done.add(prefix + "" + comparator);
					if (items[j].indexOf(this.SMALLER_THAN_EQUAL_TO) != -1) {
						comparatorLength = this.SMALLER_THAN_EQUAL_TO.length();
					}
					postfix = items[j].substring(comparatorIndex + comparatorLength + 1);
					for (int z = j + 1; z < items.length; z++) {
						if (items[z].indexOf(prefix) != -1) {
							int innerIndex = items[z].indexOf(comparator);
							if (innerIndex != -1) {
								if (items[z].indexOf(this.SMALLER_THAN_EQUAL_TO) != -1) {
									comparatorLength = this.SMALLER_THAN_EQUAL_TO.length();
								}
								postfix_new = items[z].substring(comparatorIndex + comparatorLength + 1);
								if (comparator.equals(this.SMALLER_THAN)
										&& Float.parseFloat(postfix_new) < Float.parseFloat(postfix)) {
									itemIndex = z;
								} else if (comparator.equals(this.LARGER_THAN)
										&& Float.parseFloat(postfix_new) > Float.parseFloat(postfix)) {
									itemIndex = z;
								}
							}
						}
					}
					newRule.append(items[itemIndex] + this.CONNECTOR);
				}
			} else {
				newRule.append(items[itemIndex] + this.CONNECTOR);
			}
		}
		int modified = newRule.lastIndexOf(this.CONNECTOR);
		if (modified != -1) {
			newRule.delete(modified + 1, newRule.length());
			a_RulesList.remove(a_index);
			a_RulesList.add(a_index, newRule.toString());
		}
	}

	/**
	 * Generate the rules recursively from the ClassifierTree. "AND" can be
	 * displayed in red to improve the readibility in the future. Some
	 * limitations are listed in the algorithm too.
	 * 
	 * @param a_ClassifierTree
	 * @param a_rule
	 */
	@SuppressWarnings("unchecked")
	private void generateRules(ClassifierTree a_ClassifierTree, StringBuffer a_rule) {
		ClassifierTree[] childClassifierTrees = a_ClassifierTree.getClassifierTreeChildren();
		if (childClassifierTrees != null) {
			for (int i = 0; i < childClassifierTrees.length; i++) {
				StringBuffer myString = new StringBuffer(a_rule.toString());
				if (childClassifierTrees[i].isLeaf()) {
					// Add rule content. Remove the result part. According to
					// dumpModel() method
					// in the ClassifierSplitModel, it starts from a semicolon
					// ":". However, if
					// there is a ":" in the conclusion part, part of the
					// conclusion will also be
					// included. To be improved in the future.
					myString.append(childClassifierTrees[i].getM_NodeContent());
					m_RuleLists.add(myString.substring(0, myString.lastIndexOf(":")));
					ClassifierSplitModel classifierSplitModel = childClassifierTrees[i].getClassifierSplitModel();
					Distribution distribution = classifierSplitModel.distribution();
					// Add other columns. I assume that the number of records
					// per bag >0, otherwise, there
					// should be no this SUBTREE at all. Since the leaf has no
					// subtree, we always call .perBag(0)
					int classIndex = distribution.maxClass();
					m_SuppLists.add(new Double(Utils.roundDouble(distribution.perBag(0),
							NumberFormatter.MAX_FRACTION_DIGIT)));
					m_ConfLists.add(new Double(Utils.roundDouble(distribution.numCorrect(0) / distribution.perBag(0)
							* 100, NumberFormatter.MAX_FRACTION_DIGIT)));
					m_ClassNameLists.add(m_ClassValues.get(classIndex));
				} else {
					myString.append(childClassifierTrees[i].getM_NodeContent() + this.CONNECTOR);
					generateRules(childClassifierTrees[i], myString);
				}
			}
		}
	}

	public void setColumnWidth() {
		TableColumnModel tcm = m_DataTable.getColumnModel();
		for (int i = 1; i < tcm.getColumnCount(); i++) {
			tcm.getColumn(i).setMinWidth(90);
		}
		tcm.getColumn(1).setMinWidth(250);
		m_DataTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
		tcm.getColumn(0).setCellRenderer(m_DataTable.getTableHeader().getDefaultRenderer());
	}

	/**
	 * Exort the data table into an excel file.
	 * 
	 * Called by the OperatorResult class. The subclass of OperatorResult must
	 * call m_SelectedView.export() explictly if it overwirtes the export()
	 * function of OperatorResult.
	 */
	public void export() throws AppException, SysException {
		// Use user home directory
		File directory = new File(System.getProperty("user.dir"));
		// Create and initialize file chooser for excel
		JFileChooser chooser = new JFileChooser(directory);
		chooser.setDialogTitle(Resource.srcStr("FileExport"));
		chooser.setFileFilter(ExcelExporter.FILTER);
		chooser.setSelectedFile(ExcelExporter.DEFAULT_FILE);
		// pop up the file chooser dialog and return the file value
		int returnVal = chooser.showSaveDialog(this);
		if (returnVal == JFileChooser.APPROVE_OPTION) {
			File exportFile = chooser.getSelectedFile();
			// <<tyleung 20/4/2005
			if (exportFile.exists()) {
				int option = JOptionPane.showConfirmDialog((Component) this, "The file  \"" + exportFile.getName()
						+ "\"" + " already exists. Do you want to replace the existing file?",//						
						"AlphaMiner", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
				if (option != JOptionPane.CANCEL_OPTION) {
					if (option == JOptionPane.YES_OPTION) {
						// Create the excel exporter with the excel file
						// extension enforced to be .xls
						ExcelExporter aExporter = new ExcelExporter(m_DataTable, exportFile, true);
						aExporter.export();
					} else {
						returnVal = chooser.showSaveDialog(this);
					}
				}
			} else {
				// Create the excel exporter with the excel file extension
				// enforced to be .xls
				ExcelExporter aExporter = new ExcelExporter(m_DataTable, exportFile, true);
				aExporter.export();
			}
		}
		// tyleung 20/4/2005>>
	}
	/**
	 * A JLabel like JTable render.
	 * 
	 * @author twang
	 */
	class JLabelRenderer extends JLabel implements TableCellRenderer {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		public JLabelRenderer() {
			// setFont(getFont().deriveFont(Font.BOLD));
			// setOpaque(true); // To make background color show.
		}

		public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
				boolean hasFocus, int row, int column) {
			// setText(((JLabel)table.getValueAt(row, column)).toString());
			JLabel label = (JLabel) value;
			label.setAutoscrolls(false);
			// label.setPreferredSize(new Dimension(2, 30));
			return (Component) label;
		}
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -