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 | /* |
---|
18 | * ClustererPanel.java |
---|
19 | * Copyright (C) 1999 University of Waikato, Hamilton, New Zealand |
---|
20 | * |
---|
21 | */ |
---|
22 | |
---|
23 | package weka.gui.explorer; |
---|
24 | |
---|
25 | import weka.clusterers.ClusterEvaluation; |
---|
26 | import weka.clusterers.Clusterer; |
---|
27 | import weka.core.Attribute; |
---|
28 | import weka.core.Capabilities; |
---|
29 | import weka.core.CapabilitiesHandler; |
---|
30 | import weka.core.Drawable; |
---|
31 | import weka.core.FastVector; |
---|
32 | import weka.core.Instances; |
---|
33 | import weka.core.OptionHandler; |
---|
34 | import weka.core.SerializedObject; |
---|
35 | import weka.core.Utils; |
---|
36 | import weka.core.Version; |
---|
37 | import weka.filters.Filter; |
---|
38 | import weka.filters.unsupervised.attribute.Remove; |
---|
39 | import weka.gui.ExtensionFileFilter; |
---|
40 | import weka.gui.GenericObjectEditor; |
---|
41 | import weka.gui.InstancesSummaryPanel; |
---|
42 | import weka.gui.ListSelectorDialog; |
---|
43 | import weka.gui.Logger; |
---|
44 | import weka.gui.PropertyPanel; |
---|
45 | import weka.gui.ResultHistoryPanel; |
---|
46 | import weka.gui.SaveBuffer; |
---|
47 | import weka.gui.SetInstancesPanel; |
---|
48 | import weka.gui.SysErrLog; |
---|
49 | import weka.gui.TaskLogger; |
---|
50 | import weka.gui.explorer.Explorer.CapabilitiesFilterChangeEvent; |
---|
51 | import weka.gui.explorer.Explorer.CapabilitiesFilterChangeListener; |
---|
52 | import weka.gui.explorer.Explorer.ExplorerPanel; |
---|
53 | import weka.gui.explorer.Explorer.LogHandler; |
---|
54 | import weka.gui.treevisualizer.PlaceNode2; |
---|
55 | import weka.gui.treevisualizer.TreeVisualizer; |
---|
56 | import weka.gui.visualize.VisualizePanel; |
---|
57 | import weka.gui.visualize.plugins.TreeVisualizePlugin; |
---|
58 | |
---|
59 | import java.awt.BorderLayout; |
---|
60 | import java.awt.Dimension; |
---|
61 | import java.awt.Font; |
---|
62 | import java.awt.GridBagConstraints; |
---|
63 | import java.awt.GridBagLayout; |
---|
64 | import java.awt.GridLayout; |
---|
65 | import java.awt.Insets; |
---|
66 | import java.awt.Point; |
---|
67 | import java.awt.event.ActionEvent; |
---|
68 | import java.awt.event.ActionListener; |
---|
69 | import java.awt.event.InputEvent; |
---|
70 | import java.awt.event.MouseAdapter; |
---|
71 | import java.awt.event.MouseEvent; |
---|
72 | import java.beans.PropertyChangeEvent; |
---|
73 | import java.beans.PropertyChangeListener; |
---|
74 | import java.io.File; |
---|
75 | import java.io.FileInputStream; |
---|
76 | import java.io.FileOutputStream; |
---|
77 | import java.io.InputStream; |
---|
78 | import java.io.ObjectInputStream; |
---|
79 | import java.io.ObjectOutputStream; |
---|
80 | import java.io.OutputStream; |
---|
81 | import java.text.SimpleDateFormat; |
---|
82 | import java.util.Date; |
---|
83 | import java.util.Random; |
---|
84 | import java.util.Vector; |
---|
85 | import java.util.zip.GZIPInputStream; |
---|
86 | import java.util.zip.GZIPOutputStream; |
---|
87 | |
---|
88 | import javax.swing.BorderFactory; |
---|
89 | import javax.swing.ButtonGroup; |
---|
90 | import javax.swing.DefaultComboBoxModel; |
---|
91 | import javax.swing.DefaultListModel; |
---|
92 | import javax.swing.JButton; |
---|
93 | import javax.swing.JCheckBox; |
---|
94 | import javax.swing.JComboBox; |
---|
95 | import javax.swing.JFileChooser; |
---|
96 | import javax.swing.JFrame; |
---|
97 | import javax.swing.JLabel; |
---|
98 | import javax.swing.JList; |
---|
99 | import javax.swing.JMenu; |
---|
100 | import javax.swing.JMenuItem; |
---|
101 | import javax.swing.JOptionPane; |
---|
102 | import javax.swing.JPanel; |
---|
103 | import javax.swing.JPopupMenu; |
---|
104 | import javax.swing.JRadioButton; |
---|
105 | import javax.swing.JScrollPane; |
---|
106 | import javax.swing.JTextArea; |
---|
107 | import javax.swing.JTextField; |
---|
108 | import javax.swing.JViewport; |
---|
109 | import javax.swing.SwingConstants; |
---|
110 | import javax.swing.event.ChangeEvent; |
---|
111 | import javax.swing.event.ChangeListener; |
---|
112 | import javax.swing.filechooser.FileFilter; |
---|
113 | |
---|
114 | import weka.gui.hierarchyvisualizer.HierarchyVisualizer; |
---|
115 | |
---|
116 | /** |
---|
117 | * This panel allows the user to select and configure a clusterer, and evaluate |
---|
118 | * the clusterer using a number of testing modes (test on the training data, |
---|
119 | * train/test on a percentage split, test on a |
---|
120 | * separate split). The results of clustering runs are stored in a result |
---|
121 | * history so that previous results are accessible. |
---|
122 | * |
---|
123 | * @author Mark Hall (mhall@cs.waikato.ac.nz) |
---|
124 | * @author Richard Kirkby (rkirkby@cs.waikato.ac.nz) |
---|
125 | * @version $Revision: 5961 $ |
---|
126 | */ |
---|
127 | public class ClustererPanel |
---|
128 | extends JPanel |
---|
129 | implements CapabilitiesFilterChangeListener, ExplorerPanel, LogHandler { |
---|
130 | |
---|
131 | /** for serialization */ |
---|
132 | static final long serialVersionUID = -2474932792950820990L; |
---|
133 | |
---|
134 | /** the parent frame */ |
---|
135 | protected Explorer m_Explorer = null; |
---|
136 | |
---|
137 | /** The filename extension that should be used for model files */ |
---|
138 | public static String MODEL_FILE_EXTENSION = ".model"; |
---|
139 | |
---|
140 | /** Lets the user configure the clusterer */ |
---|
141 | protected GenericObjectEditor m_ClustererEditor = |
---|
142 | new GenericObjectEditor(); |
---|
143 | |
---|
144 | /** The panel showing the current clusterer selection */ |
---|
145 | protected PropertyPanel m_CLPanel = new PropertyPanel(m_ClustererEditor); |
---|
146 | |
---|
147 | /** The output area for classification results */ |
---|
148 | protected JTextArea m_OutText = new JTextArea(20, 40); |
---|
149 | |
---|
150 | /** The destination for log/status messages */ |
---|
151 | protected Logger m_Log = new SysErrLog(); |
---|
152 | |
---|
153 | /** The buffer saving object for saving output */ |
---|
154 | SaveBuffer m_SaveOut = new SaveBuffer(m_Log, this); |
---|
155 | |
---|
156 | /** A panel controlling results viewing */ |
---|
157 | protected ResultHistoryPanel m_History = new ResultHistoryPanel(m_OutText); |
---|
158 | |
---|
159 | /** Click to set test mode to generate a % split */ |
---|
160 | protected JRadioButton m_PercentBut = new JRadioButton("Percentage split"); |
---|
161 | |
---|
162 | /** Click to set test mode to test on training data */ |
---|
163 | protected JRadioButton m_TrainBut = new JRadioButton("Use training set"); |
---|
164 | |
---|
165 | /** Click to set test mode to a user-specified test set */ |
---|
166 | protected JRadioButton m_TestSplitBut = |
---|
167 | new JRadioButton("Supplied test set"); |
---|
168 | |
---|
169 | /** Click to set test mode to classes to clusters based evaluation */ |
---|
170 | protected JRadioButton m_ClassesToClustersBut = |
---|
171 | new JRadioButton("Classes to clusters evaluation"); |
---|
172 | |
---|
173 | /** Lets the user select the class column for classes to clusters based |
---|
174 | evaluation */ |
---|
175 | protected JComboBox m_ClassCombo = new JComboBox(); |
---|
176 | |
---|
177 | /** Label by where the % split is entered */ |
---|
178 | protected JLabel m_PercentLab = new JLabel("%", SwingConstants.RIGHT); |
---|
179 | |
---|
180 | /** The field where the % split is entered */ |
---|
181 | protected JTextField m_PercentText = new JTextField("66"); |
---|
182 | |
---|
183 | /** The button used to open a separate test dataset */ |
---|
184 | protected JButton m_SetTestBut = new JButton("Set..."); |
---|
185 | |
---|
186 | /** The frame used to show the test set selection panel */ |
---|
187 | protected JFrame m_SetTestFrame; |
---|
188 | |
---|
189 | /** The button used to popup a list for choosing attributes to ignore while |
---|
190 | clustering */ |
---|
191 | protected JButton m_ignoreBut = new JButton("Ignore attributes"); |
---|
192 | |
---|
193 | protected DefaultListModel m_ignoreKeyModel = new DefaultListModel(); |
---|
194 | protected JList m_ignoreKeyList = new JList(m_ignoreKeyModel); |
---|
195 | |
---|
196 | // protected Remove m_ignoreFilter = null; |
---|
197 | |
---|
198 | /** |
---|
199 | * Alters the enabled/disabled status of elements associated with each |
---|
200 | * radio button |
---|
201 | */ |
---|
202 | ActionListener m_RadioListener = new ActionListener() { |
---|
203 | public void actionPerformed(ActionEvent e) { |
---|
204 | updateRadioLinks(); |
---|
205 | } |
---|
206 | }; |
---|
207 | |
---|
208 | /** Click to start running the clusterer */ |
---|
209 | protected JButton m_StartBut = new JButton("Start"); |
---|
210 | |
---|
211 | /** Stop the class combo from taking up to much space */ |
---|
212 | private Dimension COMBO_SIZE = new Dimension(250, m_StartBut |
---|
213 | .getPreferredSize().height); |
---|
214 | |
---|
215 | /** Click to stop a running clusterer */ |
---|
216 | protected JButton m_StopBut = new JButton("Stop"); |
---|
217 | |
---|
218 | /** The main set of instances we're playing with */ |
---|
219 | protected Instances m_Instances; |
---|
220 | |
---|
221 | /** The user-supplied test set (if any) */ |
---|
222 | protected Instances m_TestInstances; |
---|
223 | |
---|
224 | /** The current visualization object */ |
---|
225 | protected VisualizePanel m_CurrentVis = null; |
---|
226 | |
---|
227 | /** Check to save the predictions in the results list for visualizing |
---|
228 | later on */ |
---|
229 | protected JCheckBox m_StorePredictionsBut = |
---|
230 | new JCheckBox("Store clusters for visualization"); |
---|
231 | |
---|
232 | /** A thread that clustering runs in */ |
---|
233 | protected Thread m_RunThread; |
---|
234 | |
---|
235 | /** The instances summary panel displayed by m_SetTestFrame */ |
---|
236 | protected InstancesSummaryPanel m_Summary; |
---|
237 | |
---|
238 | /** Filter to ensure only model files are selected */ |
---|
239 | protected FileFilter m_ModelFilter = |
---|
240 | new ExtensionFileFilter(MODEL_FILE_EXTENSION, "Model object files"); |
---|
241 | |
---|
242 | /** The file chooser for selecting model files */ |
---|
243 | protected JFileChooser m_FileChooser |
---|
244 | = new JFileChooser(new File(System.getProperty("user.dir"))); |
---|
245 | |
---|
246 | /* Register the property editors we need */ |
---|
247 | static { |
---|
248 | GenericObjectEditor.registerEditors(); |
---|
249 | } |
---|
250 | |
---|
251 | /** |
---|
252 | * Creates the clusterer panel |
---|
253 | */ |
---|
254 | public ClustererPanel() { |
---|
255 | |
---|
256 | // Connect / configure the components |
---|
257 | m_OutText.setEditable(false); |
---|
258 | m_OutText.setFont(new Font("Monospaced", Font.PLAIN, 12)); |
---|
259 | m_OutText.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); |
---|
260 | m_OutText.addMouseListener(new MouseAdapter() { |
---|
261 | public void mouseClicked(MouseEvent e) { |
---|
262 | if ((e.getModifiers() & InputEvent.BUTTON1_MASK) |
---|
263 | != InputEvent.BUTTON1_MASK) { |
---|
264 | m_OutText.selectAll(); |
---|
265 | } |
---|
266 | } |
---|
267 | }); |
---|
268 | m_History.setBorder(BorderFactory.createTitledBorder("Result list (right-click for options)")); |
---|
269 | m_ClustererEditor.setClassType(Clusterer.class); |
---|
270 | m_ClustererEditor.setValue(ExplorerDefaults.getClusterer()); |
---|
271 | m_ClustererEditor.addPropertyChangeListener(new PropertyChangeListener() { |
---|
272 | public void propertyChange(PropertyChangeEvent e) { |
---|
273 | m_StartBut.setEnabled(true); |
---|
274 | Capabilities currentFilter = m_ClustererEditor.getCapabilitiesFilter(); |
---|
275 | Clusterer clusterer = (Clusterer) m_ClustererEditor.getValue(); |
---|
276 | Capabilities currentSchemeCapabilities = null; |
---|
277 | if (clusterer != null && currentFilter != null && |
---|
278 | (clusterer instanceof CapabilitiesHandler)) { |
---|
279 | currentSchemeCapabilities = ((CapabilitiesHandler)clusterer).getCapabilities(); |
---|
280 | |
---|
281 | if (!currentSchemeCapabilities.supportsMaybe(currentFilter) && |
---|
282 | !currentSchemeCapabilities.supports(currentFilter)) { |
---|
283 | m_StartBut.setEnabled(false); |
---|
284 | } |
---|
285 | } |
---|
286 | repaint(); |
---|
287 | } |
---|
288 | }); |
---|
289 | |
---|
290 | m_TrainBut.setToolTipText("Cluster the same set that the clusterer" |
---|
291 | + " is trained on"); |
---|
292 | m_PercentBut.setToolTipText("Train on a percentage of the data and" |
---|
293 | + " cluster the remainder"); |
---|
294 | m_TestSplitBut.setToolTipText("Cluster a user-specified dataset"); |
---|
295 | m_ClassesToClustersBut.setToolTipText("Evaluate clusters with respect to a" |
---|
296 | +" class"); |
---|
297 | m_ClassCombo.setToolTipText("Select the class attribute for class based" |
---|
298 | +" evaluation"); |
---|
299 | m_StartBut.setToolTipText("Starts the clustering"); |
---|
300 | m_StopBut.setToolTipText("Stops a running clusterer"); |
---|
301 | m_StorePredictionsBut. |
---|
302 | setToolTipText("Store predictions in the result list for later " |
---|
303 | +"visualization"); |
---|
304 | m_ignoreBut.setToolTipText("Ignore attributes during clustering"); |
---|
305 | |
---|
306 | m_FileChooser.setFileFilter(m_ModelFilter); |
---|
307 | m_FileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); |
---|
308 | |
---|
309 | m_ClassCombo.setPreferredSize(COMBO_SIZE); |
---|
310 | m_ClassCombo.setMaximumSize(COMBO_SIZE); |
---|
311 | m_ClassCombo.setMinimumSize(COMBO_SIZE); |
---|
312 | m_ClassCombo.setEnabled(false); |
---|
313 | |
---|
314 | m_PercentBut.setSelected(ExplorerDefaults.getClustererTestMode() == 2); |
---|
315 | m_TrainBut.setSelected(ExplorerDefaults.getClustererTestMode() == 3); |
---|
316 | m_TestSplitBut.setSelected(ExplorerDefaults.getClustererTestMode() == 4); |
---|
317 | m_ClassesToClustersBut.setSelected(ExplorerDefaults.getClustererTestMode() == 5); |
---|
318 | m_StorePredictionsBut.setSelected(ExplorerDefaults.getClustererStoreClustersForVis()); |
---|
319 | updateRadioLinks(); |
---|
320 | ButtonGroup bg = new ButtonGroup(); |
---|
321 | bg.add(m_TrainBut); |
---|
322 | bg.add(m_PercentBut); |
---|
323 | bg.add(m_TestSplitBut); |
---|
324 | bg.add(m_ClassesToClustersBut); |
---|
325 | m_TrainBut.addActionListener(m_RadioListener); |
---|
326 | m_PercentBut.addActionListener(m_RadioListener); |
---|
327 | m_TestSplitBut.addActionListener(m_RadioListener); |
---|
328 | m_ClassesToClustersBut.addActionListener(m_RadioListener); |
---|
329 | m_SetTestBut.addActionListener(new ActionListener() { |
---|
330 | public void actionPerformed(ActionEvent e) { |
---|
331 | setTestSet(); |
---|
332 | } |
---|
333 | }); |
---|
334 | |
---|
335 | m_StartBut.setEnabled(false); |
---|
336 | m_StopBut.setEnabled(false); |
---|
337 | m_ignoreBut.setEnabled(false); |
---|
338 | m_StartBut.addActionListener(new ActionListener() { |
---|
339 | public void actionPerformed(ActionEvent e) { |
---|
340 | startClusterer(); |
---|
341 | } |
---|
342 | }); |
---|
343 | m_StopBut.addActionListener(new ActionListener() { |
---|
344 | public void actionPerformed(ActionEvent e) { |
---|
345 | stopClusterer(); |
---|
346 | } |
---|
347 | }); |
---|
348 | |
---|
349 | m_ignoreBut.addActionListener(new ActionListener() { |
---|
350 | public void actionPerformed(ActionEvent e) { |
---|
351 | setIgnoreColumns(); |
---|
352 | } |
---|
353 | }); |
---|
354 | |
---|
355 | m_History.setHandleRightClicks(false); |
---|
356 | // see if we can popup a menu for the selected result |
---|
357 | m_History.getList().addMouseListener(new MouseAdapter() { |
---|
358 | public void mouseClicked(MouseEvent e) { |
---|
359 | if (((e.getModifiers() & InputEvent.BUTTON1_MASK) |
---|
360 | != InputEvent.BUTTON1_MASK) || e.isAltDown()) { |
---|
361 | int index = m_History.getList().locationToIndex(e.getPoint()); |
---|
362 | if (index != -1) { |
---|
363 | String name = m_History.getNameAtIndex(index); |
---|
364 | visualizeClusterer(name, e.getX(), e.getY()); |
---|
365 | } else { |
---|
366 | visualizeClusterer(null, e.getX(), e.getY()); |
---|
367 | } |
---|
368 | } |
---|
369 | } |
---|
370 | }); |
---|
371 | |
---|
372 | m_ClassCombo.addActionListener(new ActionListener() { |
---|
373 | public void actionPerformed(ActionEvent e) { |
---|
374 | updateCapabilitiesFilter(m_ClustererEditor.getCapabilitiesFilter()); |
---|
375 | } |
---|
376 | }); |
---|
377 | |
---|
378 | // Layout the GUI |
---|
379 | JPanel p1 = new JPanel(); |
---|
380 | p1.setBorder(BorderFactory.createCompoundBorder( |
---|
381 | BorderFactory.createTitledBorder("Clusterer"), |
---|
382 | BorderFactory.createEmptyBorder(0, 5, 5, 5) |
---|
383 | )); |
---|
384 | p1.setLayout(new BorderLayout()); |
---|
385 | p1.add(m_CLPanel, BorderLayout.NORTH); |
---|
386 | |
---|
387 | JPanel p2 = new JPanel(); |
---|
388 | GridBagLayout gbL = new GridBagLayout(); |
---|
389 | p2.setLayout(gbL); |
---|
390 | p2.setBorder(BorderFactory.createCompoundBorder( |
---|
391 | BorderFactory.createTitledBorder("Cluster mode"), |
---|
392 | BorderFactory.createEmptyBorder(0, 5, 5, 5) |
---|
393 | )); |
---|
394 | GridBagConstraints gbC = new GridBagConstraints(); |
---|
395 | gbC.anchor = GridBagConstraints.WEST; |
---|
396 | gbC.gridy = 0; gbC.gridx = 0; |
---|
397 | gbL.setConstraints(m_TrainBut, gbC); |
---|
398 | p2.add(m_TrainBut); |
---|
399 | |
---|
400 | gbC = new GridBagConstraints(); |
---|
401 | gbC.anchor = GridBagConstraints.WEST; |
---|
402 | gbC.gridy = 1; gbC.gridx = 0; |
---|
403 | gbL.setConstraints(m_TestSplitBut, gbC); |
---|
404 | p2.add(m_TestSplitBut); |
---|
405 | |
---|
406 | gbC = new GridBagConstraints(); |
---|
407 | gbC.anchor = GridBagConstraints.EAST; |
---|
408 | gbC.fill = GridBagConstraints.HORIZONTAL; |
---|
409 | gbC.gridy = 1; gbC.gridx = 1; gbC.gridwidth = 2; |
---|
410 | gbC.insets = new Insets(2, 10, 2, 0); |
---|
411 | gbL.setConstraints(m_SetTestBut, gbC); |
---|
412 | p2.add(m_SetTestBut); |
---|
413 | |
---|
414 | gbC = new GridBagConstraints(); |
---|
415 | gbC.anchor = GridBagConstraints.WEST; |
---|
416 | gbC.gridy = 2; gbC.gridx = 0; |
---|
417 | gbL.setConstraints(m_PercentBut, gbC); |
---|
418 | p2.add(m_PercentBut); |
---|
419 | |
---|
420 | gbC = new GridBagConstraints(); |
---|
421 | gbC.anchor = GridBagConstraints.EAST; |
---|
422 | gbC.fill = GridBagConstraints.HORIZONTAL; |
---|
423 | gbC.gridy = 2; gbC.gridx = 1; |
---|
424 | gbC.insets = new Insets(2, 10, 2, 10); |
---|
425 | gbL.setConstraints(m_PercentLab, gbC); |
---|
426 | p2.add(m_PercentLab); |
---|
427 | |
---|
428 | gbC = new GridBagConstraints(); |
---|
429 | gbC.anchor = GridBagConstraints.EAST; |
---|
430 | gbC.fill = GridBagConstraints.HORIZONTAL; |
---|
431 | gbC.gridy = 2; gbC.gridx = 2; gbC.weightx = 100; |
---|
432 | gbC.ipadx = 20; |
---|
433 | gbL.setConstraints(m_PercentText, gbC); |
---|
434 | p2.add(m_PercentText); |
---|
435 | |
---|
436 | gbC = new GridBagConstraints(); |
---|
437 | gbC.anchor = GridBagConstraints.WEST; |
---|
438 | gbC.gridy = 3; gbC.gridx = 0; gbC.gridwidth = 2; |
---|
439 | gbL.setConstraints(m_ClassesToClustersBut, gbC); |
---|
440 | p2.add(m_ClassesToClustersBut); |
---|
441 | |
---|
442 | m_ClassCombo.setBorder(BorderFactory.createEmptyBorder(0, 20, 0, 0)); |
---|
443 | gbC = new GridBagConstraints(); |
---|
444 | gbC.anchor = GridBagConstraints.WEST; |
---|
445 | gbC.gridy = 4; gbC.gridx = 0; gbC.gridwidth = 2; |
---|
446 | gbL.setConstraints(m_ClassCombo, gbC); |
---|
447 | p2.add(m_ClassCombo); |
---|
448 | |
---|
449 | gbC = new GridBagConstraints(); |
---|
450 | gbC.anchor = GridBagConstraints.WEST; |
---|
451 | gbC.gridy = 5; gbC.gridx = 0; gbC.gridwidth = 2; |
---|
452 | gbL.setConstraints(m_StorePredictionsBut, gbC); |
---|
453 | p2.add(m_StorePredictionsBut); |
---|
454 | |
---|
455 | JPanel buttons = new JPanel(); |
---|
456 | buttons.setLayout(new GridLayout(2, 1)); |
---|
457 | JPanel ssButs = new JPanel(); |
---|
458 | ssButs.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); |
---|
459 | ssButs.setLayout(new GridLayout(1, 2, 5, 5)); |
---|
460 | ssButs.add(m_StartBut); |
---|
461 | ssButs.add(m_StopBut); |
---|
462 | |
---|
463 | JPanel ib = new JPanel(); |
---|
464 | ib.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); |
---|
465 | ib.setLayout(new GridLayout(1, 1, 5, 5)); |
---|
466 | ib.add(m_ignoreBut); |
---|
467 | buttons.add(ib); |
---|
468 | buttons.add(ssButs); |
---|
469 | |
---|
470 | JPanel p3 = new JPanel(); |
---|
471 | p3.setBorder(BorderFactory.createTitledBorder("Clusterer output")); |
---|
472 | p3.setLayout(new BorderLayout()); |
---|
473 | final JScrollPane js = new JScrollPane(m_OutText); |
---|
474 | p3.add(js, BorderLayout.CENTER); |
---|
475 | js.getViewport().addChangeListener(new ChangeListener() { |
---|
476 | private int lastHeight; |
---|
477 | public void stateChanged(ChangeEvent e) { |
---|
478 | JViewport vp = (JViewport)e.getSource(); |
---|
479 | int h = vp.getViewSize().height; |
---|
480 | if (h != lastHeight) { // i.e. an addition not just a user scrolling |
---|
481 | lastHeight = h; |
---|
482 | int x = h - vp.getExtentSize().height; |
---|
483 | vp.setViewPosition(new Point(0, x)); |
---|
484 | } |
---|
485 | } |
---|
486 | }); |
---|
487 | |
---|
488 | JPanel mondo = new JPanel(); |
---|
489 | gbL = new GridBagLayout(); |
---|
490 | mondo.setLayout(gbL); |
---|
491 | gbC = new GridBagConstraints(); |
---|
492 | // gbC.anchor = GridBagConstraints.WEST; |
---|
493 | gbC.fill = GridBagConstraints.HORIZONTAL; |
---|
494 | gbC.gridy = 0; gbC.gridx = 0; |
---|
495 | gbL.setConstraints(p2, gbC); |
---|
496 | mondo.add(p2); |
---|
497 | gbC = new GridBagConstraints(); |
---|
498 | gbC.anchor = GridBagConstraints.NORTH; |
---|
499 | gbC.fill = GridBagConstraints.HORIZONTAL; |
---|
500 | gbC.gridy = 1; gbC.gridx = 0; |
---|
501 | gbL.setConstraints(buttons, gbC); |
---|
502 | mondo.add(buttons); |
---|
503 | gbC = new GridBagConstraints(); |
---|
504 | //gbC.anchor = GridBagConstraints.NORTH; |
---|
505 | gbC.fill = GridBagConstraints.BOTH; |
---|
506 | gbC.gridy = 2; gbC.gridx = 0; gbC.weightx = 0; |
---|
507 | gbL.setConstraints(m_History, gbC); |
---|
508 | mondo.add(m_History); |
---|
509 | gbC = new GridBagConstraints(); |
---|
510 | gbC.fill = GridBagConstraints.BOTH; |
---|
511 | gbC.gridy = 0; gbC.gridx = 1; |
---|
512 | gbC.gridheight = 3; |
---|
513 | gbC.weightx = 100; gbC.weighty = 100; |
---|
514 | gbL.setConstraints(p3, gbC); |
---|
515 | mondo.add(p3); |
---|
516 | |
---|
517 | setLayout(new BorderLayout()); |
---|
518 | add(p1, BorderLayout.NORTH); |
---|
519 | add(mondo, BorderLayout.CENTER); |
---|
520 | } |
---|
521 | |
---|
522 | /** |
---|
523 | * Updates the enabled status of the input fields and labels. |
---|
524 | */ |
---|
525 | protected void updateRadioLinks() { |
---|
526 | |
---|
527 | m_SetTestBut.setEnabled(m_TestSplitBut.isSelected()); |
---|
528 | if ((m_SetTestFrame != null) && (!m_TestSplitBut.isSelected())) { |
---|
529 | m_SetTestFrame.setVisible(false); |
---|
530 | } |
---|
531 | m_PercentText.setEnabled(m_PercentBut.isSelected()); |
---|
532 | m_PercentLab.setEnabled(m_PercentBut.isSelected()); |
---|
533 | m_ClassCombo.setEnabled(m_ClassesToClustersBut.isSelected()); |
---|
534 | } |
---|
535 | |
---|
536 | /** |
---|
537 | * Sets the Logger to receive informational messages |
---|
538 | * |
---|
539 | * @param newLog the Logger that will now get info messages |
---|
540 | */ |
---|
541 | public void setLog(Logger newLog) { |
---|
542 | |
---|
543 | m_Log = newLog; |
---|
544 | } |
---|
545 | |
---|
546 | /** |
---|
547 | * Tells the panel to use a new set of instances. |
---|
548 | * |
---|
549 | * @param inst a set of Instances |
---|
550 | */ |
---|
551 | public void setInstances(Instances inst) { |
---|
552 | |
---|
553 | m_Instances = inst; |
---|
554 | |
---|
555 | m_ignoreKeyModel.removeAllElements(); |
---|
556 | |
---|
557 | String [] attribNames = new String [m_Instances.numAttributes()]; |
---|
558 | for (int i = 0; i < m_Instances.numAttributes(); i++) { |
---|
559 | String name = m_Instances.attribute(i).name(); |
---|
560 | m_ignoreKeyModel.addElement(name); |
---|
561 | |
---|
562 | String type = ""; |
---|
563 | switch (m_Instances.attribute(i).type()) { |
---|
564 | case Attribute.NOMINAL: |
---|
565 | type = "(Nom) "; |
---|
566 | break; |
---|
567 | case Attribute.NUMERIC: |
---|
568 | type = "(Num) "; |
---|
569 | break; |
---|
570 | case Attribute.STRING: |
---|
571 | type = "(Str) "; |
---|
572 | break; |
---|
573 | case Attribute.DATE: |
---|
574 | type = "(Dat) "; |
---|
575 | break; |
---|
576 | case Attribute.RELATIONAL: |
---|
577 | type = "(Rel) "; |
---|
578 | break; |
---|
579 | default: |
---|
580 | type = "(???) "; |
---|
581 | } |
---|
582 | String attnm = m_Instances.attribute(i).name(); |
---|
583 | |
---|
584 | attribNames[i] = type + attnm; |
---|
585 | } |
---|
586 | |
---|
587 | |
---|
588 | m_StartBut.setEnabled(m_RunThread == null); |
---|
589 | m_StopBut.setEnabled(m_RunThread != null); |
---|
590 | m_ignoreBut.setEnabled(true); |
---|
591 | m_ClassCombo.setModel(new DefaultComboBoxModel(attribNames)); |
---|
592 | if (inst.classIndex() == -1) |
---|
593 | m_ClassCombo.setSelectedIndex(attribNames.length - 1); |
---|
594 | else |
---|
595 | m_ClassCombo.setSelectedIndex(inst.classIndex()); |
---|
596 | updateRadioLinks(); |
---|
597 | } |
---|
598 | |
---|
599 | /** |
---|
600 | * Sets the user test set. Information about the current test set |
---|
601 | * is displayed in an InstanceSummaryPanel and the user is given the |
---|
602 | * ability to load another set from a file or url. |
---|
603 | * |
---|
604 | */ |
---|
605 | protected void setTestSet() { |
---|
606 | |
---|
607 | if (m_SetTestFrame == null) { |
---|
608 | final SetInstancesPanel sp = new SetInstancesPanel(); |
---|
609 | sp.setReadIncrementally(false); |
---|
610 | m_Summary = sp.getSummary(); |
---|
611 | if (m_TestInstances != null) { |
---|
612 | sp.setInstances(m_TestInstances); |
---|
613 | } |
---|
614 | sp.addPropertyChangeListener(new PropertyChangeListener() { |
---|
615 | public void propertyChange(PropertyChangeEvent e) { |
---|
616 | m_TestInstances = sp.getInstances(); |
---|
617 | m_TestInstances.setClassIndex(-1); // make sure that no class attribute is set! |
---|
618 | } |
---|
619 | }); |
---|
620 | // Add propertychangelistener to update m_TestInstances whenever |
---|
621 | // it changes in the settestframe |
---|
622 | m_SetTestFrame = new JFrame("Test Instances"); |
---|
623 | sp.setParentFrame(m_SetTestFrame); // enable Close-Button |
---|
624 | m_SetTestFrame.getContentPane().setLayout(new BorderLayout()); |
---|
625 | m_SetTestFrame.getContentPane().add(sp, BorderLayout.CENTER); |
---|
626 | m_SetTestFrame.pack(); |
---|
627 | } |
---|
628 | m_SetTestFrame.setVisible(true); |
---|
629 | } |
---|
630 | |
---|
631 | /** |
---|
632 | * Starts running the currently configured clusterer with the current |
---|
633 | * settings. This is run in a separate thread, and will only start if |
---|
634 | * there is no clusterer already running. The clusterer output is sent |
---|
635 | * to the results history panel. |
---|
636 | */ |
---|
637 | protected void startClusterer() { |
---|
638 | |
---|
639 | if (m_RunThread == null) { |
---|
640 | m_StartBut.setEnabled(false); |
---|
641 | m_StopBut.setEnabled(true); |
---|
642 | m_ignoreBut.setEnabled(false); |
---|
643 | m_RunThread = new Thread() { |
---|
644 | public void run() { |
---|
645 | // Copy the current state of things |
---|
646 | m_Log.statusMessage("Setting up..."); |
---|
647 | Instances inst = new Instances(m_Instances); |
---|
648 | inst.setClassIndex(-1); |
---|
649 | Instances userTest = null; |
---|
650 | ClustererAssignmentsPlotInstances plotInstances = ExplorerDefaults.getClustererAssignmentsPlotInstances(); |
---|
651 | plotInstances.setClusterer((Clusterer) m_ClustererEditor.getValue()); |
---|
652 | if (m_TestInstances != null) { |
---|
653 | userTest = new Instances(m_TestInstances); |
---|
654 | } |
---|
655 | |
---|
656 | boolean saveVis = m_StorePredictionsBut.isSelected(); |
---|
657 | String grph = null; |
---|
658 | int[] ignoredAtts = null; |
---|
659 | |
---|
660 | int testMode = 0; |
---|
661 | int percent = 66; |
---|
662 | Clusterer clusterer = (Clusterer) m_ClustererEditor.getValue(); |
---|
663 | Clusterer fullClusterer = null; |
---|
664 | StringBuffer outBuff = new StringBuffer(); |
---|
665 | String name = (new SimpleDateFormat("HH:mm:ss - ")).format(new Date()); |
---|
666 | String cname = clusterer.getClass().getName(); |
---|
667 | if (cname.startsWith("weka.clusterers.")) { |
---|
668 | name += cname.substring("weka.clusterers.".length()); |
---|
669 | } else { |
---|
670 | name += cname; |
---|
671 | } |
---|
672 | String cmd = m_ClustererEditor.getValue().getClass().getName(); |
---|
673 | if (m_ClustererEditor.getValue() instanceof OptionHandler) |
---|
674 | cmd += " " + Utils.joinOptions(((OptionHandler) m_ClustererEditor.getValue()).getOptions()); |
---|
675 | try { |
---|
676 | m_Log.logMessage("Started " + cname); |
---|
677 | m_Log.logMessage("Command: " + cmd); |
---|
678 | if (m_Log instanceof TaskLogger) { |
---|
679 | ((TaskLogger)m_Log).taskStarted(); |
---|
680 | } |
---|
681 | if (m_PercentBut.isSelected()) { |
---|
682 | testMode = 2; |
---|
683 | percent = Integer.parseInt(m_PercentText.getText()); |
---|
684 | if ((percent <= 0) || (percent >= 100)) { |
---|
685 | throw new Exception("Percentage must be between 0 and 100"); |
---|
686 | } |
---|
687 | } else if (m_TrainBut.isSelected()) { |
---|
688 | testMode = 3; |
---|
689 | } else if (m_TestSplitBut.isSelected()) { |
---|
690 | testMode = 4; |
---|
691 | // Check the test instance compatibility |
---|
692 | if (userTest == null) { |
---|
693 | throw new Exception("No user test set has been opened"); |
---|
694 | } |
---|
695 | if (!inst.equalHeaders(userTest)) { |
---|
696 | throw new Exception("Train and test set are not compatible\n" + inst.equalHeadersMsg(userTest)); |
---|
697 | } |
---|
698 | } else if (m_ClassesToClustersBut.isSelected()) { |
---|
699 | testMode = 5; |
---|
700 | } else { |
---|
701 | throw new Exception("Unknown test mode"); |
---|
702 | } |
---|
703 | |
---|
704 | Instances trainInst = new Instances(inst); |
---|
705 | if (m_ClassesToClustersBut.isSelected()) { |
---|
706 | trainInst.setClassIndex(m_ClassCombo.getSelectedIndex()); |
---|
707 | inst.setClassIndex(m_ClassCombo.getSelectedIndex()); |
---|
708 | if (inst.classAttribute().isNumeric()) { |
---|
709 | throw new Exception("Class must be nominal for class based " |
---|
710 | +"evaluation!"); |
---|
711 | } |
---|
712 | } |
---|
713 | if (!m_ignoreKeyList.isSelectionEmpty()) { |
---|
714 | trainInst = removeIgnoreCols(trainInst); |
---|
715 | } |
---|
716 | |
---|
717 | // Output some header information |
---|
718 | outBuff.append("=== Run information ===\n\n"); |
---|
719 | outBuff.append("Scheme: " + cname); |
---|
720 | if (clusterer instanceof OptionHandler) { |
---|
721 | String [] o = ((OptionHandler) clusterer).getOptions(); |
---|
722 | outBuff.append(" " + Utils.joinOptions(o)); |
---|
723 | } |
---|
724 | outBuff.append("\n"); |
---|
725 | outBuff.append("Relation: " + inst.relationName() + '\n'); |
---|
726 | outBuff.append("Instances: " + inst.numInstances() + '\n'); |
---|
727 | outBuff.append("Attributes: " + inst.numAttributes() + '\n'); |
---|
728 | if (inst.numAttributes() < 100) { |
---|
729 | boolean [] selected = new boolean [inst.numAttributes()]; |
---|
730 | for (int i = 0; i < inst.numAttributes(); i++) { |
---|
731 | selected[i] = true; |
---|
732 | } |
---|
733 | if (!m_ignoreKeyList.isSelectionEmpty()) { |
---|
734 | int [] indices = m_ignoreKeyList.getSelectedIndices(); |
---|
735 | for (int i = 0; i < indices.length; i++) { |
---|
736 | selected[indices[i]] = false; |
---|
737 | } |
---|
738 | } |
---|
739 | if (m_ClassesToClustersBut.isSelected()) { |
---|
740 | selected[m_ClassCombo.getSelectedIndex()] = false; |
---|
741 | } |
---|
742 | for (int i = 0; i < inst.numAttributes(); i++) { |
---|
743 | if (selected[i]) { |
---|
744 | outBuff.append(" " + inst.attribute(i).name() |
---|
745 | + '\n'); |
---|
746 | } |
---|
747 | } |
---|
748 | if (!m_ignoreKeyList.isSelectionEmpty() |
---|
749 | || m_ClassesToClustersBut.isSelected()) { |
---|
750 | outBuff.append("Ignored:\n"); |
---|
751 | for (int i = 0; i < inst.numAttributes(); i++) { |
---|
752 | if (!selected[i]) { |
---|
753 | outBuff.append(" " + inst.attribute(i).name() |
---|
754 | + '\n'); |
---|
755 | } |
---|
756 | } |
---|
757 | } |
---|
758 | } else { |
---|
759 | outBuff.append(" [list of attributes omitted]\n"); |
---|
760 | } |
---|
761 | |
---|
762 | if (!m_ignoreKeyList.isSelectionEmpty()) { |
---|
763 | ignoredAtts = m_ignoreKeyList.getSelectedIndices(); |
---|
764 | } |
---|
765 | |
---|
766 | if (m_ClassesToClustersBut.isSelected()) { |
---|
767 | // add class to ignored list |
---|
768 | if (ignoredAtts == null) { |
---|
769 | ignoredAtts = new int[1]; |
---|
770 | ignoredAtts[0] = m_ClassCombo.getSelectedIndex(); |
---|
771 | } else { |
---|
772 | int[] newIgnoredAtts = new int[ignoredAtts.length+1]; |
---|
773 | System.arraycopy(ignoredAtts, 0, newIgnoredAtts, 0, ignoredAtts.length); |
---|
774 | newIgnoredAtts[ignoredAtts.length] = m_ClassCombo.getSelectedIndex(); |
---|
775 | ignoredAtts = newIgnoredAtts; |
---|
776 | } |
---|
777 | } |
---|
778 | |
---|
779 | |
---|
780 | outBuff.append("Test mode: "); |
---|
781 | switch (testMode) { |
---|
782 | case 3: // Test on training |
---|
783 | outBuff.append("evaluate on training data\n"); |
---|
784 | break; |
---|
785 | case 2: // Percent split |
---|
786 | outBuff.append("split " + percent |
---|
787 | + "% train, remainder test\n"); |
---|
788 | break; |
---|
789 | case 4: // Test on user split |
---|
790 | outBuff.append("user supplied test set: " |
---|
791 | + userTest.numInstances() + " instances\n"); |
---|
792 | break; |
---|
793 | case 5: // Classes to clusters evaluation on training |
---|
794 | outBuff.append("Classes to clusters evaluation on training data"); |
---|
795 | |
---|
796 | break; |
---|
797 | } |
---|
798 | outBuff.append("\n"); |
---|
799 | m_History.addResult(name, outBuff); |
---|
800 | m_History.setSingle(name); |
---|
801 | |
---|
802 | // Build the model and output it. |
---|
803 | m_Log.statusMessage("Building model on training data..."); |
---|
804 | |
---|
805 | // remove the class attribute (if set) and build the clusterer |
---|
806 | clusterer.buildClusterer(removeClass(trainInst)); |
---|
807 | |
---|
808 | if (testMode == 2) { |
---|
809 | outBuff.append("\n=== Clustering model (full training set) ===\n\n"); |
---|
810 | |
---|
811 | outBuff.append(clusterer.toString() + '\n'); |
---|
812 | } |
---|
813 | m_History.updateResult(name); |
---|
814 | if (clusterer instanceof Drawable) { |
---|
815 | try { |
---|
816 | grph = ((Drawable)clusterer).graph(); |
---|
817 | } catch (Exception ex) { |
---|
818 | } |
---|
819 | } |
---|
820 | // copy full model for output |
---|
821 | SerializedObject so = new SerializedObject(clusterer); |
---|
822 | fullClusterer = (Clusterer) so.getObject(); |
---|
823 | |
---|
824 | ClusterEvaluation eval = new ClusterEvaluation(); |
---|
825 | eval.setClusterer(clusterer); |
---|
826 | switch (testMode) { |
---|
827 | case 3: case 5: // Test on training |
---|
828 | m_Log.statusMessage("Clustering training data..."); |
---|
829 | eval.evaluateClusterer(trainInst); |
---|
830 | plotInstances.setInstances(inst); |
---|
831 | plotInstances.setClusterEvaluation(eval); |
---|
832 | outBuff.append("=== Model and evaluation on training set ===\n\n"); |
---|
833 | break; |
---|
834 | |
---|
835 | case 2: // Percent split |
---|
836 | m_Log.statusMessage("Randomizing instances..."); |
---|
837 | inst.randomize(new Random(1)); |
---|
838 | trainInst.randomize(new Random(1)); |
---|
839 | int trainSize = trainInst.numInstances() * percent / 100; |
---|
840 | int testSize = trainInst.numInstances() - trainSize; |
---|
841 | Instances train = new Instances(trainInst, 0, trainSize); |
---|
842 | Instances test = new Instances(trainInst, trainSize, testSize); |
---|
843 | Instances testVis = new Instances(inst, trainSize, testSize); |
---|
844 | m_Log.statusMessage("Building model on training split..."); |
---|
845 | clusterer.buildClusterer(train); |
---|
846 | m_Log.statusMessage("Evaluating on test split..."); |
---|
847 | eval.evaluateClusterer(test); |
---|
848 | plotInstances.setInstances(testVis); |
---|
849 | plotInstances.setClusterEvaluation(eval); |
---|
850 | outBuff.append("=== Model and evaluation on test split ===\n"); |
---|
851 | break; |
---|
852 | |
---|
853 | case 4: // Test on user split |
---|
854 | m_Log.statusMessage("Evaluating on test data..."); |
---|
855 | Instances userTestT = new Instances(userTest); |
---|
856 | if (!m_ignoreKeyList.isSelectionEmpty()) { |
---|
857 | userTestT = removeIgnoreCols(userTestT); |
---|
858 | } |
---|
859 | eval.evaluateClusterer(userTestT); |
---|
860 | plotInstances.setInstances(userTest); |
---|
861 | plotInstances.setClusterEvaluation(eval); |
---|
862 | outBuff.append("=== Model and evaluation on test set ===\n"); |
---|
863 | break; |
---|
864 | |
---|
865 | default: |
---|
866 | throw new Exception("Test mode not implemented"); |
---|
867 | } |
---|
868 | outBuff.append(eval.clusterResultsToString()); |
---|
869 | outBuff.append("\n"); |
---|
870 | m_History.updateResult(name); |
---|
871 | m_Log.logMessage("Finished " + cname); |
---|
872 | m_Log.statusMessage("OK"); |
---|
873 | } catch (Exception ex) { |
---|
874 | ex.printStackTrace(); |
---|
875 | m_Log.logMessage(ex.getMessage()); |
---|
876 | JOptionPane.showMessageDialog(ClustererPanel.this, |
---|
877 | "Problem evaluating clusterer:\n" |
---|
878 | + ex.getMessage(), |
---|
879 | "Evaluate clusterer", |
---|
880 | JOptionPane.ERROR_MESSAGE); |
---|
881 | m_Log.statusMessage("Problem evaluating clusterer"); |
---|
882 | } finally { |
---|
883 | if (plotInstances != null) { |
---|
884 | plotInstances.setUp(); |
---|
885 | m_CurrentVis = new VisualizePanel(); |
---|
886 | m_CurrentVis.setName(name+" ("+inst.relationName()+")"); |
---|
887 | m_CurrentVis.setLog(m_Log); |
---|
888 | try { |
---|
889 | m_CurrentVis.addPlot(plotInstances.getPlotData(name)); |
---|
890 | } catch (Exception ex) { |
---|
891 | System.err.println(ex); |
---|
892 | } |
---|
893 | plotInstances.cleanUp(); |
---|
894 | |
---|
895 | FastVector vv = new FastVector(); |
---|
896 | vv.addElement(fullClusterer); |
---|
897 | Instances trainHeader = new Instances(m_Instances, 0); |
---|
898 | vv.addElement(trainHeader); |
---|
899 | if (ignoredAtts != null) vv.addElement(ignoredAtts); |
---|
900 | if (saveVis) { |
---|
901 | vv.addElement(m_CurrentVis); |
---|
902 | if (grph != null) { |
---|
903 | vv.addElement(grph); |
---|
904 | } |
---|
905 | |
---|
906 | } |
---|
907 | m_History.addObject(name, vv); |
---|
908 | } |
---|
909 | if (isInterrupted()) { |
---|
910 | m_Log.logMessage("Interrupted " + cname); |
---|
911 | m_Log.statusMessage("See error log"); |
---|
912 | } |
---|
913 | m_RunThread = null; |
---|
914 | m_StartBut.setEnabled(true); |
---|
915 | m_StopBut.setEnabled(false); |
---|
916 | m_ignoreBut.setEnabled(true); |
---|
917 | if (m_Log instanceof TaskLogger) { |
---|
918 | ((TaskLogger)m_Log).taskFinished(); |
---|
919 | } |
---|
920 | } |
---|
921 | } |
---|
922 | }; |
---|
923 | m_RunThread.setPriority(Thread.MIN_PRIORITY); |
---|
924 | m_RunThread.start(); |
---|
925 | } |
---|
926 | } |
---|
927 | |
---|
928 | private Instances removeClass(Instances inst) { |
---|
929 | Remove af = new Remove(); |
---|
930 | Instances retI = null; |
---|
931 | |
---|
932 | try { |
---|
933 | if (inst.classIndex() < 0) { |
---|
934 | retI = inst; |
---|
935 | } else { |
---|
936 | af.setAttributeIndices(""+(inst.classIndex()+1)); |
---|
937 | af.setInvertSelection(false); |
---|
938 | af.setInputFormat(inst); |
---|
939 | retI = Filter.useFilter(inst, af); |
---|
940 | } |
---|
941 | } catch (Exception e) { |
---|
942 | e.printStackTrace(); |
---|
943 | } |
---|
944 | return retI; |
---|
945 | } |
---|
946 | |
---|
947 | private Instances removeIgnoreCols(Instances inst) { |
---|
948 | |
---|
949 | // If the user is doing classes to clusters evaluation and |
---|
950 | // they have opted to ignore the class, then unselect the class in |
---|
951 | // the ignore list |
---|
952 | if (m_ClassesToClustersBut.isSelected()) { |
---|
953 | int classIndex = m_ClassCombo.getSelectedIndex(); |
---|
954 | if (m_ignoreKeyList.isSelectedIndex(classIndex)) { |
---|
955 | m_ignoreKeyList.removeSelectionInterval(classIndex, classIndex); |
---|
956 | } |
---|
957 | } |
---|
958 | int [] selected = m_ignoreKeyList.getSelectedIndices(); |
---|
959 | Remove af = new Remove(); |
---|
960 | Instances retI = null; |
---|
961 | |
---|
962 | try { |
---|
963 | af.setAttributeIndicesArray(selected); |
---|
964 | af.setInvertSelection(false); |
---|
965 | af.setInputFormat(inst); |
---|
966 | retI = Filter.useFilter(inst, af); |
---|
967 | } catch (Exception e) { |
---|
968 | e.printStackTrace(); |
---|
969 | } |
---|
970 | |
---|
971 | return retI; |
---|
972 | } |
---|
973 | |
---|
974 | private Instances removeIgnoreCols(Instances inst, int[] toIgnore) { |
---|
975 | |
---|
976 | Remove af = new Remove(); |
---|
977 | Instances retI = null; |
---|
978 | |
---|
979 | try { |
---|
980 | af.setAttributeIndicesArray(toIgnore); |
---|
981 | af.setInvertSelection(false); |
---|
982 | af.setInputFormat(inst); |
---|
983 | retI = Filter.useFilter(inst, af); |
---|
984 | } catch (Exception e) { |
---|
985 | e.printStackTrace(); |
---|
986 | } |
---|
987 | |
---|
988 | return retI; |
---|
989 | } |
---|
990 | |
---|
991 | /** |
---|
992 | * Stops the currently running clusterer (if any). |
---|
993 | */ |
---|
994 | protected void stopClusterer() { |
---|
995 | |
---|
996 | if (m_RunThread != null) { |
---|
997 | m_RunThread.interrupt(); |
---|
998 | |
---|
999 | // This is deprecated (and theoretically the interrupt should do). |
---|
1000 | m_RunThread.stop(); |
---|
1001 | |
---|
1002 | } |
---|
1003 | } |
---|
1004 | |
---|
1005 | /** |
---|
1006 | * Pops up a TreeVisualizer for the clusterer from the currently |
---|
1007 | * selected item in the results list |
---|
1008 | * @param graphString the description of the tree in dotty format |
---|
1009 | * @param treeName the title to assign to the display |
---|
1010 | */ |
---|
1011 | protected void visualizeTree(String graphString, String treeName) { |
---|
1012 | final javax.swing.JFrame jf = |
---|
1013 | new javax.swing.JFrame("Weka Classifier Tree Visualizer: "+treeName); |
---|
1014 | jf.setSize(500,400); |
---|
1015 | jf.getContentPane().setLayout(new BorderLayout()); |
---|
1016 | if (graphString.contains("digraph")) { |
---|
1017 | TreeVisualizer tv = new TreeVisualizer(null, |
---|
1018 | graphString, |
---|
1019 | new PlaceNode2()); |
---|
1020 | jf.getContentPane().add(tv, BorderLayout.CENTER); |
---|
1021 | jf.addWindowListener(new java.awt.event.WindowAdapter() { |
---|
1022 | public void windowClosing(java.awt.event.WindowEvent e) { |
---|
1023 | jf.dispose(); |
---|
1024 | } |
---|
1025 | }); |
---|
1026 | jf.setVisible(true); |
---|
1027 | tv.fitToScreen(); |
---|
1028 | } else if (graphString.startsWith("Newick:")) { |
---|
1029 | HierarchyVisualizer tv = new HierarchyVisualizer(graphString.substring(7)); |
---|
1030 | jf.getContentPane().add(tv, BorderLayout.CENTER); |
---|
1031 | jf.addWindowListener(new java.awt.event.WindowAdapter() { |
---|
1032 | public void windowClosing(java.awt.event.WindowEvent e) { |
---|
1033 | jf.dispose(); |
---|
1034 | } |
---|
1035 | }); |
---|
1036 | jf.setVisible(true); |
---|
1037 | tv.fitToScreen(); |
---|
1038 | } |
---|
1039 | } |
---|
1040 | |
---|
1041 | /** |
---|
1042 | * Pops up a visualize panel to display cluster assignments |
---|
1043 | * @param sp the visualize panel to display |
---|
1044 | */ |
---|
1045 | protected void visualizeClusterAssignments(VisualizePanel sp) { |
---|
1046 | if (sp != null) { |
---|
1047 | String plotName = sp.getName(); |
---|
1048 | final javax.swing.JFrame jf = |
---|
1049 | new javax.swing.JFrame("Weka Clusterer Visualize: "+plotName); |
---|
1050 | jf.setSize(500,400); |
---|
1051 | jf.getContentPane().setLayout(new BorderLayout()); |
---|
1052 | jf.getContentPane().add(sp, BorderLayout.CENTER); |
---|
1053 | jf.addWindowListener(new java.awt.event.WindowAdapter() { |
---|
1054 | public void windowClosing(java.awt.event.WindowEvent e) { |
---|
1055 | jf.dispose(); |
---|
1056 | } |
---|
1057 | }); |
---|
1058 | |
---|
1059 | jf.setVisible(true); |
---|
1060 | } |
---|
1061 | } |
---|
1062 | |
---|
1063 | /** |
---|
1064 | * Handles constructing a popup menu with visualization options |
---|
1065 | * @param name the name of the result history list entry clicked on by |
---|
1066 | * the user |
---|
1067 | * @param x the x coordinate for popping up the menu |
---|
1068 | * @param y the y coordinate for popping up the menu |
---|
1069 | */ |
---|
1070 | protected void visualizeClusterer(String name, int x, int y) { |
---|
1071 | final String selectedName = name; |
---|
1072 | JPopupMenu resultListMenu = new JPopupMenu(); |
---|
1073 | |
---|
1074 | JMenuItem visMainBuffer = new JMenuItem("View in main window"); |
---|
1075 | if (selectedName != null) { |
---|
1076 | visMainBuffer.addActionListener(new ActionListener() { |
---|
1077 | public void actionPerformed(ActionEvent e) { |
---|
1078 | m_History.setSingle(selectedName); |
---|
1079 | } |
---|
1080 | }); |
---|
1081 | } else { |
---|
1082 | visMainBuffer.setEnabled(false); |
---|
1083 | } |
---|
1084 | resultListMenu.add(visMainBuffer); |
---|
1085 | |
---|
1086 | JMenuItem visSepBuffer = new JMenuItem("View in separate window"); |
---|
1087 | if (selectedName != null) { |
---|
1088 | visSepBuffer.addActionListener(new ActionListener() { |
---|
1089 | public void actionPerformed(ActionEvent e) { |
---|
1090 | m_History.openFrame(selectedName); |
---|
1091 | } |
---|
1092 | }); |
---|
1093 | } else { |
---|
1094 | visSepBuffer.setEnabled(false); |
---|
1095 | } |
---|
1096 | resultListMenu.add(visSepBuffer); |
---|
1097 | |
---|
1098 | JMenuItem saveOutput = new JMenuItem("Save result buffer"); |
---|
1099 | if (selectedName != null) { |
---|
1100 | saveOutput.addActionListener(new ActionListener() { |
---|
1101 | public void actionPerformed(ActionEvent e) { |
---|
1102 | saveBuffer(selectedName); |
---|
1103 | } |
---|
1104 | }); |
---|
1105 | } else { |
---|
1106 | saveOutput.setEnabled(false); |
---|
1107 | } |
---|
1108 | resultListMenu.add(saveOutput); |
---|
1109 | |
---|
1110 | JMenuItem deleteOutput = new JMenuItem("Delete result buffer"); |
---|
1111 | if (selectedName != null) { |
---|
1112 | deleteOutput.addActionListener(new ActionListener() { |
---|
1113 | public void actionPerformed(ActionEvent e) { |
---|
1114 | m_History.removeResult(selectedName); |
---|
1115 | } |
---|
1116 | }); |
---|
1117 | } else { |
---|
1118 | deleteOutput.setEnabled(false); |
---|
1119 | } |
---|
1120 | resultListMenu.add(deleteOutput); |
---|
1121 | |
---|
1122 | resultListMenu.addSeparator(); |
---|
1123 | |
---|
1124 | JMenuItem loadModel = new JMenuItem("Load model"); |
---|
1125 | loadModel.addActionListener(new ActionListener() { |
---|
1126 | public void actionPerformed(ActionEvent e) { |
---|
1127 | loadClusterer(); |
---|
1128 | } |
---|
1129 | }); |
---|
1130 | resultListMenu.add(loadModel); |
---|
1131 | |
---|
1132 | FastVector o = null; |
---|
1133 | if (selectedName != null) { |
---|
1134 | o = (FastVector)m_History.getNamedObject(selectedName); |
---|
1135 | } |
---|
1136 | |
---|
1137 | VisualizePanel temp_vp = null; |
---|
1138 | String temp_grph = null; |
---|
1139 | Clusterer temp_clusterer = null; |
---|
1140 | Instances temp_trainHeader = null; |
---|
1141 | int[] temp_ignoreAtts = null; |
---|
1142 | |
---|
1143 | if (o != null) { |
---|
1144 | for (int i = 0; i < o.size(); i++) { |
---|
1145 | Object temp = o.elementAt(i); |
---|
1146 | if (temp instanceof Clusterer) { |
---|
1147 | temp_clusterer = (Clusterer)temp; |
---|
1148 | } else if (temp instanceof Instances) { // training header |
---|
1149 | temp_trainHeader = (Instances)temp; |
---|
1150 | } else if (temp instanceof int[]) { // ignored attributes |
---|
1151 | temp_ignoreAtts = (int[])temp; |
---|
1152 | } else if (temp instanceof VisualizePanel) { // normal errors |
---|
1153 | temp_vp = (VisualizePanel)temp; |
---|
1154 | } else if (temp instanceof String) { // graphable output |
---|
1155 | temp_grph = (String)temp; |
---|
1156 | } |
---|
1157 | } |
---|
1158 | } |
---|
1159 | |
---|
1160 | final VisualizePanel vp = temp_vp; |
---|
1161 | final String grph = temp_grph; |
---|
1162 | final Clusterer clusterer = temp_clusterer; |
---|
1163 | final Instances trainHeader = temp_trainHeader; |
---|
1164 | final int[] ignoreAtts = temp_ignoreAtts; |
---|
1165 | |
---|
1166 | JMenuItem saveModel = new JMenuItem("Save model"); |
---|
1167 | if (clusterer != null) { |
---|
1168 | saveModel.addActionListener(new ActionListener() { |
---|
1169 | public void actionPerformed(ActionEvent e) { |
---|
1170 | saveClusterer(selectedName, clusterer, trainHeader, ignoreAtts); |
---|
1171 | } |
---|
1172 | }); |
---|
1173 | } else { |
---|
1174 | saveModel.setEnabled(false); |
---|
1175 | } |
---|
1176 | resultListMenu.add(saveModel); |
---|
1177 | |
---|
1178 | JMenuItem reEvaluate = |
---|
1179 | new JMenuItem("Re-evaluate model on current test set"); |
---|
1180 | if (clusterer != null && m_TestInstances != null) { |
---|
1181 | reEvaluate.addActionListener(new ActionListener() { |
---|
1182 | public void actionPerformed(ActionEvent e) { |
---|
1183 | reevaluateModel(selectedName, clusterer, trainHeader, ignoreAtts); |
---|
1184 | } |
---|
1185 | }); |
---|
1186 | } else { |
---|
1187 | reEvaluate.setEnabled(false); |
---|
1188 | } |
---|
1189 | resultListMenu.add(reEvaluate); |
---|
1190 | |
---|
1191 | resultListMenu.addSeparator(); |
---|
1192 | |
---|
1193 | JMenuItem visClusts = new JMenuItem("Visualize cluster assignments"); |
---|
1194 | if (vp != null) { |
---|
1195 | visClusts.addActionListener(new ActionListener() { |
---|
1196 | public void actionPerformed(ActionEvent e) { |
---|
1197 | visualizeClusterAssignments(vp); |
---|
1198 | } |
---|
1199 | }); |
---|
1200 | |
---|
1201 | } else { |
---|
1202 | visClusts.setEnabled(false); |
---|
1203 | } |
---|
1204 | resultListMenu.add(visClusts); |
---|
1205 | |
---|
1206 | JMenuItem visTree = new JMenuItem("Visualize tree"); |
---|
1207 | if (grph != null) { |
---|
1208 | visTree.addActionListener(new ActionListener() { |
---|
1209 | public void actionPerformed(ActionEvent e) { |
---|
1210 | String title; |
---|
1211 | if (vp != null) title = vp.getName(); |
---|
1212 | else title = selectedName; |
---|
1213 | visualizeTree(grph, title); |
---|
1214 | } |
---|
1215 | }); |
---|
1216 | } else { |
---|
1217 | visTree.setEnabled(false); |
---|
1218 | } |
---|
1219 | resultListMenu.add(visTree); |
---|
1220 | |
---|
1221 | |
---|
1222 | // visualization plugins |
---|
1223 | JMenu visPlugins = new JMenu("Plugins"); |
---|
1224 | boolean availablePlugins = false; |
---|
1225 | |
---|
1226 | // trees |
---|
1227 | if (grph != null) { |
---|
1228 | // trees |
---|
1229 | Vector pluginsVector = GenericObjectEditor.getClassnames(TreeVisualizePlugin.class.getName()); |
---|
1230 | for (int i = 0; i < pluginsVector.size(); i++) { |
---|
1231 | String className = (String) (pluginsVector.elementAt(i)); |
---|
1232 | try { |
---|
1233 | TreeVisualizePlugin plugin = (TreeVisualizePlugin) Class.forName(className).newInstance(); |
---|
1234 | if (plugin == null) |
---|
1235 | continue; |
---|
1236 | availablePlugins = true; |
---|
1237 | JMenuItem pluginMenuItem = plugin.getVisualizeMenuItem(grph, selectedName); |
---|
1238 | Version version = new Version(); |
---|
1239 | if (pluginMenuItem != null) { |
---|
1240 | if (version.compareTo(plugin.getMinVersion()) < 0) |
---|
1241 | pluginMenuItem.setText(pluginMenuItem.getText() + " (weka outdated)"); |
---|
1242 | if (version.compareTo(plugin.getMaxVersion()) >= 0) |
---|
1243 | pluginMenuItem.setText(pluginMenuItem.getText() + " (plugin outdated)"); |
---|
1244 | visPlugins.add(pluginMenuItem); |
---|
1245 | } |
---|
1246 | } |
---|
1247 | catch (Exception e) { |
---|
1248 | //e.printStackTrace(); |
---|
1249 | } |
---|
1250 | } |
---|
1251 | } |
---|
1252 | |
---|
1253 | if (availablePlugins) |
---|
1254 | resultListMenu.add(visPlugins); |
---|
1255 | |
---|
1256 | resultListMenu.show(m_History.getList(), x, y); |
---|
1257 | } |
---|
1258 | |
---|
1259 | /** |
---|
1260 | * Save the currently selected clusterer output to a file. |
---|
1261 | * @param name the name of the buffer to save |
---|
1262 | */ |
---|
1263 | protected void saveBuffer(String name) { |
---|
1264 | StringBuffer sb = m_History.getNamedBuffer(name); |
---|
1265 | if (sb != null) { |
---|
1266 | if (m_SaveOut.save(sb)) { |
---|
1267 | m_Log.logMessage("Save successful."); |
---|
1268 | } |
---|
1269 | } |
---|
1270 | } |
---|
1271 | |
---|
1272 | private void setIgnoreColumns() { |
---|
1273 | ListSelectorDialog jd = new ListSelectorDialog(null, m_ignoreKeyList); |
---|
1274 | |
---|
1275 | // Open the dialog |
---|
1276 | int result = jd.showDialog(); |
---|
1277 | |
---|
1278 | if (result != ListSelectorDialog.APPROVE_OPTION) { |
---|
1279 | // clear selected indices |
---|
1280 | m_ignoreKeyList.clearSelection(); |
---|
1281 | } |
---|
1282 | } |
---|
1283 | |
---|
1284 | /** |
---|
1285 | * Saves the currently selected clusterer |
---|
1286 | */ |
---|
1287 | protected void saveClusterer(String name, Clusterer clusterer, |
---|
1288 | Instances trainHeader, int[] ignoredAtts) { |
---|
1289 | |
---|
1290 | File sFile = null; |
---|
1291 | boolean saveOK = true; |
---|
1292 | |
---|
1293 | int returnVal = m_FileChooser.showSaveDialog(this); |
---|
1294 | if (returnVal == JFileChooser.APPROVE_OPTION) { |
---|
1295 | sFile = m_FileChooser.getSelectedFile(); |
---|
1296 | if (!sFile.getName().toLowerCase().endsWith(MODEL_FILE_EXTENSION)) { |
---|
1297 | sFile = new File(sFile.getParent(), sFile.getName() |
---|
1298 | + MODEL_FILE_EXTENSION); |
---|
1299 | } |
---|
1300 | m_Log.statusMessage("Saving model to file..."); |
---|
1301 | |
---|
1302 | try { |
---|
1303 | OutputStream os = new FileOutputStream(sFile); |
---|
1304 | if (sFile.getName().endsWith(".gz")) { |
---|
1305 | os = new GZIPOutputStream(os); |
---|
1306 | } |
---|
1307 | ObjectOutputStream objectOutputStream = new ObjectOutputStream(os); |
---|
1308 | objectOutputStream.writeObject(clusterer); |
---|
1309 | if (trainHeader != null) objectOutputStream.writeObject(trainHeader); |
---|
1310 | if (ignoredAtts != null) objectOutputStream.writeObject(ignoredAtts); |
---|
1311 | objectOutputStream.flush(); |
---|
1312 | objectOutputStream.close(); |
---|
1313 | } catch (Exception e) { |
---|
1314 | |
---|
1315 | JOptionPane.showMessageDialog(null, e, "Save Failed", |
---|
1316 | JOptionPane.ERROR_MESSAGE); |
---|
1317 | saveOK = false; |
---|
1318 | } |
---|
1319 | if (saveOK) |
---|
1320 | m_Log.logMessage("Saved model (" + name |
---|
1321 | + ") to file '" + sFile.getName() + "'"); |
---|
1322 | m_Log.statusMessage("OK"); |
---|
1323 | } |
---|
1324 | } |
---|
1325 | |
---|
1326 | /** |
---|
1327 | * Loads a clusterer |
---|
1328 | */ |
---|
1329 | protected void loadClusterer() { |
---|
1330 | |
---|
1331 | int returnVal = m_FileChooser.showOpenDialog(this); |
---|
1332 | if (returnVal == JFileChooser.APPROVE_OPTION) { |
---|
1333 | File selected = m_FileChooser.getSelectedFile(); |
---|
1334 | Clusterer clusterer = null; |
---|
1335 | Instances trainHeader = null; |
---|
1336 | int[] ignoredAtts = null; |
---|
1337 | |
---|
1338 | m_Log.statusMessage("Loading model from file..."); |
---|
1339 | |
---|
1340 | try { |
---|
1341 | InputStream is = new FileInputStream(selected); |
---|
1342 | if (selected.getName().endsWith(".gz")) { |
---|
1343 | is = new GZIPInputStream(is); |
---|
1344 | } |
---|
1345 | ObjectInputStream objectInputStream = new ObjectInputStream(is); |
---|
1346 | clusterer = (Clusterer) objectInputStream.readObject(); |
---|
1347 | try { // see if we can load the header & ignored attribute info |
---|
1348 | trainHeader = (Instances) objectInputStream.readObject(); |
---|
1349 | ignoredAtts = (int[]) objectInputStream.readObject(); |
---|
1350 | } catch (Exception e) {} // don't fuss if we can't |
---|
1351 | objectInputStream.close(); |
---|
1352 | } catch (Exception e) { |
---|
1353 | |
---|
1354 | JOptionPane.showMessageDialog(null, e, "Load Failed", |
---|
1355 | JOptionPane.ERROR_MESSAGE); |
---|
1356 | } |
---|
1357 | |
---|
1358 | m_Log.statusMessage("OK"); |
---|
1359 | |
---|
1360 | if (clusterer != null) { |
---|
1361 | m_Log.logMessage("Loaded model from file '" + selected.getName()+ "'"); |
---|
1362 | String name = (new SimpleDateFormat("HH:mm:ss - ")).format(new Date()); |
---|
1363 | String cname = clusterer.getClass().getName(); |
---|
1364 | if (cname.startsWith("weka.clusterers.")) |
---|
1365 | cname = cname.substring("weka.clusterers.".length()); |
---|
1366 | name += cname + " from file '" + selected.getName() + "'"; |
---|
1367 | StringBuffer outBuff = new StringBuffer(); |
---|
1368 | |
---|
1369 | outBuff.append("=== Model information ===\n\n"); |
---|
1370 | outBuff.append("Filename: " + selected.getName() + "\n"); |
---|
1371 | outBuff.append("Scheme: " + clusterer.getClass().getName()); |
---|
1372 | if (clusterer instanceof OptionHandler) { |
---|
1373 | String [] o = ((OptionHandler) clusterer).getOptions(); |
---|
1374 | outBuff.append(" " + Utils.joinOptions(o)); |
---|
1375 | } |
---|
1376 | outBuff.append("\n"); |
---|
1377 | |
---|
1378 | if (trainHeader != null) { |
---|
1379 | |
---|
1380 | outBuff.append("Relation: " + trainHeader.relationName() + '\n'); |
---|
1381 | outBuff.append("Attributes: " + trainHeader.numAttributes() + '\n'); |
---|
1382 | if (trainHeader.numAttributes() < 100) { |
---|
1383 | boolean [] selectedAtts = new boolean [trainHeader.numAttributes()]; |
---|
1384 | for (int i = 0; i < trainHeader.numAttributes(); i++) { |
---|
1385 | selectedAtts[i] = true; |
---|
1386 | } |
---|
1387 | |
---|
1388 | if (ignoredAtts != null) |
---|
1389 | for (int i=0; i<ignoredAtts.length; i++) |
---|
1390 | selectedAtts[ignoredAtts[i]] = false; |
---|
1391 | |
---|
1392 | for (int i = 0; i < trainHeader.numAttributes(); i++) { |
---|
1393 | if (selectedAtts[i]) { |
---|
1394 | outBuff.append(" " + trainHeader.attribute(i).name() |
---|
1395 | + '\n'); |
---|
1396 | } |
---|
1397 | } |
---|
1398 | if (ignoredAtts != null) { |
---|
1399 | outBuff.append("Ignored:\n"); |
---|
1400 | for (int i=0; i<ignoredAtts.length; i++) |
---|
1401 | outBuff.append(" " |
---|
1402 | + trainHeader.attribute(ignoredAtts[i]).name() |
---|
1403 | + '\n'); |
---|
1404 | } |
---|
1405 | } else { |
---|
1406 | outBuff.append(" [list of attributes omitted]\n"); |
---|
1407 | } |
---|
1408 | } else { |
---|
1409 | outBuff.append("\nTraining data unknown\n"); |
---|
1410 | } |
---|
1411 | |
---|
1412 | outBuff.append("\n=== Clustering model ===\n\n"); |
---|
1413 | outBuff.append(clusterer.toString() + "\n"); |
---|
1414 | |
---|
1415 | m_History.addResult(name, outBuff); |
---|
1416 | m_History.setSingle(name); |
---|
1417 | FastVector vv = new FastVector(); |
---|
1418 | vv.addElement(clusterer); |
---|
1419 | if (trainHeader != null) vv.addElement(trainHeader); |
---|
1420 | if (ignoredAtts != null) vv.addElement(ignoredAtts); |
---|
1421 | // allow visualization of graphable classifiers |
---|
1422 | String grph = null; |
---|
1423 | if (clusterer instanceof Drawable) { |
---|
1424 | try { |
---|
1425 | grph = ((Drawable)clusterer).graph(); |
---|
1426 | } catch (Exception ex) { |
---|
1427 | } |
---|
1428 | } |
---|
1429 | if (grph != null) vv.addElement(grph); |
---|
1430 | |
---|
1431 | m_History.addObject(name, vv); |
---|
1432 | |
---|
1433 | } |
---|
1434 | } |
---|
1435 | } |
---|
1436 | |
---|
1437 | /** |
---|
1438 | * Re-evaluates the named clusterer with the current test set. Unpredictable |
---|
1439 | * things will happen if the data set is not compatible with the clusterer. |
---|
1440 | * |
---|
1441 | * @param name the name of the clusterer entry |
---|
1442 | * @param clusterer the clusterer to evaluate |
---|
1443 | * @param trainHeader the header of the training set |
---|
1444 | * @param ignoredAtts ignored attributes |
---|
1445 | */ |
---|
1446 | protected void reevaluateModel(final String name, |
---|
1447 | final Clusterer clusterer, |
---|
1448 | final Instances trainHeader, |
---|
1449 | final int[] ignoredAtts) { |
---|
1450 | |
---|
1451 | if (m_RunThread == null) { |
---|
1452 | m_StartBut.setEnabled(false); |
---|
1453 | m_StopBut.setEnabled(true); |
---|
1454 | m_ignoreBut.setEnabled(false); |
---|
1455 | m_RunThread = new Thread() { |
---|
1456 | public void run() { |
---|
1457 | // Copy the current state of things |
---|
1458 | m_Log.statusMessage("Setting up..."); |
---|
1459 | |
---|
1460 | StringBuffer outBuff = m_History.getNamedBuffer(name); |
---|
1461 | Instances userTest = null; |
---|
1462 | |
---|
1463 | ClustererAssignmentsPlotInstances plotInstances = ExplorerDefaults.getClustererAssignmentsPlotInstances(); |
---|
1464 | plotInstances.setClusterer(clusterer); |
---|
1465 | if (m_TestInstances != null) { |
---|
1466 | userTest = new Instances(m_TestInstances); |
---|
1467 | } |
---|
1468 | |
---|
1469 | boolean saveVis = m_StorePredictionsBut.isSelected(); |
---|
1470 | String grph = null; |
---|
1471 | |
---|
1472 | try { |
---|
1473 | if (userTest == null) { |
---|
1474 | throw new Exception("No user test set has been opened"); |
---|
1475 | } |
---|
1476 | if (trainHeader != null && !trainHeader.equalHeaders(userTest)) { |
---|
1477 | throw new Exception("Train and test set are not compatible\n" + trainHeader.equalHeadersMsg(userTest)); |
---|
1478 | } |
---|
1479 | |
---|
1480 | m_Log.statusMessage("Evaluating on test data..."); |
---|
1481 | m_Log.logMessage("Re-evaluating clusterer (" + name + ") on test set"); |
---|
1482 | |
---|
1483 | m_Log.logMessage("Started reevaluate model"); |
---|
1484 | if (m_Log instanceof TaskLogger) { |
---|
1485 | ((TaskLogger)m_Log).taskStarted(); |
---|
1486 | } |
---|
1487 | ClusterEvaluation eval = new ClusterEvaluation(); |
---|
1488 | eval.setClusterer(clusterer); |
---|
1489 | |
---|
1490 | Instances userTestT = new Instances(userTest); |
---|
1491 | if (ignoredAtts != null) { |
---|
1492 | userTestT = removeIgnoreCols(userTestT, ignoredAtts); |
---|
1493 | } |
---|
1494 | |
---|
1495 | eval.evaluateClusterer(userTestT); |
---|
1496 | |
---|
1497 | plotInstances.setClusterEvaluation(eval); |
---|
1498 | plotInstances.setInstances(userTest); |
---|
1499 | plotInstances.setUp(); |
---|
1500 | |
---|
1501 | outBuff.append("\n=== Re-evaluation on test set ===\n\n"); |
---|
1502 | outBuff.append("User supplied test set\n"); |
---|
1503 | outBuff.append("Relation: " + userTest.relationName() + '\n'); |
---|
1504 | outBuff.append("Instances: " + userTest.numInstances() + '\n'); |
---|
1505 | outBuff.append("Attributes: " + userTest.numAttributes() + "\n\n"); |
---|
1506 | if (trainHeader == null) |
---|
1507 | outBuff.append("NOTE - if test set is not compatible then results are " |
---|
1508 | + "unpredictable\n\n"); |
---|
1509 | |
---|
1510 | outBuff.append(eval.clusterResultsToString()); |
---|
1511 | outBuff.append("\n"); |
---|
1512 | m_History.updateResult(name); |
---|
1513 | m_Log.logMessage("Finished re-evaluation"); |
---|
1514 | m_Log.statusMessage("OK"); |
---|
1515 | } catch (Exception ex) { |
---|
1516 | ex.printStackTrace(); |
---|
1517 | m_Log.logMessage(ex.getMessage()); |
---|
1518 | JOptionPane.showMessageDialog(ClustererPanel.this, |
---|
1519 | "Problem evaluating clusterer:\n" |
---|
1520 | + ex.getMessage(), |
---|
1521 | "Evaluate clusterer", |
---|
1522 | JOptionPane.ERROR_MESSAGE); |
---|
1523 | m_Log.statusMessage("Problem evaluating clusterer"); |
---|
1524 | |
---|
1525 | } finally { |
---|
1526 | if (plotInstances != null) { |
---|
1527 | m_CurrentVis = new VisualizePanel(); |
---|
1528 | m_CurrentVis.setName(name+" ("+userTest.relationName()+")"); |
---|
1529 | m_CurrentVis.setLog(m_Log); |
---|
1530 | try { |
---|
1531 | m_CurrentVis.addPlot(plotInstances.getPlotData(name)); |
---|
1532 | } catch (Exception ex) { |
---|
1533 | System.err.println(ex); |
---|
1534 | } |
---|
1535 | |
---|
1536 | FastVector vv = new FastVector(); |
---|
1537 | vv.addElement(clusterer); |
---|
1538 | if (trainHeader != null) vv.addElement(trainHeader); |
---|
1539 | if (ignoredAtts != null) vv.addElement(ignoredAtts); |
---|
1540 | if (saveVis) { |
---|
1541 | vv.addElement(m_CurrentVis); |
---|
1542 | if (grph != null) { |
---|
1543 | vv.addElement(grph); |
---|
1544 | } |
---|
1545 | |
---|
1546 | } |
---|
1547 | m_History.addObject(name, vv); |
---|
1548 | |
---|
1549 | } |
---|
1550 | if (isInterrupted()) { |
---|
1551 | m_Log.logMessage("Interrupted reevaluate model"); |
---|
1552 | m_Log.statusMessage("See error log"); |
---|
1553 | } |
---|
1554 | m_RunThread = null; |
---|
1555 | m_StartBut.setEnabled(true); |
---|
1556 | m_StopBut.setEnabled(false); |
---|
1557 | m_ignoreBut.setEnabled(true); |
---|
1558 | if (m_Log instanceof TaskLogger) { |
---|
1559 | ((TaskLogger)m_Log).taskFinished(); |
---|
1560 | } |
---|
1561 | } |
---|
1562 | } |
---|
1563 | |
---|
1564 | }; |
---|
1565 | m_RunThread.setPriority(Thread.MIN_PRIORITY); |
---|
1566 | m_RunThread.start(); |
---|
1567 | } |
---|
1568 | } |
---|
1569 | |
---|
1570 | /** |
---|
1571 | * updates the capabilities filter of the GOE |
---|
1572 | * |
---|
1573 | * @param filter the new filter to use |
---|
1574 | */ |
---|
1575 | protected void updateCapabilitiesFilter(Capabilities filter) { |
---|
1576 | Instances tempInst; |
---|
1577 | Capabilities filterClass; |
---|
1578 | |
---|
1579 | if (filter == null) { |
---|
1580 | m_ClustererEditor.setCapabilitiesFilter(new Capabilities(null)); |
---|
1581 | return; |
---|
1582 | } |
---|
1583 | |
---|
1584 | if (!ExplorerDefaults.getInitGenericObjectEditorFilter()) |
---|
1585 | tempInst = new Instances(m_Instances, 0); |
---|
1586 | else |
---|
1587 | tempInst = new Instances(m_Instances); |
---|
1588 | tempInst.setClassIndex(-1); |
---|
1589 | |
---|
1590 | try { |
---|
1591 | filterClass = Capabilities.forInstances(tempInst); |
---|
1592 | } |
---|
1593 | catch (Exception e) { |
---|
1594 | filterClass = new Capabilities(null); |
---|
1595 | } |
---|
1596 | |
---|
1597 | m_ClustererEditor.setCapabilitiesFilter(filterClass); |
---|
1598 | |
---|
1599 | // check capabilities |
---|
1600 | m_StartBut.setEnabled(true); |
---|
1601 | Capabilities currentFilter = m_ClustererEditor.getCapabilitiesFilter(); |
---|
1602 | Clusterer clusterer = (Clusterer) m_ClustererEditor.getValue(); |
---|
1603 | Capabilities currentSchemeCapabilities = null; |
---|
1604 | if (clusterer != null && currentFilter != null && |
---|
1605 | (clusterer instanceof CapabilitiesHandler)) { |
---|
1606 | currentSchemeCapabilities = ((CapabilitiesHandler)clusterer).getCapabilities(); |
---|
1607 | |
---|
1608 | if (!currentSchemeCapabilities.supportsMaybe(currentFilter) && |
---|
1609 | !currentSchemeCapabilities.supports(currentFilter)) { |
---|
1610 | m_StartBut.setEnabled(false); |
---|
1611 | } |
---|
1612 | } |
---|
1613 | } |
---|
1614 | |
---|
1615 | /** |
---|
1616 | * method gets called in case of a change event |
---|
1617 | * |
---|
1618 | * @param e the associated change event |
---|
1619 | */ |
---|
1620 | public void capabilitiesFilterChanged(CapabilitiesFilterChangeEvent e) { |
---|
1621 | if (e.getFilter() == null) |
---|
1622 | updateCapabilitiesFilter(null); |
---|
1623 | else |
---|
1624 | updateCapabilitiesFilter((Capabilities) e.getFilter().clone()); |
---|
1625 | } |
---|
1626 | |
---|
1627 | /** |
---|
1628 | * Sets the Explorer to use as parent frame (used for sending notifications |
---|
1629 | * about changes in the data) |
---|
1630 | * |
---|
1631 | * @param parent the parent frame |
---|
1632 | */ |
---|
1633 | public void setExplorer(Explorer parent) { |
---|
1634 | m_Explorer = parent; |
---|
1635 | } |
---|
1636 | |
---|
1637 | /** |
---|
1638 | * returns the parent Explorer frame |
---|
1639 | * |
---|
1640 | * @return the parent |
---|
1641 | */ |
---|
1642 | public Explorer getExplorer() { |
---|
1643 | return m_Explorer; |
---|
1644 | } |
---|
1645 | |
---|
1646 | /** |
---|
1647 | * Returns the title for the tab in the Explorer |
---|
1648 | * |
---|
1649 | * @return the title of this tab |
---|
1650 | */ |
---|
1651 | public String getTabTitle() { |
---|
1652 | return "Cluster"; |
---|
1653 | } |
---|
1654 | |
---|
1655 | /** |
---|
1656 | * Returns the tooltip for the tab in the Explorer |
---|
1657 | * |
---|
1658 | * @return the tooltip of this tab |
---|
1659 | */ |
---|
1660 | public String getTabTitleToolTip() { |
---|
1661 | return "Identify instance clusters"; |
---|
1662 | } |
---|
1663 | |
---|
1664 | /** |
---|
1665 | * Tests out the clusterer panel from the command line. |
---|
1666 | * |
---|
1667 | * @param args may optionally contain the name of a dataset to load. |
---|
1668 | */ |
---|
1669 | public static void main(String [] args) { |
---|
1670 | |
---|
1671 | try { |
---|
1672 | final javax.swing.JFrame jf = |
---|
1673 | new javax.swing.JFrame("Weka Explorer: Cluster"); |
---|
1674 | jf.getContentPane().setLayout(new BorderLayout()); |
---|
1675 | final ClustererPanel sp = new ClustererPanel(); |
---|
1676 | jf.getContentPane().add(sp, BorderLayout.CENTER); |
---|
1677 | weka.gui.LogPanel lp = new weka.gui.LogPanel(); |
---|
1678 | sp.setLog(lp); |
---|
1679 | jf.getContentPane().add(lp, BorderLayout.SOUTH); |
---|
1680 | jf.addWindowListener(new java.awt.event.WindowAdapter() { |
---|
1681 | public void windowClosing(java.awt.event.WindowEvent e) { |
---|
1682 | jf.dispose(); |
---|
1683 | System.exit(0); |
---|
1684 | } |
---|
1685 | }); |
---|
1686 | jf.pack(); |
---|
1687 | jf.setSize(800, 600); |
---|
1688 | jf.setVisible(true); |
---|
1689 | if (args.length == 1) { |
---|
1690 | System.err.println("Loading instances from " + args[0]); |
---|
1691 | java.io.Reader r = new java.io.BufferedReader( |
---|
1692 | new java.io.FileReader(args[0])); |
---|
1693 | Instances i = new Instances(r); |
---|
1694 | sp.setInstances(i); |
---|
1695 | } |
---|
1696 | } catch (Exception ex) { |
---|
1697 | ex.printStackTrace(); |
---|
1698 | System.err.println(ex.getMessage()); |
---|
1699 | } |
---|
1700 | } |
---|
1701 | } |
---|