ClassifierPanel.java
Upload User: rhdiban
Upload Date: 2013-08-09
Package Size: 15085k
Code Size: 66k
Category:

Windows Develop

Development Platform:

Java

  1. /*
  2.  *    This program is free software; you can redistribute it and/or modify
  3.  *    it under the terms of the GNU General Public License as published by
  4.  *    the Free Software Foundation; either version 2 of the License, or
  5.  *    (at your option) any later version.
  6.  *
  7.  *    This program is distributed in the hope that it will be useful,
  8.  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  9.  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10.  *    GNU General Public License for more details.
  11.  *
  12.  *    You should have received a copy of the GNU General Public License
  13.  *    along with this program; if not, write to the Free Software
  14.  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15.  */
  16. /*
  17.  *    ClassifierPanel.java
  18.  *    Copyright (C) 1999 Len Trigg
  19.  *
  20.  */
  21. package weka.gui.explorer;
  22. import weka.core.Instances;
  23. import weka.core.Instance;
  24. import weka.core.FastVector;
  25. import weka.core.OptionHandler;
  26. import weka.core.Attribute;
  27. import weka.core.Utils;
  28. import weka.core.Drawable;
  29. import weka.core.SerializedObject;
  30. import weka.classifiers.Classifier;
  31. import weka.classifiers.DistributionClassifier;
  32. import weka.classifiers.Evaluation;
  33. import weka.classifiers.CostMatrix;
  34. import weka.classifiers.evaluation.NominalPrediction;
  35. import weka.classifiers.evaluation.MarginCurve;
  36. import weka.classifiers.evaluation.ThresholdCurve;
  37. import weka.classifiers.evaluation.CostCurve;
  38. import weka.filters.Filter;
  39. import weka.gui.Logger;
  40. import weka.gui.TaskLogger;
  41. import weka.gui.SysErrLog;
  42. import weka.gui.GenericObjectEditor;
  43. import weka.gui.PropertyPanel;
  44. import weka.gui.ResultHistoryPanel;
  45. import weka.gui.SetInstancesPanel;
  46. import weka.gui.CostMatrixEditor;
  47. import weka.gui.PropertyDialog;
  48. import weka.gui.InstancesSummaryPanel;
  49. import weka.gui.SaveBuffer;
  50. import weka.gui.visualize.VisualizePanel;
  51. import weka.gui.visualize.PlotData2D;
  52. import weka.gui.visualize.Plot2D;
  53. import weka.gui.ExtensionFileFilter;
  54. import weka.gui.treevisualizer.*;
  55. import java.util.Random;
  56. import java.util.Date;
  57. import java.text.SimpleDateFormat;
  58. import java.awt.FlowLayout;
  59. import java.awt.BorderLayout;
  60. import java.awt.GridLayout;
  61. import java.awt.GridBagLayout;
  62. import java.awt.GridBagConstraints;
  63. import java.awt.Insets;
  64. import java.awt.Font;
  65. import java.awt.Point;
  66. import java.awt.event.ActionListener;
  67. import java.awt.event.ActionEvent;
  68. import java.awt.event.InputEvent;
  69. import java.awt.event.MouseAdapter;
  70. import java.awt.event.MouseEvent;
  71. import java.awt.Window;
  72. import java.awt.Dimension;
  73. import java.beans.PropertyChangeListener;
  74. import java.beans.PropertyChangeEvent;
  75. import java.beans.PropertyChangeSupport;
  76. import java.io.File;
  77. import java.io.FileWriter;
  78. import java.io.Writer;
  79. import java.io.BufferedWriter;
  80. import java.io.PrintWriter;
  81. import java.io.OutputStream;
  82. import java.io.ObjectOutputStream;
  83. import java.io.FileOutputStream;
  84. import java.util.zip.GZIPOutputStream;
  85. import java.io.InputStream;
  86. import java.io.ObjectInputStream;
  87. import java.io.FileInputStream;
  88. import java.util.zip.GZIPInputStream;
  89. import javax.swing.JFileChooser;
  90. import javax.swing.JPanel;
  91. import javax.swing.JLabel;
  92. import javax.swing.JButton;
  93. import javax.swing.BorderFactory;
  94. import javax.swing.JTextArea;
  95. import javax.swing.JScrollPane;
  96. import javax.swing.JRadioButton;
  97. import javax.swing.ButtonGroup;
  98. import javax.swing.JOptionPane;
  99. import javax.swing.JComboBox;
  100. import javax.swing.DefaultComboBoxModel;
  101. import javax.swing.JTextField;
  102. import javax.swing.SwingConstants;
  103. import javax.swing.JFrame;
  104. import javax.swing.event.ChangeListener;
  105. import javax.swing.event.ChangeEvent;
  106. import javax.swing.JViewport;
  107. import javax.swing.JCheckBox;
  108. import javax.swing.ListSelectionModel;
  109. import javax.swing.event.ListSelectionEvent;
  110. import javax.swing.event.ListSelectionListener;
  111. import javax.swing.JPopupMenu;
  112. import javax.swing.JMenu;
  113. import javax.swing.JMenuItem;
  114. import javax.swing.filechooser.FileFilter;
  115. /** 
  116.  * This panel allows the user to select and configure a classifier, set the
  117.  * attribute of the current dataset to be used as the class, and evaluate
  118.  * the classifier using a number of testing modes (test on the training data,
  119.  * train/test on a percentage split, n-fold cross-validation, test on a
  120.  * separate split). The results of classification runs are stored in a result
  121.  * history so that previous results are accessible.
  122.  *
  123.  * @author Len Trigg (trigg@cs.waikato.ac.nz)
  124.  * @author Mark Hall (mhall@cs.waikato.ac.nz)
  125.  * @author Richard Kirkby (rkirkby@cs.waikato.ac.nz)
  126.  * @version $Revision: 1.55 $
  127.  */
  128. public class ClassifierPanel extends JPanel {
  129.   /** Lets the user configure the classifier */
  130.   protected GenericObjectEditor m_ClassifierEditor =
  131.     new GenericObjectEditor();
  132.   /** The panel showing the current classifier selection */
  133.   protected PropertyPanel m_CEPanel = new PropertyPanel(m_ClassifierEditor);
  134.   
  135.   /** The output area for classification results */
  136.   protected JTextArea m_OutText = new JTextArea(20, 40);
  137.   /** The destination for log/status messages */
  138.   protected Logger m_Log = new SysErrLog();
  139.   /** The buffer saving object for saving output */
  140.   SaveBuffer m_SaveOut = new SaveBuffer(m_Log, this);
  141.   /** A panel controlling results viewing */
  142.   protected ResultHistoryPanel m_History = new ResultHistoryPanel(m_OutText);
  143.   /** Lets the user select the class column */
  144.   protected JComboBox m_ClassCombo = new JComboBox();
  145.   /** Click to set test mode to cross-validation */
  146.   protected JRadioButton m_CVBut = new JRadioButton("Cross-validation");
  147.   /** Click to set test mode to generate a % split */
  148.   protected JRadioButton m_PercentBut = new JRadioButton("Percentage split");
  149.   /** Click to set test mode to test on training data */
  150.   protected JRadioButton m_TrainBut = new JRadioButton("Use training set");
  151.   /** Click to set test mode to a user-specified test set */
  152.   protected JRadioButton m_TestSplitBut =
  153.     new JRadioButton("Supplied test set");
  154.   /** Check to save the predictions in the results list for visualizing
  155.       later on */
  156.   protected JCheckBox m_StorePredictionsBut = 
  157.     new JCheckBox("Store predictions for visualization");
  158.   /** Check to output the model built from the training data */
  159.   protected JCheckBox m_OutputModelBut = new JCheckBox("Output model");
  160.   /** Check to output true/false positives, precision/recall for each class */
  161.   protected JCheckBox m_OutputPerClassBut =
  162.     new JCheckBox("Output per-class stats");
  163.   /** Check to output a confusion matrix */
  164.   protected JCheckBox m_OutputConfusionBut =
  165.     new JCheckBox("Output confusion matrix");
  166.   /** Check to output entropy statistics */
  167.   protected JCheckBox m_OutputEntropyBut =
  168.     new JCheckBox("Output entropy evaluation measures");
  169.   /** Check to evaluate w.r.t a cost matrix */
  170.   protected JCheckBox m_EvalWRTCostsBut =
  171.     new JCheckBox("Cost-sensitive evaluation");
  172.   protected JButton m_SetCostsBut = new JButton("Set...");
  173.   /** Label by where the cv folds are entered */
  174.   protected JLabel m_CVLab = new JLabel("Folds", SwingConstants.RIGHT);
  175.   /** The field where the cv folds are entered */
  176.   protected JTextField m_CVText = new JTextField("10");
  177.   /** Label by where the % split is entered */
  178.   protected JLabel m_PercentLab = new JLabel("%", SwingConstants.RIGHT);
  179.   /** The field where the % split is entered */
  180.   protected JTextField m_PercentText = new JTextField("66");
  181.   /** The button used to open a separate test dataset */
  182.   protected JButton m_SetTestBut = new JButton("Set...");
  183.   /** The frame used to show the test set selection panel */
  184.   protected JFrame m_SetTestFrame;
  185.   /** The frame used to show the cost matrix editing panel */
  186.   protected PropertyDialog m_SetCostsFrame;
  187.   /**
  188.    * Alters the enabled/disabled status of elements associated with each
  189.    * radio button
  190.    */
  191.   ActionListener m_RadioListener = new ActionListener() {
  192.     public void actionPerformed(ActionEvent e) {
  193.       updateRadioLinks();
  194.     }
  195.   };
  196.   /** Button for further output/visualize options */
  197.   JButton m_MoreOptions = new JButton("More options...");
  198.   /**
  199.    * User specified random seed for cross validation or % split
  200.    */
  201.   protected JTextField m_RandomSeedText = new JTextField("1      ");
  202.   protected JLabel m_RandomLab = new JLabel("Random seed for XVal / % Split", 
  203.     SwingConstants.RIGHT);
  204.   /** Click to start running the classifier */
  205.   protected JButton m_StartBut = new JButton("Start");
  206.   /** Click to stop a running classifier */
  207.   protected JButton m_StopBut = new JButton("Stop");
  208.   /** Stop the class combo from taking up to much space */
  209.   private Dimension COMBO_SIZE = new Dimension(150, m_StartBut
  210.        .getPreferredSize().height);
  211.   /** The cost matrix editor for evaluation costs */
  212.   protected CostMatrixEditor m_CostMatrixEditor = new CostMatrixEditor();
  213.   /** The main set of instances we're playing with */
  214.   protected Instances m_Instances;
  215.   /** The user-supplied test set (if any) */
  216.   protected Instances m_TestInstances;
  217.   /** The user supplied test set after preprocess filters have been applied */
  218.   protected Instances m_TestInstancesCopy;
  219.   
  220.   /** A thread that classification runs in */
  221.   protected Thread m_RunThread;
  222.   /** default x index for visualizing */
  223.   protected int m_visXIndex;
  224.   
  225.   /** default y index for visualizing */
  226.   protected int m_visYIndex;
  227.   /** The current visualization object */
  228.   protected VisualizePanel m_CurrentVis = null;
  229.   /** The preprocess panel through which filters can be applied to
  230.       user supplied test data sets */
  231.   protected PreprocessPanel m_Preprocess = null;
  232.   /** The instances summary panel displayed by m_SetTestFrame */
  233.   protected InstancesSummaryPanel m_Summary = null;
  234.   /** Filter to ensure only model files are selected */  
  235.   protected FileFilter m_ModelFilter =
  236.     new ExtensionFileFilter("model", "Model object files");
  237.   /** The file chooser for selecting model files */
  238.   protected JFileChooser m_FileChooser 
  239.     = new JFileChooser(new File(System.getProperty("user.dir")));
  240.   /* Register the property editors we need */
  241.   static {
  242.     java.beans.PropertyEditorManager
  243.       .registerEditor(weka.core.SelectedTag.class,
  244.       weka.gui.SelectedTagEditor.class);
  245.     java.beans.PropertyEditorManager
  246.       .registerEditor(weka.filters.Filter.class,
  247.       weka.gui.GenericObjectEditor.class);
  248.     java.beans.PropertyEditorManager
  249.       .registerEditor(weka.classifiers.Classifier [].class,
  250.       weka.gui.GenericArrayEditor.class);
  251.     java.beans.PropertyEditorManager
  252.       .registerEditor(weka.classifiers.DistributionClassifier.class,
  253.       weka.gui.GenericObjectEditor.class);
  254.     java.beans.PropertyEditorManager
  255.       .registerEditor(weka.classifiers.Classifier.class,
  256.       weka.gui.GenericObjectEditor.class);
  257.     java.beans.PropertyEditorManager
  258.       .registerEditor(weka.classifiers.CostMatrix.class,
  259.       weka.gui.CostMatrixEditor.class);
  260.   }
  261.   
  262.   /**
  263.    * Creates the classifier panel
  264.    */
  265.   public ClassifierPanel() {
  266.     // Connect / configure the components
  267.     m_OutText.setEditable(false);
  268.     m_OutText.setFont(new Font("Monospaced", Font.PLAIN, 12));
  269.     m_OutText.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
  270.     m_OutText.addMouseListener(new MouseAdapter() {
  271.       public void mouseClicked(MouseEvent e) {
  272. if ((e.getModifiers() & InputEvent.BUTTON1_MASK)
  273.     != InputEvent.BUTTON1_MASK) {
  274.   m_OutText.selectAll();
  275. }
  276.       }
  277.     });
  278.     m_History.setBorder(BorderFactory.createTitledBorder("Result list (right-click for options)"));
  279.     m_ClassifierEditor.setClassType(Classifier.class);
  280.     m_ClassifierEditor.setValue(new weka.classifiers.rules.ZeroR());
  281.     m_ClassifierEditor.addPropertyChangeListener(new PropertyChangeListener() {
  282.       public void propertyChange(PropertyChangeEvent e) {
  283. repaint();
  284.       }
  285.     });
  286.     m_ClassCombo.setToolTipText("Select the attribute to use as the class");
  287.     m_TrainBut.setToolTipText("Test on the same set that the classifier"
  288.       + " is trained on");
  289.     m_CVBut.setToolTipText("Perform a n-fold cross-validation");
  290.     m_PercentBut.setToolTipText("Train on a percentage of the data and"
  291. + " test on the remainder");
  292.     m_TestSplitBut.setToolTipText("Test on a user-specified dataset");
  293.     m_StartBut.setToolTipText("Starts the classification");
  294.     m_StopBut.setToolTipText("Stops a running classification");
  295.     m_StorePredictionsBut.
  296.       setToolTipText("Store predictions in the result list for later "
  297.      +"visualization");
  298.     m_OutputModelBut
  299.       .setToolTipText("Output the model obtained from the full training set");
  300.     m_OutputPerClassBut.setToolTipText("Output precision/recall & true/false"
  301.     + " positives for each class");
  302.     m_OutputConfusionBut
  303.       .setToolTipText("Output the matrix displaying class confusions");
  304.     m_OutputEntropyBut
  305.       .setToolTipText("Output entropy-based evaluation measures");
  306.     m_EvalWRTCostsBut
  307.       .setToolTipText("Evaluate errors with respect to a cost matrix");
  308.     m_FileChooser.setFileFilter(m_ModelFilter);
  309.     m_FileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
  310.     m_StorePredictionsBut.setSelected(true);
  311.     m_OutputModelBut.setSelected(true);
  312.     m_OutputPerClassBut.setSelected(true);
  313.     m_OutputConfusionBut.setSelected(true);
  314.     m_ClassCombo.setEnabled(false);
  315.     m_ClassCombo.setPreferredSize(COMBO_SIZE);
  316.     m_ClassCombo.setMaximumSize(COMBO_SIZE);
  317.     m_ClassCombo.setMinimumSize(COMBO_SIZE);
  318.     m_CVBut.setSelected(true);
  319.     updateRadioLinks();
  320.     ButtonGroup bg = new ButtonGroup();
  321.     bg.add(m_TrainBut);
  322.     bg.add(m_CVBut);
  323.     bg.add(m_PercentBut);
  324.     bg.add(m_TestSplitBut);
  325.     m_TrainBut.addActionListener(m_RadioListener);
  326.     m_CVBut.addActionListener(m_RadioListener);
  327.     m_PercentBut.addActionListener(m_RadioListener);
  328.     m_TestSplitBut.addActionListener(m_RadioListener);
  329.     m_SetTestBut.addActionListener(new ActionListener() {
  330.       public void actionPerformed(ActionEvent e) {
  331. setTestSet();
  332.       }
  333.     });
  334.     m_EvalWRTCostsBut.addActionListener(new ActionListener() {
  335.       public void actionPerformed(ActionEvent e) {
  336. m_SetCostsBut.setEnabled(m_EvalWRTCostsBut.isSelected());
  337. if ((m_SetCostsFrame != null) 
  338.     && (!m_EvalWRTCostsBut.isSelected())) {
  339.   m_SetCostsFrame.setVisible(false);
  340. }
  341.       }
  342.     });
  343.     m_CostMatrixEditor.setValue(new CostMatrix(1));
  344.     m_SetCostsBut.setEnabled(m_EvalWRTCostsBut.isSelected());
  345.     m_SetCostsBut.addActionListener(new ActionListener() {
  346.       public void actionPerformed(ActionEvent e) {
  347. m_SetCostsBut.setEnabled(false);
  348. if (m_SetCostsFrame == null) {
  349.   m_SetCostsFrame = new PropertyDialog(m_CostMatrixEditor, 100, 100);
  350.   // pd.setSize(250,150);
  351.   m_SetCostsFrame.addWindowListener(new java.awt.event.WindowAdapter() {
  352.     public void windowClosing(java.awt.event.WindowEvent p) {
  353.       m_SetCostsBut.setEnabled(m_EvalWRTCostsBut.isSelected());
  354.       if ((m_SetCostsFrame != null) 
  355.   && (!m_EvalWRTCostsBut.isSelected())) {
  356. m_SetCostsFrame.setVisible(false);
  357.       }
  358.     }
  359.   });
  360. }
  361. m_SetCostsFrame.setVisible(true);
  362.       }
  363.     });
  364.     m_StartBut.setEnabled(false);
  365.     m_StopBut.setEnabled(false);
  366.     m_StartBut.addActionListener(new ActionListener() {
  367.       public void actionPerformed(ActionEvent e) {
  368. startClassifier();
  369.       }
  370.     });
  371.     m_StopBut.addActionListener(new ActionListener() {
  372.       public void actionPerformed(ActionEvent e) {
  373. stopClassifier();
  374.       }
  375.     });
  376.    
  377.     m_ClassCombo.addActionListener(new ActionListener() {
  378.       public void actionPerformed(ActionEvent e) {
  379. int selected = m_ClassCombo.getSelectedIndex();
  380. if (selected != -1) {
  381.   boolean isNominal = m_Instances.attribute(selected).isNominal();
  382.   m_OutputPerClassBut.setEnabled(isNominal);
  383.   m_OutputConfusionBut.setEnabled(isNominal);
  384. }
  385.       }
  386.     });
  387.     m_History.setHandleRightClicks(false);
  388.     // see if we can popup a menu for the selected result
  389.     m_History.getList().addMouseListener(new MouseAdapter() {
  390. public void mouseClicked(MouseEvent e) {
  391.   if ((e.getModifiers() & InputEvent.BUTTON1_MASK)
  392.       == InputEvent.BUTTON1_MASK) {
  393.     
  394.   } else {
  395.     int index = m_History.getList().locationToIndex(e.getPoint());
  396.     if (index != -1) {
  397.       String name = m_History.getNameAtIndex(index);
  398.       visualize(name, e.getX(), e.getY());
  399.     } else {
  400.       visualize(null, e.getX(), e.getY());
  401.     }
  402.   }
  403. }
  404.       });
  405.     m_MoreOptions.addActionListener(new ActionListener() {
  406.       public void actionPerformed(ActionEvent e) {
  407. m_MoreOptions.setEnabled(false);
  408. JPanel moreOptionsPanel = new JPanel();
  409. moreOptionsPanel.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5));
  410. moreOptionsPanel.setLayout(new GridLayout(7, 1));
  411. moreOptionsPanel.add(m_OutputModelBut);
  412. moreOptionsPanel.add(m_OutputPerClassBut);   
  413. moreOptionsPanel.add(m_OutputEntropyBut);   
  414. moreOptionsPanel.add(m_OutputConfusionBut);   
  415. moreOptionsPanel.add(m_StorePredictionsBut);
  416. JPanel costMatrixOption = new JPanel();
  417. costMatrixOption.setLayout(new BorderLayout());
  418. costMatrixOption.add(m_EvalWRTCostsBut, BorderLayout.WEST);
  419. costMatrixOption.add(m_SetCostsBut, BorderLayout.EAST);
  420. moreOptionsPanel.add(costMatrixOption);
  421. JPanel seedPanel = new JPanel();
  422. seedPanel.setLayout(new BorderLayout());
  423. seedPanel.add(m_RandomLab, BorderLayout.WEST);
  424. seedPanel.add(m_RandomSeedText, BorderLayout.EAST);
  425. moreOptionsPanel.add(seedPanel);
  426. JPanel all = new JPanel();
  427. all.setLayout(new BorderLayout());
  428. JButton oK = new JButton("OK");
  429. JPanel okP = new JPanel();
  430. okP.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
  431. okP.setLayout(new GridLayout(1,1,5,5));
  432. okP.add(oK);
  433. all.add(moreOptionsPanel, BorderLayout.CENTER);
  434. all.add(okP, BorderLayout.SOUTH);
  435. final javax.swing.JFrame jf = 
  436.   new javax.swing.JFrame("Classifier evaluation options");
  437. jf.getContentPane().setLayout(new BorderLayout());
  438. jf.getContentPane().add(all, BorderLayout.CENTER);
  439. jf.addWindowListener(new java.awt.event.WindowAdapter() {
  440.   public void windowClosing(java.awt.event.WindowEvent w) {
  441.     jf.dispose();
  442.     m_MoreOptions.setEnabled(true);
  443.   }
  444. });
  445. oK.addActionListener(new ActionListener() {
  446.   public void actionPerformed(ActionEvent a) {
  447.     m_MoreOptions.setEnabled(true);
  448.     jf.dispose();
  449.   }
  450. });
  451. jf.pack();
  452. jf.setLocation(m_MoreOptions.getLocationOnScreen());
  453. jf.setVisible(true);
  454.       }
  455.     });
  456.     // Layout the GUI
  457.     JPanel p1 = new JPanel();
  458.     p1.setBorder(BorderFactory.createCompoundBorder(
  459.  BorderFactory.createTitledBorder("Classifier"),
  460.  BorderFactory.createEmptyBorder(0, 5, 5, 5)
  461.  ));
  462.     p1.setLayout(new BorderLayout());
  463.     p1.add(m_CEPanel, BorderLayout.NORTH);
  464.     JPanel p2 = new JPanel();
  465.     GridBagLayout gbL = new GridBagLayout();
  466.     p2.setLayout(gbL);
  467.     p2.setBorder(BorderFactory.createCompoundBorder(
  468.  BorderFactory.createTitledBorder("Test options"),
  469.  BorderFactory.createEmptyBorder(0, 5, 5, 5)
  470.  ));
  471.     GridBagConstraints gbC = new GridBagConstraints();
  472.     gbC.anchor = GridBagConstraints.WEST;
  473.     gbC.gridy = 0;     gbC.gridx = 0;
  474.     gbL.setConstraints(m_TrainBut, gbC);
  475.     p2.add(m_TrainBut);
  476.     gbC = new GridBagConstraints();
  477.     gbC.anchor = GridBagConstraints.WEST;
  478.     gbC.gridy = 1;     gbC.gridx = 0;
  479.     gbL.setConstraints(m_TestSplitBut, gbC);
  480.     p2.add(m_TestSplitBut);
  481.     gbC = new GridBagConstraints();
  482.     gbC.anchor = GridBagConstraints.EAST;
  483.     gbC.fill = GridBagConstraints.HORIZONTAL;
  484.     gbC.gridy = 1;     gbC.gridx = 1;    gbC.gridwidth = 2;
  485.     gbC.insets = new Insets(2, 10, 2, 0);
  486.     gbL.setConstraints(m_SetTestBut, gbC);
  487.     p2.add(m_SetTestBut);
  488.     gbC = new GridBagConstraints();
  489.     gbC.anchor = GridBagConstraints.WEST;
  490.     gbC.gridy = 2;     gbC.gridx = 0;
  491.     gbL.setConstraints(m_CVBut, gbC);
  492.     p2.add(m_CVBut);
  493.     gbC = new GridBagConstraints();
  494.     gbC.anchor = GridBagConstraints.EAST;
  495.     gbC.fill = GridBagConstraints.HORIZONTAL;
  496.     gbC.gridy = 2;     gbC.gridx = 1;
  497.     gbC.insets = new Insets(2, 10, 2, 10);
  498.     gbL.setConstraints(m_CVLab, gbC);
  499.     p2.add(m_CVLab);
  500.     gbC = new GridBagConstraints();
  501.     gbC.anchor = GridBagConstraints.EAST;
  502.     gbC.fill = GridBagConstraints.HORIZONTAL;
  503.     gbC.gridy = 2;     gbC.gridx = 2;  gbC.weightx = 100;
  504.     gbC.ipadx = 20;
  505.     gbL.setConstraints(m_CVText, gbC);
  506.     p2.add(m_CVText);
  507.     gbC = new GridBagConstraints();
  508.     gbC.anchor = GridBagConstraints.WEST;
  509.     gbC.gridy = 3;     gbC.gridx = 0;
  510.     gbL.setConstraints(m_PercentBut, gbC);
  511.     p2.add(m_PercentBut);
  512.     gbC = new GridBagConstraints();
  513.     gbC.anchor = GridBagConstraints.EAST;
  514.     gbC.fill = GridBagConstraints.HORIZONTAL;
  515.     gbC.gridy = 3;     gbC.gridx = 1;
  516.     gbC.insets = new Insets(2, 10, 2, 10);
  517.     gbL.setConstraints(m_PercentLab, gbC);
  518.     p2.add(m_PercentLab);
  519.     gbC = new GridBagConstraints();
  520.     gbC.anchor = GridBagConstraints.EAST;
  521.     gbC.fill = GridBagConstraints.HORIZONTAL;
  522.     gbC.gridy = 3;     gbC.gridx = 2;  gbC.weightx = 100;
  523.     gbC.ipadx = 20;
  524.     gbL.setConstraints(m_PercentText, gbC);
  525.     p2.add(m_PercentText);
  526.     gbC = new GridBagConstraints();
  527.     gbC.anchor = GridBagConstraints.WEST;
  528.     gbC.fill = GridBagConstraints.HORIZONTAL;
  529.     gbC.gridy = 4;     gbC.gridx = 0;  gbC.weightx = 100;
  530.     gbC.gridwidth = 3;
  531.     gbC.insets = new Insets(3, 0, 1, 0);
  532.     gbL.setConstraints(m_MoreOptions, gbC);
  533.     p2.add(m_MoreOptions);
  534.     JPanel buttons = new JPanel();
  535.     buttons.setLayout(new GridLayout(2, 2));
  536.     buttons.add(m_ClassCombo);
  537.     m_ClassCombo.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
  538.     JPanel ssButs = new JPanel();
  539.     ssButs.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
  540.     ssButs.setLayout(new GridLayout(1, 2, 5, 5));
  541.     ssButs.add(m_StartBut);
  542.     ssButs.add(m_StopBut);
  543.     buttons.add(ssButs);
  544.     
  545.     JPanel p3 = new JPanel();
  546.     p3.setBorder(BorderFactory.createTitledBorder("Classifier output"));
  547.     p3.setLayout(new BorderLayout());
  548.     final JScrollPane js = new JScrollPane(m_OutText);
  549.     p3.add(js, BorderLayout.CENTER);
  550.     js.getViewport().addChangeListener(new ChangeListener() {
  551.       private int lastHeight;
  552.       public void stateChanged(ChangeEvent e) {
  553. JViewport vp = (JViewport)e.getSource();
  554. int h = vp.getViewSize().height; 
  555. if (h != lastHeight) { // i.e. an addition not just a user scrolling
  556.   lastHeight = h;
  557.   int x = h - vp.getExtentSize().height;
  558.   vp.setViewPosition(new Point(0, x));
  559. }
  560.       }
  561.     });
  562.     
  563.     JPanel mondo = new JPanel();
  564.     gbL = new GridBagLayout();
  565.     mondo.setLayout(gbL);
  566.     gbC = new GridBagConstraints();
  567.     //    gbC.anchor = GridBagConstraints.WEST;
  568.     gbC.fill = GridBagConstraints.HORIZONTAL;
  569.     gbC.gridy = 0;     gbC.gridx = 0;
  570.     gbL.setConstraints(p2, gbC);
  571.     mondo.add(p2);
  572.     gbC = new GridBagConstraints();
  573.     gbC.anchor = GridBagConstraints.NORTH;
  574.     gbC.fill = GridBagConstraints.HORIZONTAL;
  575.     gbC.gridy = 1;     gbC.gridx = 0;
  576.     gbL.setConstraints(buttons, gbC);
  577.     mondo.add(buttons);
  578.     gbC = new GridBagConstraints();
  579.     //gbC.anchor = GridBagConstraints.NORTH;
  580.     gbC.fill = GridBagConstraints.BOTH;
  581.     gbC.gridy = 2;     gbC.gridx = 0; gbC.weightx = 0;
  582.     gbL.setConstraints(m_History, gbC);
  583.     mondo.add(m_History);
  584.     gbC = new GridBagConstraints();
  585.     gbC.fill = GridBagConstraints.BOTH;
  586.     gbC.gridy = 0;     gbC.gridx = 1;
  587.     gbC.gridheight = 3;
  588.     gbC.weightx = 100; gbC.weighty = 100;
  589.     gbL.setConstraints(p3, gbC);
  590.     mondo.add(p3);
  591.     setLayout(new BorderLayout());
  592.     add(p1, BorderLayout.NORTH);
  593.     add(mondo, BorderLayout.CENTER);
  594.   }
  595.   
  596.   /**
  597.    * Updates the enabled status of the input fields and labels.
  598.    */
  599.   protected void updateRadioLinks() {
  600.     
  601.     m_SetTestBut.setEnabled(m_TestSplitBut.isSelected());
  602.     if ((m_SetTestFrame != null) && (!m_TestSplitBut.isSelected())) {
  603.       m_SetTestFrame.setVisible(false);
  604.     }
  605.     m_CVText.setEnabled(m_CVBut.isSelected());
  606.     m_CVLab.setEnabled(m_CVBut.isSelected());
  607.     m_PercentText.setEnabled(m_PercentBut.isSelected());
  608.     m_PercentLab.setEnabled(m_PercentBut.isSelected());
  609.   }
  610.   /**
  611.    * Sets the preprocess panel through which user selected
  612.    * filters can be applied to any supplied test data
  613.    * @param p the preprocess panel to use
  614.    */
  615.   public void setPreprocess(PreprocessPanel p) {
  616.     m_Preprocess = p;
  617.   }
  618.   /**
  619.    * Sets the Logger to receive informational messages
  620.    *
  621.    * @param newLog the Logger that will now get info messages
  622.    */
  623.   public void setLog(Logger newLog) {
  624.     m_Log = newLog;
  625.   }
  626.   
  627.   /**
  628.    * Set the default attributes to use on the x and y axis
  629.    * of a new visualization object.
  630.    * @param x the index of the attribute to use on the x axis
  631.    * @param y the index of the attribute to use on the y axis
  632.    */
  633.   public void setXY_VisualizeIndexes(int x, int y) {
  634.     m_visXIndex = x;
  635.     m_visYIndex = y;
  636.   }
  637.   /**
  638.    * Tells the panel to use a new set of instances.
  639.    *
  640.    * @param inst a set of Instances
  641.    */
  642.   public void setInstances(Instances inst) {
  643.     m_Instances = inst;
  644.     setXY_VisualizeIndexes(0,0); // reset the default x and y indexes
  645.     String [] attribNames = new String [m_Instances.numAttributes()];
  646.     for (int i = 0; i < attribNames.length; i++) {
  647.       String type = "";
  648.       switch (m_Instances.attribute(i).type()) {
  649.       case Attribute.NOMINAL:
  650. type = "(Nom) ";
  651. break;
  652.       case Attribute.NUMERIC:
  653. type = "(Num) ";
  654. break;
  655.       case Attribute.STRING:
  656. type = "(Str) ";
  657. break;
  658.       default:
  659. type = "(???) ";
  660.       }
  661.       attribNames[i] = type + m_Instances.attribute(i).name();
  662.     }
  663.     m_ClassCombo.setModel(new DefaultComboBoxModel(attribNames));
  664.     if (attribNames.length > 0) {
  665.       m_ClassCombo.setSelectedIndex(attribNames.length - 1);
  666.       m_ClassCombo.setEnabled(true);
  667.       m_StartBut.setEnabled(m_RunThread == null);
  668.       m_StopBut.setEnabled(m_RunThread != null);
  669.     } else {
  670.       m_StartBut.setEnabled(false);
  671.       m_StopBut.setEnabled(false);
  672.     }
  673.   }
  674.   /**
  675.    * Attempts to filter the user specified test set through
  676.    * the most currently used set of filters (if any) from the
  677.    * pre-process panel.
  678.    */
  679.   protected void filterUserTestInstances() {
  680.     if (m_Preprocess != null && m_TestInstances != null) {
  681.       m_TestInstancesCopy = new Instances(m_TestInstances);
  682.       SerializedObject sf = m_Preprocess.getMostRecentFilters();
  683.       if (sf != null) {
  684. Filter [] filters = null;
  685. try {
  686.   filters = (Filter [])sf.getObject();
  687. } catch (Exception ex) {
  688.   JOptionPane.showMessageDialog(this,
  689. "Could not deserialize filters",
  690. null,
  691. JOptionPane.ERROR_MESSAGE);
  692. }
  693. if (filters.length != 0) {
  694.   try {
  695.     m_Log.statusMessage("Applying preprocess filters to test data...");
  696.     m_TestInstancesCopy = new Instances(m_TestInstances);
  697.     for (int i = 0; i < filters.length; i++) {
  698.       m_Log.statusMessage("Passing through filter " + (i + 1) + ": "
  699.   + filters[i].getClass().getName());
  700.       filters[i].setInputFormat(m_TestInstancesCopy);
  701.       m_TestInstancesCopy = Filter.useFilter(m_TestInstancesCopy, 
  702.      filters[i]);
  703.     }
  704.     m_Log.statusMessage("OK");
  705.   } catch (Exception ex) {
  706.     m_Log.statusMessage("See error log");
  707.     m_Log.logMessage("Problem applying filters to test data "
  708.      +"(Classifier Panel)");
  709.   }
  710.   if (m_Summary != null && m_TestInstancesCopy != null) {
  711.     m_Summary.setInstances(m_TestInstancesCopy);
  712.   }
  713. }
  714.       }
  715.     }
  716.   }
  717.   /**
  718.    * Sets the user test set. Information about the current test set
  719.    * is displayed in an InstanceSummaryPanel and the user is given the
  720.    * ability to load another set from a file or url.
  721.    *
  722.    */
  723.   protected void setTestSet() {
  724.     if (m_SetTestFrame == null) {
  725.       final SetInstancesPanel sp = new SetInstancesPanel();
  726.       m_Summary = sp.getSummary();
  727.       if (m_TestInstancesCopy != null) {
  728. sp.setInstances(m_TestInstancesCopy);
  729.       }
  730.       sp.addPropertyChangeListener(new PropertyChangeListener() {
  731. public void propertyChange(PropertyChangeEvent e) {
  732.   m_TestInstances = sp.getInstances();
  733.   filterUserTestInstances();
  734. }
  735.       });
  736.       // Add propertychangelistener to update m_TestInstances whenever
  737.       // it changes in the settestframe
  738.       m_SetTestFrame = new JFrame("Test Instances");
  739.       m_SetTestFrame.getContentPane().setLayout(new BorderLayout());
  740.       m_SetTestFrame.getContentPane().add(sp, BorderLayout.CENTER);
  741.       m_SetTestFrame.pack();
  742.     }
  743.     m_SetTestFrame.setVisible(true);
  744.   }
  745.   /**
  746.    * Process a classifier's prediction for an instance and update a
  747.    * set of plotting instances and additional plotting info. plotInfo
  748.    * for nominal class datasets holds shape types (actual data points have
  749.    * automatic shape type assignment; classifer error data points have
  750.    * box shape type). For numeric class datasets, the actual data points
  751.    * are stored in plotInstances and plotInfo stores the error (which is
  752.    * later converted to shape size values)
  753.    * @param toPredict the actual data point
  754.    * @param classifier the classifier
  755.    * @param eval the evaluation object to use for evaluating the classifer on
  756.    * the instance to predict
  757.    * @param predictions a fastvector to add the prediction to
  758.    * @param plotInstances a set of plottable instances
  759.    * @param plotShape additional plotting information (shape)
  760.    * @param plotSize additional plotting information (size)
  761.    */
  762.   private void processClassifierPrediction(Instance toPredict,
  763.    Classifier classifier,
  764.    Evaluation eval,
  765.    FastVector predictions,
  766.    Instances plotInstances,
  767.    FastVector plotShape,
  768.    FastVector plotSize) {
  769.     try {
  770.       double pred;
  771.       // classifier is a distribution classifer and class is nominal
  772.       if (predictions != null) {
  773. Instance classMissing = (Instance)toPredict.copy();
  774. classMissing.setDataset(toPredict.dataset());
  775. classMissing.setClassMissing();
  776. DistributionClassifier dc = 
  777.   (DistributionClassifier)classifier;
  778. double [] dist = 
  779.   dc.distributionForInstance(classMissing);
  780. pred = eval.evaluateModelOnce(dist, toPredict);
  781. int actual = (int)toPredict.classValue();
  782. predictions.addElement(new 
  783.   NominalPrediction(actual, dist, toPredict.weight()));
  784.       } else {
  785. pred = eval.evaluateModelOnce(classifier, 
  786.       toPredict);
  787.       }
  788.       double [] values = new double[plotInstances.numAttributes()];
  789.       for (int i = 0; i < plotInstances.numAttributes(); i++) {
  790. if (i < toPredict.classIndex()) {
  791.   values[i] = toPredict.value(i);
  792. } else if (i == toPredict.classIndex()) {
  793.   values[i] = pred;
  794.   values[i+1] = toPredict.value(i);
  795.   /* // if the class value of the instances to predict is missing then
  796.   // set it to the predicted value
  797.   if (toPredict.isMissing(i)) {
  798.     values[i+1] = pred;
  799.     } */
  800.   i++;
  801. } else {
  802.   values[i] = toPredict.value(i-1);
  803. }
  804.       }
  805.       plotInstances.add(new Instance(1.0, values));
  806.       if (toPredict.classAttribute().isNominal()) {
  807. if (toPredict.isMissing(toPredict.classIndex())) {
  808.   plotShape.addElement(new Integer(Plot2D.MISSING_SHAPE));
  809. } else if (pred != toPredict.classValue()) {
  810.   // set to default error point shape
  811.   plotShape.addElement(new Integer(Plot2D.ERROR_SHAPE));
  812. } else {
  813.   // otherwise set to constant (automatically assigned) point shape
  814.   plotShape.addElement(new Integer(Plot2D.CONST_AUTOMATIC_SHAPE));
  815. }
  816. plotSize.addElement(new Integer(Plot2D.DEFAULT_SHAPE_SIZE));
  817.       } else {
  818. // store the error (to be converted to a point size later)
  819. Double errd = null;
  820. if (!toPredict.isMissing(toPredict.classIndex())) {
  821.   errd = new Double(pred - toPredict.classValue());
  822.   plotShape.addElement(new Integer(Plot2D.CONST_AUTOMATIC_SHAPE));
  823. } else {
  824.   // missing shape if actual class not present
  825.   plotShape.addElement(new Integer(Plot2D.MISSING_SHAPE));
  826. }
  827. plotSize.addElement(errd);
  828.       }
  829.     } catch (Exception ex) {
  830.       ex.printStackTrace();
  831.     }
  832.   }
  833.   /**
  834.    * Post processes numeric class errors into shape sizes for plotting
  835.    * in the visualize panel
  836.    * @param plotSize a FastVector of numeric class errors
  837.    */
  838.   private void postProcessPlotInfo(FastVector plotSize) {
  839.     int maxpSize = 20;
  840.     double maxErr = Double.NEGATIVE_INFINITY;
  841.     double minErr = Double.POSITIVE_INFINITY;
  842.     double err;
  843.     
  844.     for (int i = 0; i < plotSize.size(); i++) {
  845.       Double errd = (Double)plotSize.elementAt(i);
  846.       if (errd != null) {
  847. err = Math.abs(errd.doubleValue());
  848.         if (err < minErr) {
  849.   minErr = err;
  850. }
  851. if (err > maxErr) {
  852.   maxErr = err;
  853. }
  854.       }
  855.     }
  856.     
  857.     for (int i = 0; i < plotSize.size(); i++) {
  858.       Double errd = (Double)plotSize.elementAt(i);
  859.       if (errd != null) {
  860. err = Math.abs(errd.doubleValue());
  861. if (maxErr - minErr > 0) {
  862.   double temp = (((err - minErr) / (maxErr - minErr)) 
  863.  * maxpSize);
  864.   plotSize.setElementAt(new Integer((int)temp), i);
  865. } else {
  866.   plotSize.setElementAt(new Integer(1), i);
  867. }
  868.       } else {
  869. plotSize.setElementAt(new Integer(1), i);
  870.       }
  871.     }
  872.   }
  873.   /**
  874.    * Sets up the structure for the visualizable instances. This dataset
  875.    * contains the original attributes plus the classifier's predictions
  876.    * for the class as an attribute called "predicted+WhateverTheClassIsCalled".
  877.    * @param trainInstancs the instances that the classifier is trained on
  878.    * @return a new set of instances containing one more attribute (predicted
  879.    * class) than the trainInstances
  880.    */
  881.   private Instances setUpVisualizableInstances(Instances trainInstances) {
  882.     FastVector hv = new FastVector();
  883.     Attribute predictedClass;
  884.     Attribute classAt = trainInstances.attribute(trainInstances.classIndex());
  885.     if (classAt.isNominal()) {
  886.       FastVector attVals = new FastVector();
  887.       for (int i = 0; i < classAt.numValues(); i++) {
  888. attVals.addElement(classAt.value(i));
  889.       }
  890.       predictedClass = new Attribute("predicted"+classAt.name(), attVals);
  891.     } else {
  892.       predictedClass = new Attribute("predicted"+classAt.name());
  893.     }
  894.     for (int i = 0; i < trainInstances.numAttributes(); i++) {
  895.       if (i == trainInstances.classIndex()) {
  896. hv.addElement(predictedClass);
  897.       }
  898.       hv.addElement(trainInstances.attribute(i).copy());
  899.     }
  900.     return new Instances(trainInstances.relationName()+"_predicted", hv, 
  901.  trainInstances.numInstances());
  902.   }
  903.   /**
  904.    * Starts running the currently configured classifier with the current
  905.    * settings. This is run in a separate thread, and will only start if
  906.    * there is no classifier already running. The classifier output is sent
  907.    * to the results history panel.
  908.    */
  909.   protected void startClassifier() {
  910.     if (m_RunThread == null) {
  911.       synchronized (this) {
  912. m_StartBut.setEnabled(false);
  913. m_StopBut.setEnabled(true);
  914.       }
  915.       m_RunThread = new Thread() {
  916. public void run() {
  917.   // Copy the current state of things
  918.   m_Log.statusMessage("Setting up...");
  919.   CostMatrix costMatrix = null;
  920.   Instances inst = new Instances(m_Instances);
  921.   Instances userTest = null;
  922.   // additional vis info (either shape type or point size)
  923.   FastVector plotShape = new FastVector();
  924.   FastVector plotSize = new FastVector();
  925.   Instances predInstances = null;
  926.   // will hold the prediction objects if the class is nominal
  927.   FastVector predictions = null;
  928.  
  929.   // for timing
  930.   long trainTimeStart = 0, trainTimeElapsed = 0;
  931.   if (m_TestInstances != null) {
  932.     userTest = new Instances(m_TestInstancesCopy);
  933.   }
  934.   if (m_EvalWRTCostsBut.isSelected()) {
  935.     costMatrix = new CostMatrix((CostMatrix) m_CostMatrixEditor
  936. .getValue());
  937.   }
  938.   boolean outputModel = m_OutputModelBut.isSelected();
  939.   boolean outputConfusion = m_OutputConfusionBut.isSelected();
  940.   boolean outputPerClass = m_OutputPerClassBut.isSelected();
  941.   boolean outputSummary = true;
  942.           boolean outputEntropy = m_OutputEntropyBut.isSelected();
  943.   boolean saveVis = m_StorePredictionsBut.isSelected();
  944.   String grph = null;
  945.   int testMode = 0;
  946.   int numFolds = 10, percent = 66;
  947.   int classIndex = m_ClassCombo.getSelectedIndex();
  948.   Classifier classifier = (Classifier) m_ClassifierEditor.getValue();
  949.   StringBuffer outBuff = new StringBuffer();
  950.   String name = (new SimpleDateFormat("HH:mm:ss - "))
  951.   .format(new Date());
  952.   String cname = classifier.getClass().getName();
  953.   if (cname.startsWith("weka.classifiers.")) {
  954.     name += cname.substring("weka.classifiers.".length());
  955.   } else {
  956.     name += cname;
  957.   }
  958.   try {
  959.     if (m_CVBut.isSelected()) {
  960.       testMode = 1;
  961.       numFolds = Integer.parseInt(m_CVText.getText());
  962.       if (numFolds <= 1) {
  963. throw new Exception("Number of folds must be greater than 1");
  964.       }
  965.     } else if (m_PercentBut.isSelected()) {
  966.       testMode = 2;
  967.       percent = Integer.parseInt(m_PercentText.getText());
  968.       if ((percent <= 0) || (percent >= 100)) {
  969. throw new Exception("Percentage must be between 0 and 100");
  970.       }
  971.     } else if (m_TrainBut.isSelected()) {
  972.       testMode = 3;
  973.     } else if (m_TestSplitBut.isSelected()) {
  974.       testMode = 4;
  975.       // Check the test instance compatibility
  976.       if (userTest == null) {
  977. throw new Exception("No user test set has been opened");
  978.       }
  979.       if (!inst.equalHeaders(userTest)) {
  980. throw new Exception("Train and test set are not compatible");
  981.       }
  982.       userTest.setClassIndex(classIndex);
  983.     } else {
  984.       throw new Exception("Unknown test mode");
  985.     }
  986.     inst.setClassIndex(classIndex);
  987.     // set up the structure of the plottable instances for 
  988.     // visualization
  989.     predInstances = setUpVisualizableInstances(inst);
  990.     predInstances.setClassIndex(inst.classIndex()+1);
  991.     
  992.     if (inst.classAttribute().isNominal() && 
  993. classifier instanceof DistributionClassifier) {
  994.       predictions = new FastVector();
  995.     }
  996.     // Output some header information
  997.     m_Log.logMessage("Started " + cname);
  998.     if (m_Log instanceof TaskLogger) {
  999.       ((TaskLogger)m_Log).taskStarted();
  1000.     }
  1001.     outBuff.append("=== Run information ===nn");
  1002.     outBuff.append("Scheme:       " + cname);
  1003.     if (classifier instanceof OptionHandler) {
  1004.       String [] o = ((OptionHandler) classifier).getOptions();
  1005.       outBuff.append(" " + Utils.joinOptions(o));
  1006.     }
  1007.     outBuff.append("n");
  1008.     outBuff.append("Relation:     " + inst.relationName() + 'n');
  1009.     outBuff.append("Instances:    " + inst.numInstances() + 'n');
  1010.     outBuff.append("Attributes:   " + inst.numAttributes() + 'n');
  1011.     if (inst.numAttributes() < 100) {
  1012.       for (int i = 0; i < inst.numAttributes(); i++) {
  1013. outBuff.append("              " + inst.attribute(i).name()
  1014.        + 'n');
  1015.       }
  1016.     } else {
  1017.       outBuff.append("              [list of attributes omitted]n");
  1018.     }
  1019.     outBuff.append("Test mode:    ");
  1020.     switch (testMode) {
  1021.       case 3: // Test on training
  1022.       outBuff.append("evaluate on training datan");
  1023.       break;
  1024.       case 1: // CV mode
  1025.       outBuff.append("" + numFolds + "-fold cross-validationn");
  1026.       break;
  1027.       case 2: // Percent split
  1028.       outBuff.append("split " + percent
  1029.        + "% train, remainder testn");
  1030.       break;
  1031.       case 4: // Test on user split
  1032.       outBuff.append("user supplied test set: "
  1033.      + userTest.numInstances() + " instancesn");
  1034.       break;
  1035.     }
  1036.             if (costMatrix != null) {
  1037.                outBuff.append("Evaluation cost matrix:n")
  1038.                .append(costMatrix.toString()).append("n");
  1039.             }
  1040.     outBuff.append("n");
  1041.     m_History.addResult(name, outBuff);
  1042.     m_History.setSingle(name);
  1043.     
  1044.     // Build the model and output it.
  1045.     if (outputModel || (testMode == 3) || (testMode == 4)) {
  1046.       m_Log.statusMessage("Building model on training data...");
  1047.       trainTimeStart = System.currentTimeMillis();
  1048.       classifier.buildClassifier(inst);
  1049.       trainTimeElapsed = System.currentTimeMillis() - trainTimeStart;
  1050.     }
  1051.     if (outputModel) {
  1052.       outBuff.append("=== Classifier model (full training set) ===nn");
  1053.       outBuff.append(classifier.toString() + "n");
  1054.       outBuff.append("nTime taken to build model: " +
  1055.      Utils.doubleToString(trainTimeElapsed / 1000.0,2)
  1056.      + " secondsnn");
  1057.       m_History.updateResult(name);
  1058.       if (classifier instanceof Drawable) {
  1059. grph = null;
  1060. try {
  1061.   grph = ((Drawable)classifier).graph();
  1062. } catch (Exception ex) {
  1063. }
  1064.       }
  1065.     }
  1066.     
  1067.     Evaluation eval = null;
  1068.     switch (testMode) {
  1069.       case 3: // Test on training
  1070.       m_Log.statusMessage("Evaluating on training data...");
  1071.       eval = new Evaluation(inst, costMatrix);
  1072.       for (int jj=0;jj<inst.numInstances();jj++) {
  1073. processClassifierPrediction(inst.instance(jj), classifier,
  1074.     eval, predictions,
  1075.     predInstances, plotShape, 
  1076.     plotSize);
  1077. if ((jj % 100) == 0) {
  1078.   m_Log.statusMessage("Evaluating on training data. Processed "
  1079.       +jj+" instances...");
  1080. }
  1081.       }
  1082.       outBuff.append("=== Evaluation on training set ===n");
  1083.       break;
  1084.       case 1: // CV mode
  1085.       m_Log.statusMessage("Randomizing instances...");
  1086.       int rnd = 1;
  1087.       try {
  1088. rnd = Integer.parseInt(m_RandomSeedText.getText().trim());
  1089. System.err.println("Using random seed "+rnd);
  1090.       } catch (Exception ex) {
  1091. m_Log.logMessage("Trouble parsing random seed value");
  1092. rnd = 1;
  1093.       }
  1094.       inst.randomize(new Random(rnd));
  1095.       if (inst.attribute(classIndex).isNominal()) {
  1096. m_Log.statusMessage("Stratifying instances...");
  1097. inst.stratify(numFolds);
  1098.       }
  1099.       eval = new Evaluation(inst, costMatrix);
  1100.       // Make some splits and do a CV
  1101.       for (int fold = 0; fold < numFolds; fold++) {
  1102. m_Log.statusMessage("Creating splits for fold "
  1103.     + (fold + 1) + "...");
  1104. Instances train = inst.trainCV(numFolds, fold);
  1105. Instances test = inst.testCV(numFolds, fold);
  1106. m_Log.statusMessage("Building model for fold "
  1107.     + (fold + 1) + "...");
  1108. classifier.buildClassifier(train);
  1109. m_Log.statusMessage("Evaluating model for fold "
  1110.     + (fold + 1) + "...");
  1111. for (int jj=0;jj<test.numInstances();jj++) {
  1112.   processClassifierPrediction(test.instance(jj), classifier,
  1113.       eval, predictions,
  1114.       predInstances, plotShape,
  1115.       plotSize);
  1116. }
  1117.       }
  1118.       if (inst.attribute(classIndex).isNominal()) {
  1119. outBuff.append("=== Stratified cross-validation ===n");
  1120.       } else {
  1121. outBuff.append("=== Cross-validation ===n");
  1122.       }
  1123.       break;
  1124.       case 2: // Percent split
  1125.       m_Log.statusMessage("Randomizing instances...");
  1126.       try {
  1127. rnd = Integer.parseInt(m_RandomSeedText.getText().trim());
  1128.       } catch (Exception ex) {
  1129. m_Log.logMessage("Trouble parsing random seed value");
  1130. rnd = 1;
  1131.       }
  1132.       inst.randomize(new Random(rnd));
  1133.       int trainSize = inst.numInstances() * percent / 100;
  1134.       int testSize = inst.numInstances() - trainSize;
  1135.       Instances train = new Instances(inst, 0, trainSize);
  1136.       Instances test = new Instances(inst, trainSize, testSize);
  1137.       m_Log.statusMessage("Building model on training split...");
  1138.       classifier.buildClassifier(train);
  1139.       eval = new Evaluation(train, costMatrix);
  1140.       m_Log.statusMessage("Evaluating on test split...");
  1141.      
  1142.       for (int jj=0;jj<test.numInstances();jj++) {
  1143. processClassifierPrediction(test.instance(jj), classifier,
  1144.     eval, predictions,
  1145.     predInstances, plotShape,
  1146.     plotSize);
  1147. if ((jj % 100) == 0) {
  1148.   m_Log.statusMessage("Evaluating on test split. Processed "
  1149.       +jj+" instances...");
  1150. }
  1151.       }
  1152.       outBuff.append("=== Evaluation on test split ===n");
  1153.       break;
  1154.       case 4: // Test on user split
  1155.       m_Log.statusMessage("Evaluating on test data...");
  1156.       eval = new Evaluation(inst, costMatrix);
  1157.       
  1158.       for (int jj=0;jj<userTest.numInstances();jj++) {
  1159. processClassifierPrediction(userTest.instance(jj), classifier,
  1160.     eval, predictions,
  1161.     predInstances, plotShape,
  1162.     plotSize);
  1163. if ((jj % 100) == 0) {
  1164.   m_Log.statusMessage("Evaluating on test data. Processed "
  1165.       +jj+" instances...");
  1166. }
  1167.       }
  1168.       outBuff.append("=== Evaluation on test set ===n");
  1169.       break;
  1170.       default:
  1171.       throw new Exception("Test mode not implemented");
  1172.     }
  1173.     
  1174.     if (outputSummary) {
  1175.       outBuff.append(eval.toSummaryString(outputEntropy) + "n");
  1176.     }
  1177.     if (inst.attribute(classIndex).isNominal()) {
  1178.       if (outputPerClass) {
  1179. outBuff.append(eval.toClassDetailsString() + "n");
  1180.       }
  1181.       if (outputConfusion) {
  1182. outBuff.append(eval.toMatrixString() + "n");
  1183.       }
  1184.     }
  1185.     m_History.updateResult(name);
  1186.     m_Log.logMessage("Finished " + cname);
  1187.     m_Log.statusMessage("OK");
  1188.   } catch (Exception ex) {
  1189.     ex.printStackTrace();
  1190.     m_Log.logMessage(ex.getMessage());
  1191.     m_Log.statusMessage("See error log");
  1192.   } finally {
  1193.     try {
  1194.       if (predInstances != null && predInstances.numInstances() > 0) {
  1195. if (predInstances.attribute(predInstances.classIndex())
  1196.     .isNumeric()) {
  1197.   postProcessPlotInfo(plotSize);
  1198. }
  1199. m_CurrentVis = new VisualizePanel();
  1200. m_CurrentVis.setName(name+" ("+inst.relationName()+")");
  1201. m_CurrentVis.setLog(m_Log);
  1202. PlotData2D tempd = new PlotData2D(predInstances);
  1203. tempd.setShapeSize(plotSize);
  1204. tempd.setShapeType(plotShape);
  1205. tempd.setPlotName(name+" ("+inst.relationName()+")");
  1206. tempd.addInstanceNumberAttribute();
  1207. m_CurrentVis.addPlot(tempd);
  1208. m_CurrentVis.setColourIndex(predInstances.classIndex()+1);
  1209. m_CurrentVis.setXIndex(m_visXIndex); 
  1210. m_CurrentVis.setYIndex(m_visYIndex);
  1211. m_CurrentVis.addActionListener(new ActionListener() {
  1212.   public void actionPerformed(ActionEvent e) {
  1213.     if (m_CurrentVis.getInstances().
  1214. relationName().
  1215. compareTo(m_Instances.relationName()) == 0) {
  1216.       setXY_VisualizeIndexes(m_CurrentVis.getXIndex(), 
  1217.      m_CurrentVis.getYIndex());
  1218.     }
  1219.   }
  1220.   });
  1221.     
  1222. if (saveVis) {
  1223.   FastVector vv = new FastVector();
  1224.   if (outputModel) {
  1225.     vv.addElement(classifier);
  1226.     Instances trainHeader = new Instances(m_Instances, 0);
  1227.     trainHeader.setClassIndex(classIndex);
  1228.     vv.addElement(trainHeader);
  1229.   }
  1230.   vv.addElement(m_CurrentVis);
  1231.   if (grph != null) {
  1232.     vv.addElement(grph);
  1233.   }
  1234.   if (predictions != null) {
  1235.     vv.addElement(predictions);
  1236.     vv.addElement(inst.classAttribute());
  1237.   }
  1238.   m_History.addObject(name, vv);
  1239. } else if (outputModel) {
  1240.   FastVector vv = new FastVector();
  1241.   vv.addElement(classifier);
  1242.   Instances trainHeader = new Instances(m_Instances, 0);
  1243.   trainHeader.setClassIndex(classIndex);
  1244.   vv.addElement(trainHeader);
  1245.   m_History.addObject(name, vv);
  1246. }
  1247.       }
  1248.     } catch (Exception ex) {
  1249.       ex.printStackTrace();
  1250.     }
  1251.     
  1252.     if (isInterrupted()) {
  1253.       m_Log.logMessage("Interrupted " + cname);
  1254.       m_Log.statusMessage("See error log");
  1255.     }
  1256.     synchronized (this) {
  1257.       m_StartBut.setEnabled(true);
  1258.       m_StopBut.setEnabled(false);
  1259.       m_RunThread = null;
  1260.     }
  1261.     if (m_Log instanceof TaskLogger) {
  1262.               ((TaskLogger)m_Log).taskFinished();
  1263.             }
  1264.           }
  1265. }
  1266.       };
  1267.       m_RunThread.setPriority(Thread.MIN_PRIORITY);
  1268.       m_RunThread.start();
  1269.     }
  1270.   }
  1271.   /**
  1272.    * Handles constructing a popup menu with visualization options.
  1273.    * @param name the name of the result history list entry clicked on by
  1274.    * the user
  1275.    * @param x the x coordinate for popping up the menu
  1276.    * @param y the y coordinate for popping up the menu
  1277.    */
  1278.   protected void visualize(String name, int x, int y) {
  1279.     final String selectedName = name;
  1280.     JPopupMenu resultListMenu = new JPopupMenu();
  1281.     
  1282.     JMenuItem visMainBuffer = new JMenuItem("View in main window");
  1283.     if (selectedName != null) {
  1284.       visMainBuffer.addActionListener(new ActionListener() {
  1285.   public void actionPerformed(ActionEvent e) {
  1286.     m_History.setSingle(selectedName);
  1287.   }
  1288. });
  1289.     } else {
  1290.       visMainBuffer.setEnabled(false);
  1291.     }
  1292.     resultListMenu.add(visMainBuffer);
  1293.     
  1294.     JMenuItem visSepBuffer = new JMenuItem("View in separate window");
  1295.     if (selectedName != null) {
  1296.       visSepBuffer.addActionListener(new ActionListener() {
  1297. public void actionPerformed(ActionEvent e) {
  1298.   m_History.openFrame(selectedName);
  1299. }
  1300.       });
  1301.     } else {
  1302.       visSepBuffer.setEnabled(false);
  1303.     }
  1304.     resultListMenu.add(visSepBuffer);
  1305.     
  1306.     JMenuItem saveOutput = new JMenuItem("Save result buffer");
  1307.     if (selectedName != null) {
  1308.       saveOutput.addActionListener(new ActionListener() {
  1309.   public void actionPerformed(ActionEvent e) {
  1310.     saveBuffer(selectedName);
  1311.   }
  1312. });
  1313.     } else {
  1314.       saveOutput.setEnabled(false);
  1315.     }
  1316.     resultListMenu.add(saveOutput);
  1317.     
  1318.     resultListMenu.addSeparator();
  1319.     
  1320.     JMenuItem loadModel = new JMenuItem("Load model");
  1321.     loadModel.addActionListener(new ActionListener() {
  1322. public void actionPerformed(ActionEvent e) {
  1323.   loadClassifier();
  1324. }
  1325.       });
  1326.     resultListMenu.add(loadModel);
  1327.     FastVector o = null;
  1328.     if (selectedName != null) {
  1329.       o = (FastVector)m_History.getNamedObject(selectedName);
  1330.     }
  1331.     VisualizePanel temp_vp = null;
  1332.     String temp_grph = null;
  1333.     FastVector temp_preds = null;
  1334.     Attribute temp_classAtt = null;
  1335.     Classifier temp_classifier = null;
  1336.     Instances temp_trainHeader = null;
  1337.       
  1338.     if (o != null) { 
  1339.       for (int i = 0; i < o.size(); i++) {
  1340. Object temp = o.elementAt(i);
  1341. if (temp instanceof Classifier) {
  1342.   temp_classifier = (Classifier)temp;
  1343. } else if (temp instanceof Instances) { // training header
  1344.   temp_trainHeader = (Instances)temp;
  1345. } else if (temp instanceof VisualizePanel) { // normal errors
  1346.   temp_vp = (VisualizePanel)temp;
  1347. } else if (temp instanceof String) { // graphable output
  1348.   temp_grph = (String)temp;
  1349. } else if (temp instanceof FastVector) { // predictions
  1350.   temp_preds = (FastVector)temp;
  1351. } else if (temp instanceof Attribute) { // class attribute
  1352.   temp_classAtt = (Attribute)temp;
  1353. }
  1354.       }
  1355.     }
  1356.     final VisualizePanel vp = temp_vp;
  1357.     final String grph = temp_grph;
  1358.     final FastVector preds = temp_preds;
  1359.     final Attribute classAtt = temp_classAtt;
  1360.     final Classifier classifier = temp_classifier;
  1361.     final Instances trainHeader = temp_trainHeader;
  1362.     
  1363.     JMenuItem saveModel = new JMenuItem("Save model");
  1364.     if (classifier != null) {
  1365.       saveModel.addActionListener(new ActionListener() {
  1366.   public void actionPerformed(ActionEvent e) {
  1367.     saveClassifier(selectedName, classifier, trainHeader);
  1368.   }
  1369. });
  1370.     } else {
  1371.       saveModel.setEnabled(false);
  1372.     }
  1373.     resultListMenu.add(saveModel);
  1374.     JMenuItem reEvaluate =
  1375.       new JMenuItem("Re-evaluate model on current test set");
  1376.     if (classifier != null && m_TestInstances != null) {
  1377.       reEvaluate.addActionListener(new ActionListener() {
  1378.   public void actionPerformed(ActionEvent e) {
  1379.     reevaluateModel(selectedName, classifier, trainHeader);
  1380.   }
  1381. });
  1382.     } else {
  1383.       reEvaluate.setEnabled(false);
  1384.     }
  1385.     resultListMenu.add(reEvaluate);
  1386.     
  1387.     resultListMenu.addSeparator();
  1388.     
  1389.     JMenuItem visErrors = new JMenuItem("Visualize classifer errors");
  1390.     if (vp != null) {
  1391.       visErrors.addActionListener(new ActionListener() {
  1392.   public void actionPerformed(ActionEvent e) {
  1393.     visualizeClassifierErrors(vp);
  1394.   }
  1395. });
  1396.     } else {
  1397.       visErrors.setEnabled(false);
  1398.     }
  1399.     resultListMenu.add(visErrors);
  1400.     JMenuItem visTree = new JMenuItem("Visualize tree");
  1401.     if (grph != null) {
  1402.       visTree.addActionListener(new ActionListener() {
  1403.   public void actionPerformed(ActionEvent e) {
  1404.     String title;
  1405.     if (vp != null) title = vp.getName();
  1406.     else title = selectedName;
  1407.     visualizeTree(grph, title);
  1408.   }
  1409. });
  1410.     } else {
  1411.       visTree.setEnabled(false);
  1412.     }
  1413.     resultListMenu.add(visTree);
  1414.     JMenuItem visMargin = new JMenuItem("Visualize margin curve");
  1415.     if (preds != null) {
  1416.       visMargin.addActionListener(new ActionListener() {
  1417.   public void actionPerformed(ActionEvent e) {
  1418.     try {
  1419.       MarginCurve tc = new MarginCurve();
  1420.       Instances result = tc.getCurve(preds);
  1421.       VisualizePanel vmc = new VisualizePanel();
  1422.       vmc.setName(result.relationName());
  1423.       vmc.setLog(m_Log);
  1424.       PlotData2D tempd = new PlotData2D(result);
  1425.       tempd.setPlotName(result.relationName());
  1426.       tempd.addInstanceNumberAttribute();
  1427.       vmc.addPlot(tempd);
  1428.       visualizeClassifierErrors(vmc);
  1429.     } catch (Exception ex) {
  1430.       ex.printStackTrace();
  1431.     }
  1432.   }
  1433. });
  1434.     } else {
  1435.       visMargin.setEnabled(false);
  1436.     }
  1437.     resultListMenu.add(visMargin);
  1438.     JMenu visThreshold = new JMenu("Visualize threshold curve");
  1439.     if (preds != null && classAtt != null) {
  1440.       for (int i = 0; i < classAtt.numValues(); i++) {
  1441. JMenuItem clv = new JMenuItem(classAtt.value(i));
  1442. final int classValue = i;
  1443. clv.addActionListener(new ActionListener() {
  1444.     public void actionPerformed(ActionEvent e) {
  1445.       try {
  1446. ThresholdCurve tc = new ThresholdCurve();
  1447. Instances result = tc.getCurve(preds, classValue);
  1448. VisualizePanel vmc = new VisualizePanel();
  1449. vmc.setLog(m_Log);
  1450. vmc.setName(result.relationName()+". Class value "+
  1451.     classAtt.value(classValue)+")");
  1452. PlotData2D tempd = new PlotData2D(result);
  1453. tempd.setPlotName(result.relationName());
  1454. tempd.addInstanceNumberAttribute();
  1455. vmc.addPlot(tempd);
  1456. visualizeClassifierErrors(vmc);
  1457.       } catch (Exception ex) {
  1458. ex.printStackTrace();
  1459.       }
  1460.       }
  1461.   });
  1462.   visThreshold.add(clv);
  1463.       }
  1464.     } else {
  1465.       visThreshold.setEnabled(false);
  1466.     }
  1467.     resultListMenu.add(visThreshold);
  1468.     JMenu visCost = new JMenu("Visualize cost curve");
  1469.     if (preds != null && classAtt != null) {
  1470.       for (int i = 0; i < classAtt.numValues(); i++) {
  1471. JMenuItem clv = new JMenuItem(classAtt.value(i));
  1472. final int classValue = i;
  1473. clv.addActionListener(new ActionListener() {
  1474.     public void actionPerformed(ActionEvent e) {
  1475.       try {
  1476. CostCurve cc = new CostCurve();
  1477. Instances result = cc.getCurve(preds, classValue);
  1478. VisualizePanel vmc = new VisualizePanel();
  1479. vmc.setLog(m_Log);
  1480. vmc.setName(result.relationName()+". Class value "+
  1481.     classAtt.value(classValue)+")");
  1482. PlotData2D tempd = new PlotData2D(result);
  1483. tempd.m_displayAllPoints = true;
  1484. tempd.setPlotName(result.relationName());
  1485. boolean [] connectPoints = 
  1486.   new boolean [result.numInstances()];
  1487. for (int jj = 1; jj < connectPoints.length; jj+=2) {
  1488.   connectPoints[jj] = true;
  1489. }
  1490. tempd.setConnectPoints(connectPoints);
  1491. //   tempd.addInstanceNumberAttribute();
  1492. vmc.addPlot(tempd);
  1493. visualizeClassifierErrors(vmc);
  1494.       } catch (Exception ex) {
  1495. ex.printStackTrace();
  1496.       }
  1497.     }
  1498.   });
  1499. visCost.add(clv);
  1500.       }
  1501.     } else {
  1502.       visCost.setEnabled(false);
  1503.     }
  1504.     resultListMenu.add(visCost);
  1505.     resultListMenu.show(m_History.getList(), x, y);
  1506.   }
  1507.   /**
  1508.    * Pops up a TreeVisualizer for the classifier from the currently
  1509.    * selected item in the results list
  1510.    * @param dottyString the description of the tree in dotty format
  1511.    * @param treeName the title to assign to the display
  1512.    */
  1513.   protected void visualizeTree(String dottyString, String treeName) {
  1514.     final javax.swing.JFrame jf = 
  1515.       new javax.swing.JFrame("Weka Classifier Tree Visualizer: "+treeName);
  1516.     jf.setSize(500,400);
  1517.     jf.getContentPane().setLayout(new BorderLayout());
  1518.     TreeVisualizer tv = new TreeVisualizer(null,
  1519.    dottyString,
  1520.    new PlaceNode2());
  1521.     jf.getContentPane().add(tv, BorderLayout.CENTER);
  1522.     jf.addWindowListener(new java.awt.event.WindowAdapter() {
  1523. public void windowClosing(java.awt.event.WindowEvent e) {
  1524.   jf.dispose();
  1525. }
  1526.       });
  1527.     
  1528.     jf.setVisible(true);
  1529.     tv.fitToScreen();
  1530.   }
  1531.   /**
  1532.    * Pops up a VisualizePanel for visualizing the data and errors for 
  1533.    * the classifier from the currently selected item in the results list
  1534.    * @param sp the VisualizePanel to pop up.
  1535.    */
  1536.   protected void visualizeClassifierErrors(VisualizePanel sp) {
  1537.    
  1538.     if (sp != null) {
  1539.       String plotName = sp.getName(); 
  1540. final javax.swing.JFrame jf = 
  1541. new javax.swing.JFrame("Weka Classifier Visualize: "+plotName);
  1542. jf.setSize(500,400);
  1543. jf.getContentPane().setLayout(new BorderLayout());
  1544. jf.getContentPane().add(sp, BorderLayout.CENTER);
  1545. jf.addWindowListener(new java.awt.event.WindowAdapter() {
  1546.   public void windowClosing(java.awt.event.WindowEvent e) {
  1547.     jf.dispose();
  1548.   }
  1549. });
  1550.     jf.setVisible(true);
  1551.     }
  1552.   }
  1553.   /**
  1554.    * Save the currently selected classifier output to a file.
  1555.    * @param name the name of the buffer to save
  1556.    */
  1557.   protected void saveBuffer(String name) {
  1558.     StringBuffer sb = m_History.getNamedBuffer(name);
  1559.     if (sb != null) {
  1560.       if (m_SaveOut.save(sb)) {
  1561. m_Log.logMessage("Save successful.");
  1562.       }
  1563.     }
  1564.   }
  1565.   
  1566.   /**
  1567.    * Stops the currently running classifier (if any).
  1568.    */
  1569.   protected void stopClassifier() {
  1570.     if (m_RunThread != null) {
  1571.       m_RunThread.interrupt();
  1572.       
  1573.       // This is deprecated (and theoretically the interrupt should do).
  1574.       m_RunThread.stop();
  1575.     }
  1576.   }
  1577.   /**
  1578.    * Saves the currently selected classifier
  1579.    */
  1580.   protected void saveClassifier(String name, Classifier classifier,
  1581. Instances trainHeader) {
  1582.     File sFile = null;
  1583.     boolean saveOK = true;
  1584.  
  1585.     int returnVal = m_FileChooser.showSaveDialog(this);
  1586.     if (returnVal == JFileChooser.APPROVE_OPTION) {
  1587.       sFile = m_FileChooser.getSelectedFile();
  1588.       
  1589.       m_Log.statusMessage("Saving model to file...");
  1590.       
  1591.       try {
  1592. OutputStream os = new FileOutputStream(sFile);
  1593. if (sFile.getName().endsWith(".gz")) {
  1594.   os = new GZIPOutputStream(os);
  1595. }
  1596. ObjectOutputStream objectOutputStream = new ObjectOutputStream(os);
  1597. objectOutputStream.writeObject(classifier);
  1598. if (trainHeader != null) objectOutputStream.writeObject(trainHeader);
  1599. objectOutputStream.flush();
  1600. objectOutputStream.close();
  1601.       } catch (Exception e) {
  1602. JOptionPane.showMessageDialog(null, e, "Save Failed",
  1603.       JOptionPane.ERROR_MESSAGE);
  1604. saveOK = false;
  1605.       }
  1606.       if (saveOK)
  1607. m_Log.logMessage("Saved model (" + name
  1608.  + ") to file '" + sFile.getName() + "'");
  1609.       m_Log.statusMessage("OK");
  1610.     }
  1611.   }
  1612.   /**
  1613.    * Loads a classifier
  1614.    */
  1615.   protected void loadClassifier() {
  1616.     int returnVal = m_FileChooser.showOpenDialog(this);
  1617.     if (returnVal == JFileChooser.APPROVE_OPTION) {
  1618.       File selected = m_FileChooser.getSelectedFile();
  1619.       Classifier classifier = null;
  1620.       Instances trainHeader = null;
  1621.       m_Log.statusMessage("Loading model from file...");
  1622.       try {
  1623. InputStream is = new FileInputStream(selected);
  1624. if (selected.getName().endsWith(".gz")) {
  1625.   is = new GZIPInputStream(is);
  1626. }
  1627. ObjectInputStream objectInputStream = new ObjectInputStream(is);
  1628. classifier = (Classifier) objectInputStream.readObject();
  1629. try { // see if we can load the header
  1630.   trainHeader = (Instances) objectInputStream.readObject();
  1631. } catch (Exception e) {} // don't fuss if we can't
  1632. objectInputStream.close();
  1633.       } catch (Exception e) {
  1634. JOptionPane.showMessageDialog(null, e, "Load Failed",
  1635.       JOptionPane.ERROR_MESSAGE);
  1636.       }
  1637.       m_Log.statusMessage("OK");
  1638.       
  1639.       if (classifier != null) {
  1640. m_Log.logMessage("Loaded model from file '" + selected.getName()+ "'");
  1641. String name = (new SimpleDateFormat("HH:mm:ss - ")).format(new Date());
  1642. String cname = classifier.getClass().getName();
  1643. if (cname.startsWith("weka.classifiers."))
  1644.   cname = cname.substring("weka.classifiers.".length());
  1645. name += cname + " from file '" + selected.getName() + "'";
  1646. StringBuffer outBuff = new StringBuffer();
  1647. outBuff.append("=== Model information ===nn");
  1648. outBuff.append("Filename:     " + selected.getName() + "n");
  1649. outBuff.append("Scheme:       " + cname);
  1650. if (classifier instanceof OptionHandler) {
  1651.   String [] o = ((OptionHandler) classifier).getOptions();
  1652.   outBuff.append(" " + Utils.joinOptions(o));
  1653. }
  1654. outBuff.append("n");
  1655. if (trainHeader != null) {
  1656.   outBuff.append("Relation:     " + trainHeader.relationName() + 'n');
  1657.   outBuff.append("Attributes:   " + trainHeader.numAttributes() + 'n');
  1658.   if (trainHeader.numAttributes() < 100) {
  1659.     for (int i = 0; i < trainHeader.numAttributes(); i++) {
  1660.       outBuff.append("              " + trainHeader.attribute(i).name()
  1661.      + 'n');
  1662.     }
  1663.   } else {
  1664.     outBuff.append("              [list of attributes omitted]n");
  1665.   }
  1666. } else {
  1667.   outBuff.append("nTraining data unknownn");
  1668. outBuff.append("n=== Classifier model ===nn");
  1669. outBuff.append(classifier.toString() + "n");
  1670. m_History.addResult(name, outBuff);
  1671. m_History.setSingle(name);
  1672. FastVector vv = new FastVector();
  1673. vv.addElement(classifier);
  1674. if (trainHeader != null) vv.addElement(trainHeader);
  1675. // allow visualization of graphable classifiers
  1676. String grph = null;
  1677. if (classifier instanceof Drawable) {
  1678.   try {
  1679.     grph = ((Drawable)classifier).graph();
  1680.   } catch (Exception ex) {
  1681.   }
  1682. }
  1683. if (grph != null) vv.addElement(grph);
  1684. m_History.addObject(name, vv);
  1685.       }
  1686.     }
  1687.   }
  1688.   
  1689.   /**
  1690.    * Re-evaluates the named classifier with the current test set. Unpredictable
  1691.    * things will happen if the data set is not compatible with the classifier.
  1692.    *
  1693.    * @param name the name of the classifier entry
  1694.    * @param classifier the classifier to evaluate
  1695.    */
  1696.   protected void reevaluateModel(String name, Classifier classifier, Instances trainHeader) {
  1697.     StringBuffer outBuff = m_History.getNamedBuffer(name);
  1698.     Instances userTest = null;
  1699.     // additional vis info (either shape type or point size)
  1700.     FastVector plotShape = new FastVector();
  1701.     FastVector plotSize = new FastVector();
  1702.     Instances predInstances = null;
  1703.     
  1704.     // will hold the prediction objects if the class is nominal
  1705.     FastVector predictions = null;
  1706.     CostMatrix costMatrix = null;
  1707.     if (m_EvalWRTCostsBut.isSelected()) {
  1708.       costMatrix = new CostMatrix((CostMatrix) m_CostMatrixEditor
  1709.   .getValue());
  1710.     }    
  1711.     boolean outputConfusion = m_OutputConfusionBut.isSelected();
  1712.     boolean outputPerClass = m_OutputPerClassBut.isSelected();
  1713.     boolean outputSummary = true;
  1714.     boolean outputEntropy = m_OutputEntropyBut.isSelected();
  1715.     boolean saveVis = m_StorePredictionsBut.isSelected();
  1716.     String grph = null;    
  1717.     
  1718.     try {
  1719.       if (m_TestInstances != null) {
  1720. userTest = new Instances(m_TestInstancesCopy);
  1721.       }
  1722.       // Check the test instance compatibility
  1723.       if (userTest == null) {
  1724. throw new Exception("No user test set has been opened");
  1725.       }
  1726.       if (trainHeader != null) {
  1727. if (trainHeader.classIndex() > userTest.numAttributes()-1)
  1728.   throw new Exception("Train and test set are not compatible");
  1729. userTest.setClassIndex(trainHeader.classIndex());
  1730. if (!trainHeader.equalHeaders(userTest)) {
  1731.   throw new Exception("Train and test set are not compatible");
  1732. }
  1733.       } else {
  1734. userTest.setClassIndex(userTest.numAttributes()-1);
  1735.       }
  1736.       m_Log.statusMessage("Evaluating on test data...");
  1737.       m_Log.logMessage("Re-evaluating classifier (" + name + ") on test set");
  1738.       Evaluation eval = new Evaluation(userTest, costMatrix);
  1739.       
  1740.       // set up the structure of the plottable instances for 
  1741.       // visualization
  1742.       predInstances = setUpVisualizableInstances(userTest);
  1743.       predInstances.setClassIndex(userTest.classIndex()+1);
  1744.       
  1745.       if (userTest.classAttribute().isNominal() && 
  1746.   classifier instanceof DistributionClassifier) {
  1747. predictions = new FastVector();
  1748.       }
  1749.       
  1750.       for (int jj=0;jj<userTest.numInstances();jj++) {
  1751. processClassifierPrediction(userTest.instance(jj), classifier,
  1752.     eval, predictions,
  1753.     predInstances, plotShape,
  1754.     plotSize);
  1755. if ((jj % 100) == 0) {
  1756.   m_Log.statusMessage("Evaluating on test data. Processed "
  1757.       +jj+" instances...");
  1758. }
  1759.       }
  1760.       outBuff.append("n=== Re-evaluation on test set ===nn");
  1761.       outBuff.append("User supplied test setn");  
  1762.       outBuff.append("Relation:     " + userTest.relationName() + 'n');
  1763.       outBuff.append("Instances:    " + userTest.numInstances() + 'n');
  1764.       outBuff.append("Attributes:   " + userTest.numAttributes() + "nn");
  1765.       if (trainHeader == null)
  1766. outBuff.append("NOTE - if test set is not compatible then results are "
  1767.        + "unpredictablenn");
  1768.       
  1769.       if (outputSummary) {
  1770. outBuff.append(eval.toSummaryString(outputEntropy) + "n");
  1771.       }
  1772.       
  1773.       if (userTest.classAttribute().isNominal()) {
  1774. if (outputPerClass) {
  1775.   outBuff.append(eval.toClassDetailsString() + "n");
  1776. }
  1777. if (outputConfusion) {
  1778.   outBuff.append(eval.toMatrixString() + "n");
  1779. }
  1780.       }
  1781.       
  1782.       m_History.updateResult(name);
  1783.       m_Log.logMessage("Finished re-evaluation");
  1784.       m_Log.statusMessage("OK");
  1785.     } catch (Exception ex) {
  1786.       ex.printStackTrace();
  1787.       m_Log.logMessage(ex.getMessage());
  1788.       m_Log.statusMessage("See error log");
  1789.     } finally {
  1790.       try {
  1791. if (predInstances != null && predInstances.numInstances() > 0) {
  1792.   if (predInstances.attribute(predInstances.classIndex())
  1793.       .isNumeric()) {
  1794.     postProcessPlotInfo(plotSize);
  1795.   }
  1796.   m_CurrentVis = new VisualizePanel();
  1797.   m_CurrentVis.setName(name+" ("+userTest.relationName()+")");
  1798.   m_CurrentVis.setLog(m_Log);
  1799.   PlotData2D tempd = new PlotData2D(predInstances);
  1800.   tempd.setShapeSize(plotSize);
  1801.   tempd.setShapeType(plotShape);
  1802.   tempd.setPlotName(name+" ("+userTest.relationName()+")");
  1803.   tempd.addInstanceNumberAttribute();
  1804.   
  1805.   m_CurrentVis.addPlot(tempd);
  1806.   m_CurrentVis.setColourIndex(predInstances.classIndex()+1);
  1807.   
  1808.   m_CurrentVis.setXIndex(m_visXIndex); 
  1809.   m_CurrentVis.setYIndex(m_visYIndex);
  1810.   
  1811.   m_CurrentVis.addActionListener(new ActionListener() {
  1812.       public void actionPerformed(ActionEvent e) {
  1813. if (m_Instances != null &&
  1814.     m_CurrentVis.getInstances().
  1815.     relationName().
  1816.     compareTo(m_Instances.relationName()) == 0) {
  1817.   setXY_VisualizeIndexes(m_CurrentVis.getXIndex(), 
  1818.  m_CurrentVis.getYIndex());
  1819. }
  1820.       }
  1821.     });
  1822.   
  1823.   if (classifier instanceof Drawable) {
  1824.     try {
  1825.       grph = ((Drawable)classifier).graph();
  1826.     } catch (Exception ex) {
  1827.     }
  1828.   }
  1829.   if (saveVis) {
  1830.     FastVector vv = new FastVector();
  1831.     vv.addElement(classifier);
  1832.     if (trainHeader != null) vv.addElement(trainHeader);
  1833.     vv.addElement(m_CurrentVis);
  1834.     if (grph != null) {
  1835.       vv.addElement(grph);
  1836.     }
  1837.     if (predictions != null) {
  1838.       vv.addElement(predictions);
  1839.       vv.addElement(userTest.classAttribute());
  1840.     }
  1841.     m_History.addObject(name, vv);
  1842.   } else {
  1843.     FastVector vv = new FastVector();
  1844.     vv.addElement(classifier);
  1845.     if (trainHeader != null) vv.addElement(trainHeader);
  1846.     m_History.addObject(name, vv);
  1847.   }
  1848. }
  1849.       } catch (Exception ex) {
  1850. ex.printStackTrace();
  1851.       }
  1852.       
  1853.     }
  1854.   }
  1855.   
  1856.   /**
  1857.    * Tests out the classifier panel from the command line.
  1858.    *
  1859.    * @param args may optionally contain the name of a dataset to load.
  1860.    */
  1861.   public static void main(String [] args) {
  1862.     try {
  1863.       final javax.swing.JFrame jf =
  1864. new javax.swing.JFrame("Weka Knowledge Explorer: Classifier");
  1865.       jf.getContentPane().setLayout(new BorderLayout());
  1866.       final ClassifierPanel sp = new ClassifierPanel();
  1867.       jf.getContentPane().add(sp, BorderLayout.CENTER);
  1868.       weka.gui.LogPanel lp = new weka.gui.LogPanel();
  1869.       sp.setLog(lp);
  1870.       jf.getContentPane().add(lp, BorderLayout.SOUTH);
  1871.       jf.addWindowListener(new java.awt.event.WindowAdapter() {
  1872. public void windowClosing(java.awt.event.WindowEvent e) {
  1873.   jf.dispose();
  1874.   System.exit(0);
  1875. }
  1876.       });
  1877.       jf.pack();
  1878.       jf.setSize(800, 600);
  1879.       jf.setVisible(true);
  1880.       if (args.length == 1) {
  1881. System.err.println("Loading instances from " + args[0]);
  1882. java.io.Reader r = new java.io.BufferedReader(
  1883.    new java.io.FileReader(args[0]));
  1884. Instances i = new Instances(r);
  1885. sp.setInstances(i);
  1886.       }
  1887.     } catch (Exception ex) {
  1888.       ex.printStackTrace();
  1889.       System.err.println(ex.getMessage());
  1890.     }
  1891.   }
  1892. }