📄 userclassifier.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. *//* * UserClassifier.java * Copyright (C) 1999 Malcolm Ware * */package weka.classifiers;import java.awt.event.*;import java.io.*;import javax.swing.*;import weka.gui.treevisualizer.*;import weka.core.*;import weka.filters.*;import weka.classifiers.*;import weka.classifiers.j48.*;import weka.gui.visualize.*;/*import weka.gui.visualize.VisualizePanel;import weka.gui.visualize.VisualizePanelListener;import weka.gui.visualize.VisualizePanelEvent; */import weka.gui.GenericObjectEditor;import weka.gui.PropertyDialog;import java.beans.PropertyChangeEvent;import java.beans.PropertyChangeSupport;/** * Class for generating an user defined decision tree. For more info see <p> * * Ware M., Frank E., Holmes G., Hall M. and Witten I.H. (2000). * <i>interactive machine learning - letting users build classifiers</i>, * Working Paper 00/4, Department of Computer Science, * University of Waikato; March. Also available online at * <a href="http://www.cs.waikato.ac.nz/~ml/publications/2000/ * 00MW-etal-Interactive-ML.ps"> * http://www.cs.waikato.ac.nz/~ml/publications/2000/ * 00MW-etal-Interactive-ML.ps</a>. <p> * * @author Malcolm Ware (mfw4@cs.waikato.ac.nz) * @version $Revision: 1.8 $ */public class UserClassifier extends DistributionClassifier implements Drawable,TreeDisplayListener, VisualizePanelListener { /** I am not sure if these are strictly adhered to in visualizepanel * so I am making them private to avoid confusion, (note that they will * be correct in this class, VLINE and HLINE aren't used). */ private final static int LEAF = 0; private final static int RECTANGLE = 1; private final static int POLYGON = 2; private final static int POLYLINE = 3; private final static int VLINE = 5; private final static int HLINE =6; /** The tree display panel. */ private TreeVisualizer m_tView = null; /** The instances display. */ private VisualizePanel m_iView = null; /** Two references to the structure of the decision tree. */ private TreeClass m_top, m_focus; /** The next number that can be used as a unique id for a node. */ private int m_nextId; /** These two frames aren't used anymore. */ private JFrame m_treeFrame; private JFrame m_visFrame; /** The tabbed window for the tree and instances view. */ private JTabbedPane m_reps; /** The window. */ private JFrame m_mainWin; /** The status of whether there is a decision tree ready or not. */ private boolean m_built=false; /** A list of other m_classifiers. */ private GenericObjectEditor m_classifiers; /** A window for selecting other classifiers. */ private PropertyDialog m_propertyDialog; /* Register the property editors we need */ static { java.beans.PropertyEditorManager .registerEditor(weka.core.SelectedTag.class, weka.gui.SelectedTagEditor.class); java.beans.PropertyEditorManager .registerEditor(weka.filters.Filter.class, weka.gui.GenericObjectEditor.class); java.beans.PropertyEditorManager .registerEditor(weka.classifiers.Classifier [].class, weka.gui.GenericArrayEditor.class); java.beans.PropertyEditorManager .registerEditor(weka.classifiers.Classifier.class, weka.gui.GenericObjectEditor.class); java.beans.PropertyEditorManager .registerEditor(weka.classifiers.CostMatrix.class, weka.gui.CostMatrixEditor.class); } /** * Main method for testing this class. * * @param argv should contain command line options (see setOptions) */ public static void main(String [] argv) { try { System.out.println(Evaluation.evaluateModel(new UserClassifier(), argv)); } catch (Exception e) { System.err.println(e.getMessage()); e.printStackTrace(); } System.exit(0); //System.out.println("im done"); } /** * @return a string that represents this objects tree. */ public String toString() { if (!m_built) { return "Tree Not Built"; } StringBuffer text = new StringBuffer(); try { m_top.toString(0, text); m_top.objectStrings(text); } catch(Exception e) { System.out.println("error: " + e.getMessage()); } return text.toString(); } /** * Receives user choices from the tree view, and then deals with these * choices. * @param e The choice. */ public void userCommand(TreeDisplayEvent e) { if (m_propertyDialog != null) { m_propertyDialog.dispose(); m_propertyDialog = null; } try { if (m_iView == null || m_tView == null) { //throw exception } if (e.getCommand() == e.NO_COMMAND) { //do nothing } else if (e.getCommand() == e.ADD_CHILDREN) { //highlight the particular node and reset the vis panel if (m_top == null) { //this shouldn't happen , someone elses code would //have to have added a trigger to this listener. System.out.println("Error : Received event from a TreeDisplayer" + " that is unknown to the classifier."); } else { m_tView.setHighlight(e.getID()); /*if (m_iView == null) { m_iView = new VisualizePanel(this); m_iView.setSize(400, 300); }*/ m_focus = m_top.getNode(e.getID()); m_iView.setInstances(m_focus.m_training); if (m_focus.m_attrib1 >= 0) { m_iView.setXIndex(m_focus.m_attrib1); } if (m_focus.m_attrib2 >= 0) { m_iView.setYIndex(m_focus.m_attrib2); } m_iView.setColourIndex(m_focus.m_training.classIndex()); if (((Double)((FastVector)m_focus.m_ranges.elementAt(0)). elementAt(0)).intValue() != LEAF) { m_iView.setShapes(m_focus.m_ranges); } //m_iView.setSIndex(2); } } else if (e.getCommand() == e.REMOVE_CHILDREN) { /*if (m_iView == null) { m_iView = new VisualizePanel(this); m_iView.setSize(400, 300); }*/ m_focus = m_top.getNode(e.getID()); m_iView.setInstances(m_focus.m_training); if (m_focus.m_attrib1 >= 0) { m_iView.setXIndex(m_focus.m_attrib1); } if (m_focus.m_attrib2 >= 0) { m_iView.setYIndex(m_focus.m_attrib2); } m_iView.setColourIndex(m_focus.m_training.classIndex()); if (((Double)((FastVector)m_focus.m_ranges.elementAt(0)). elementAt(0)).intValue() != LEAF) { m_iView.setShapes(m_focus.m_ranges); } //m_iView.setSIndex(2); //now to remove all the stuff m_focus.m_set1 = null; m_focus.m_set2 = null; m_focus.setInfo(m_focus.m_attrib1, m_focus.m_attrib2, null); //tree_frame.getContentPane().removeAll(); m_tView = new TreeVisualizer(this, graph(), new PlaceNode2()); //tree_frame.getContentPane().add(m_tView); m_reps.setComponentAt(0, m_tView); //tree_frame.getContentPane().doLayout(); m_tView.setHighlight(m_focus.m_identity); } else if (e.getCommand() == e.CLASSIFY_CHILD) { /*if (m_iView == null) { m_iView = new VisualizePanel(this); m_iView.setSize(400, 300); }*/ m_focus = m_top.getNode(e.getID()); m_iView.setInstances(m_focus.m_training); if (m_focus.m_attrib1 >= 0) { m_iView.setXIndex(m_focus.m_attrib1); } if (m_focus.m_attrib2 >= 0) { m_iView.setYIndex(m_focus.m_attrib2); } m_iView.setColourIndex(m_focus.m_training.classIndex()); if (((Double)((FastVector)m_focus.m_ranges.elementAt(0)). elementAt(0)).intValue() != LEAF) { m_iView.setShapes(m_focus.m_ranges); } m_propertyDialog = new PropertyDialog(m_classifiers, m_mainWin.getLocationOnScreen().x, m_mainWin.getLocationOnScreen().y); //note property dialog may change all the time //but the generic editor which has the listeners does not //so at the construction of the editor is when I am going to add //the listeners. //focus.setClassifier(new IB1()); //tree_frame.getContentPane().removeAll(); //////m_tView = new Displayer(this, graph(), new PlaceNode2()); //tree_frame.getContentPane().add(m_tView); //tree_frame.getContentPane().doLayout(); /////////////reps.setComponentAt(0, m_tView); m_tView.setHighlight(m_focus.m_identity); } /*else if (e.getCommand() == e.SEND_INSTANCES) { TreeClass source = m_top.getNode(e.getID()); m_iView.setExtInstances(source.m_training); }*/ else if (e.getCommand() == e.ACCEPT) { int well = JOptionPane.showConfirmDialog(m_mainWin, "Are You Sure...\n" + "Click Yes To Accept The" + " Tree" + "\n Click No To Return", "Accept Tree", JOptionPane.YES_NO_OPTION); if (well == 0) { m_mainWin.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); m_mainWin.dispose(); blocker(false); //release the thread waiting at blocker to //continue. } } } catch(Exception er) { System.out.println("Error : " + er); System.out.println("Part of user input so had to catch here"); er.printStackTrace(); } } /** * This receives shapes from the data view. * It then enters these shapes into the decision tree structure. * @param e Contains the shapes, and other info. */ public void userDataEvent(VisualizePanelEvent e) { if (m_propertyDialog != null) { m_propertyDialog.dispose(); m_propertyDialog = null; } try { if (m_focus != null) { double wdom = e.getInstances1().numInstances() + e.getInstances2().numInstances(); if (wdom == 0) { wdom = 1; } TreeClass tmp = m_focus; m_focus.m_set1 = new TreeClass(null, e.getAttribute1(), e.getAttribute2(), m_nextId, e.getInstances1().numInstances() / wdom, e.getInstances1(), m_focus); m_focus.m_set2 = new TreeClass(null, e.getAttribute1(), e.getAttribute2(), m_nextId, e.getInstances2().numInstances() / wdom, e.getInstances2(), m_focus); //this needs the other instance //tree_frame.getContentPane().removeAll(); m_focus.setInfo(e.getAttribute1(), e.getAttribute2(), e.getValues()); //System.out.println(graph()); m_tView = new TreeVisualizer(this, graph(), new PlaceNode2()); //tree_frame.getContentPane().add(m_tView); //tree_frame.getContentPane().doLayout(); m_reps.setComponentAt(0, m_tView); m_focus = m_focus.m_set2; m_tView.setHighlight(m_focus.m_identity); m_iView.setInstances(m_focus.m_training); if (tmp.m_attrib1 >= 0) { m_iView.setXIndex(tmp.m_attrib1); } if (tmp.m_attrib2 >= 0) { m_iView.setYIndex(tmp.m_attrib2); } m_iView.setColourIndex(m_focus.m_training.classIndex()); if (((Double)((FastVector)m_focus.m_ranges.elementAt(0)). elementAt(0)).intValue() != LEAF) { m_iView.setShapes(m_focus.m_ranges); } //m_iView.setSIndex(2); } else { System.out.println("Somehow the focus is null"); } } catch(Exception er) { System.out.println("Error : " + er); System.out.println("Part of user input so had to catch here"); //er.printStackTrace(); } } /** * Constructor */ public UserClassifier() { //do nothing here except set alot of variables to default values m_top = null; m_tView = null; m_iView = null; m_nextId = 0; } /** * @return A string formatted with a dotty representation of the decision * tree. * @exception Exception if String can't be built properly. */ public String graph() throws Exception { //create a dotty rep of the tree from here StringBuffer text = new StringBuffer(); text.append("digraph UserClassifierTree {\n" + "node [fontsize=10]\n" + "edge [fontsize=10 style=bold]\n"); m_top.toDotty(text); return text.toString() +"}\n"; } /** * A function used to stop the code that called buildclassifier * from continuing on before the user has finished the decision tree. * @param tf True to stop the thread, False to release the thread that is * waiting there (if one). */ private synchronized void blocker(boolean tf) { if (tf) { try { wait(); } catch(InterruptedException e) { } } else { notifyAll(); } //System.out.println("out"); } /** * This will return a string describing the classifier. * @return The string. */ public String globalInfo() { return "Interactively classify through visual means." + " You are Presented with a scatter graph of the data against two user" + " selectable attributes, as well as a view of the decision tree." + " You can create binary splits by creating polygons around data" + " plotted on the scatter graph, as well as by allowing another" + " classifier to take over at points in the decision tree should you" + " see fit."; } /** * Call this function to build a decision tree for the training * data provided. * @param i The training data. * @exception Exception if can't build classification properly. */ public void buildClassifier(Instances i) throws Exception { //construct a visualizer //construct a tree displayer and feed both then do nothing //note that I will display at the bottom of each split how many //fall into each catagory m_classifiers = new GenericObjectEditor(); m_classifiers.setClassType(Classifier.class); m_classifiers.setValue(new weka.classifiers.ZeroR()); ((GenericObjectEditor.GOEPanel)m_classifiers.getCustomEditor()) .addOkListener(new ActionListener() { public void actionPerformed(ActionEvent e) { //I want to use the focus variable but to trust it I need //to kill the window if anything gets changed by either //editor try { m_focus.m_set1 = null; m_focus.m_set2 = null; m_focus.setInfo(m_focus.m_attrib1, m_focus.m_attrib2, null); m_focus.setClassifier((Classifier)m_classifiers.getValue()); m_classifiers = new GenericObjectEditor(); m_classifiers.setClassType(Classifier.class); m_classifiers.setValue(new weka.classifiers.ZeroR()); ((GenericObjectEditor.GOEPanel)m_classifiers.getCustomEditor()) .addOkListener(this);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -