source: src/main/java/weka/gui/beans/ClustererPerformanceEvaluator.java @ 23

Last change on this file since 23 was 4, checked in by gnappo, 14 years ago

Import di weka.

File size: 9.5 KB
Line 
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 *    ClustererPerformanceEvaluator.java
19 *    Copyright (C) 2004 University of Waikato, Hamilton, New Zealand
20 *
21 */
22
23package weka.gui.beans;
24
25import weka.clusterers.ClusterEvaluation;
26import weka.clusterers.Clusterer;
27
28import java.io.Serializable;
29import java.util.Enumeration;
30import java.util.Vector;
31
32/**
33 * A bean that evaluates the performance of batch trained clusterers
34 *
35 * @author <a href="mailto:mutter@cs.waikato.ac.nz">Stefan Mutter</a>
36 * @version $Revision: 4813 $
37 */
38public class ClustererPerformanceEvaluator
39  extends AbstractEvaluator
40  implements BatchClustererListener, Serializable, UserRequestAcceptor, 
41             EventConstraints {
42
43  /** for serialization */
44  private static final long serialVersionUID = 8041163601333978584L;
45
46  /**
47   * Evaluation object used for evaluating a clusterer
48   */
49  private transient ClusterEvaluation m_eval;
50
51  /**
52   * Holds the clusterer to be evaluated
53   */
54  private transient Clusterer m_clusterer;
55
56  private transient Thread m_evaluateThread = null;
57 
58  private Vector m_textListeners = new Vector();
59
60  public ClustererPerformanceEvaluator() {
61    m_visual.loadIcons(BeanVisual.ICON_PATH
62                       +"ClustererPerformanceEvaluator.gif",
63                       BeanVisual.ICON_PATH
64                       +"ClustererPerformanceEvaluator_animated.gif");
65    m_visual.setText("ClustererPerformanceEvaluator");
66  }
67
68  /**
69   * Set a custom (descriptive) name for this bean
70   *
71   * @param name the name to use
72   */
73  public void setCustomName(String name) {
74    m_visual.setText(name);
75  }
76
77  /**
78   * Get the custom (descriptive) name for this bean (if one has been set)
79   *
80   * @return the custom name (or the default name)
81   */
82  public String getCustomName() {
83    return m_visual.getText();
84  }
85 
86  /**
87   * Global info for this bean
88   *
89   * @return a <code>String</code> value
90   */
91  public String globalInfo() {
92    return "Evaluate the performance of batch trained clusterers.";
93  }
94
95  /**
96   * Accept a clusterer to be evaluated
97   *
98   * @param ce a <code>BatchClustererEvent</code> value
99   */
100  public void acceptClusterer(final BatchClustererEvent ce) {
101   
102    if (ce.getTestSet().isStructureOnly()) {
103      return; // cant evaluate empty instances
104    }
105    try {
106      if (m_evaluateThread == null) {
107        m_evaluateThread = new Thread() {
108            public void run() {
109              boolean numericClass = false; 
110//            final String oldText = m_visual.getText();
111              try {
112                if (ce.getSetNumber() == 1 /*||
113                    ce.getClusterer() != m_clusterer */) {
114                  m_eval = new ClusterEvaluation();
115                  m_clusterer = ce.getClusterer();
116                  m_eval.setClusterer(m_clusterer);
117                }
118               
119                if (ce.getSetNumber() <= ce.getMaxSetNumber()) {
120//                m_visual.setText("Evaluating ("+ce.getSetNumber()+")...");
121                  if (m_logger != null) {
122                    m_logger.statusMessage(statusMessagePrefix()
123                                           +"Evaluating ("+ce.getSetNumber()
124                                           +")...");
125                  }
126                  m_visual.setAnimated();
127                  if(ce.getTestSet().getDataSet().classIndex() != -1 && ce.getTestSet().getDataSet().classAttribute().isNumeric()){
128                    numericClass = true;
129                    ce.getTestSet().getDataSet().setClassIndex(-1);
130                  } 
131                  m_eval.evaluateClusterer(ce.getTestSet().getDataSet());
132                }
133               
134                if (ce.getSetNumber() == ce.getMaxSetNumber()) {
135                  String textTitle = m_clusterer.getClass().getName();
136                  textTitle = 
137                    textTitle.substring(textTitle.lastIndexOf('.')+1,
138                                        textTitle.length());
139                  String test;
140                  if(ce.getTestOrTrain() == 0)
141                      test = "test";
142                  else
143                      test = "training";
144                  String resultT = "=== Evaluation result for "+test+" instances ===\n\n"
145                    + "Scheme: " + textTitle + "\n"
146                    + "Relation: " + ce.getTestSet().getDataSet().relationName()
147                    + "\n\n" + m_eval.clusterResultsToString();
148                  if(numericClass)
149                      resultT = resultT + "\n\nNo class based evaluation possible. Class attribute has to be nominal.";
150                  TextEvent te = 
151                    new TextEvent(ClustererPerformanceEvaluator.this, 
152                                  resultT,
153                                  textTitle);
154                  notifyTextListeners(te);
155                  if (m_logger != null) {
156                    m_logger.statusMessage(statusMessagePrefix() + "Finished.");
157                  }
158                }
159              } catch (Exception ex) {
160                // stop all processing
161                ClustererPerformanceEvaluator.this.stop();
162                if (m_logger != null) {
163                  m_logger.statusMessage(statusMessagePrefix()
164                      + "ERROR (see log for details");
165                  m_logger.logMessage("[ClustererPerformanceEvaluator] " 
166                      + statusMessagePrefix()
167                      + " problem while evaluating clusterer. " + ex.getMessage());
168                }
169                ex.printStackTrace();
170              } finally {
171//              m_visual.setText(oldText);
172                m_visual.setStatic();
173                m_evaluateThread = null;
174                if (isInterrupted()) {
175                  if (m_logger != null) {
176                    m_logger.logMessage("[" + getCustomName() 
177                        + "] Evaluation interrupted!");
178                    m_logger.statusMessage(statusMessagePrefix() 
179                        + "INTERRUPTED");
180                  }
181                }
182                block(false);
183              }
184            }
185          };
186        m_evaluateThread.setPriority(Thread.MIN_PRIORITY);
187        m_evaluateThread.start();
188
189        // make sure the thread is still running before we block
190        //      if (m_evaluateThread.isAlive()) {
191        block(true);
192          //    }
193        m_evaluateThread = null;
194      }
195    }  catch (Exception ex) {
196      ex.printStackTrace();
197    }
198  }
199 
200  /**
201   * Returns true if. at this time, the bean is busy with some
202   * (i.e. perhaps a worker thread is performing some calculation).
203   *
204   * @return true if the bean is busy.
205   */
206  public boolean isBusy() {
207    return (m_evaluateThread != null);
208  }
209
210  /**
211   * Try and stop any action
212   */
213  public void stop() {
214    // tell the listenee (upstream bean) to stop
215    if (m_listenee instanceof BeanCommon) {
216      //      System.err.println("Listener is BeanCommon");
217      ((BeanCommon)m_listenee).stop();
218    }
219
220    // stop the evaluate thread
221    if (m_evaluateThread != null) {
222      m_evaluateThread.interrupt();
223      m_evaluateThread.stop();
224      m_evaluateThread = null;
225      m_visual.setStatic();
226    }
227  }
228 
229  /**
230   * Function used to stop code that calls acceptClusterer. This is
231   * needed as clusterer evaluation is performed inside a separate
232   * thread of execution.
233   *
234   * @param tf a <code>boolean</code> value
235   */
236  private synchronized void block(boolean tf) {
237    if (tf) {
238      try {
239        // only block if thread is still doing something useful!
240        if (m_evaluateThread != null && m_evaluateThread.isAlive()) {
241          wait();
242        }
243      } catch (InterruptedException ex) {
244      }
245    } else {
246      notifyAll();
247    }
248  }
249
250  /**
251   * Return an enumeration of user activated requests for this bean
252   *
253   * @return an <code>Enumeration</code> value
254   */
255  public Enumeration enumerateRequests() {
256    Vector newVector = new Vector(0);
257    if (m_evaluateThread != null) {
258      newVector.addElement("Stop");
259    }
260    return newVector.elements();
261  }
262
263  /**
264   * Perform the named request
265   *
266   * @param request the request to perform
267   * @exception IllegalArgumentException if an error occurs
268   */
269  public void performRequest(String request) {
270    if (request.compareTo("Stop") == 0) {
271      stop();
272    } else {
273      throw new 
274        IllegalArgumentException(request
275
276                    + " not supported (ClustererPerformanceEvaluator)");
277    }
278  }
279
280  /**
281   * Add a text listener
282   *
283   * @param cl a <code>TextListener</code> value
284   */
285  public synchronized void addTextListener(TextListener cl) {
286    m_textListeners.addElement(cl);
287  }
288
289  /**
290   * Remove a text listener
291   *
292   * @param cl a <code>TextListener</code> value
293   */
294  public synchronized void removeTextListener(TextListener cl) {
295    m_textListeners.remove(cl);
296  }
297 
298  /**
299   * Notify all text listeners of a TextEvent
300   *
301   * @param te a <code>TextEvent</code> value
302   */
303  private void notifyTextListeners(TextEvent te) {
304    Vector l;
305    synchronized (this) {
306      l = (Vector)m_textListeners.clone();
307    }
308    if (l.size() > 0) {
309      for(int i = 0; i < l.size(); i++) {
310        //      System.err.println("Notifying text listeners "
311        //                         +"(ClustererPerformanceEvaluator)");
312        ((TextListener)l.elementAt(i)).acceptText(te);
313      }
314    }
315  }
316
317  /**
318   * Returns true, if at the current time, the named event could
319   * be generated. Assumes that supplied event names are names of
320   * events that could be generated by this bean.
321   *
322   * @param eventName the name of the event in question
323   * @return true if the named event could be generated at this point in
324   * time
325   */
326  public boolean eventGeneratable(String eventName) {
327    if (m_listenee == null) {
328      return false;
329    }
330
331    if (m_listenee instanceof EventConstraints) {
332      if (!((EventConstraints)m_listenee).
333          eventGeneratable("batchClusterer")) {
334        return false;
335      }
336    }
337    return true;
338  }
339 
340  private String statusMessagePrefix() {
341    return getCustomName() + "$" + hashCode() + "|";
342  }
343}
344
Note: See TracBrowser for help on using the repository browser.