source: src/main/java/weka/gui/beans/PredictionAppender.java @ 17

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

Import di weka.

File size: 30.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 *    PredictionAppender.java
19 *    Copyright (C) 2003 University of Waikato, Hamilton, New Zealand
20 *
21 */
22
23package weka.gui.beans;
24
25import weka.clusterers.DensityBasedClusterer;
26import weka.core.Instance;
27import weka.core.DenseInstance;
28import weka.core.Instances;
29
30import java.awt.BorderLayout;
31import java.beans.EventSetDescriptor;
32import java.io.Serializable;
33import java.util.Enumeration;
34import java.util.Vector;
35
36import javax.swing.JPanel;
37
38/**
39 * Bean that can can accept batch or incremental classifier events
40 * and produce dataset or instance events which contain instances with
41 * predictions appended.
42 *
43 * @author <a href="mailto:mhall@cs.waikato.ac.nz">Mark Hall</a>
44 * @version $Revision: 5987 $
45 */
46public class PredictionAppender
47  extends JPanel
48  implements DataSource, TrainingSetProducer, TestSetProducer, Visible, BeanCommon,
49             EventConstraints, BatchClassifierListener,
50             IncrementalClassifierListener, BatchClustererListener, Serializable {
51
52  /** for serialization */
53  private static final long serialVersionUID = -2987740065058976673L;
54
55  /**
56   * Objects listenening for dataset events
57   */
58  protected Vector m_dataSourceListeners = new Vector();
59
60  /**
61   * Objects listening for instances events
62   */
63  protected Vector m_instanceListeners = new Vector();
64 
65  /**
66   * Objects listening for training set events
67   */
68  protected Vector m_trainingSetListeners = new Vector();;
69 
70  /**
71   * Objects listening for test set events
72   */
73  protected Vector m_testSetListeners = new Vector();
74
75  /**
76   * Non null if this object is a target for any events.
77   */
78  protected Object m_listenee = null;
79
80  /**
81   * Format of instances to be produced.
82   */
83  protected Instances m_format;
84
85  protected BeanVisual m_visual = 
86    new BeanVisual("PredictionAppender", 
87                   BeanVisual.ICON_PATH+"PredictionAppender.gif",
88                   BeanVisual.ICON_PATH+"PredictionAppender_animated.gif");
89
90  /**
91   * Append classifier's predicted probabilities (if the class is discrete
92   * and the classifier is a distribution classifier)
93   */
94  protected boolean m_appendProbabilities;
95
96  protected transient weka.gui.Logger m_logger;
97
98  /**
99   * Global description of this bean
100   *
101   * @return a <code>String</code> value
102   */
103  public String globalInfo() {
104    return "Accepts batch or incremental classifier events and "
105      +"produces a new data set with classifier predictions appended.";
106  }
107
108  /**
109   * Creates a new <code>PredictionAppender</code> instance.
110   */
111  public PredictionAppender() {
112    setLayout(new BorderLayout());
113    add(m_visual, BorderLayout.CENTER);
114  }
115
116  /**
117   * Set a custom (descriptive) name for this bean
118   *
119   * @param name the name to use
120   */
121  public void setCustomName(String name) {
122    m_visual.setText(name);
123  }
124
125  /**
126   * Get the custom (descriptive) name for this bean (if one has been set)
127   *
128   * @return the custom name (or the default name)
129   */
130  public String getCustomName() {
131    return m_visual.getText();
132  }
133
134  /**
135   * Return a tip text suitable for displaying in a GUI
136   *
137   * @return a <code>String</code> value
138   */
139  public String appendPredictedProbabilitiesTipText() {
140    return "append probabilities rather than labels for discrete class "
141      +"predictions";
142  }
143
144  /**
145   * Return true if predicted probabilities are to be appended rather
146   * than class value
147   *
148   * @return a <code>boolean</code> value
149   */
150  public boolean getAppendPredictedProbabilities() {
151    return m_appendProbabilities;
152  }
153
154  /**
155   * Set whether to append predicted probabilities rather than
156   * class value (for discrete class data sets)
157   *
158   * @param ap a <code>boolean</code> value
159   */
160  public void setAppendPredictedProbabilities(boolean ap) {
161    m_appendProbabilities = ap;
162  }
163
164  /**
165   * Add a training set listener
166   *
167   * @param tsl a <code>TrainingSetListener</code> value
168   */
169  public void addTrainingSetListener(TrainingSetListener tsl) {
170    // TODO Auto-generated method stub
171    m_trainingSetListeners.addElement(tsl);
172    // pass on any format that we might have determined so far
173    if (m_format != null) {
174      TrainingSetEvent e = new TrainingSetEvent(this, m_format);
175      tsl.acceptTrainingSet(e);
176    }
177  }
178
179  /**
180   * Remove a training set listener
181   *
182   * @param tsl a <code>TrainingSetListener</code> value
183   */
184  public void removeTrainingSetListener(TrainingSetListener tsl) {   
185    m_trainingSetListeners.removeElement(tsl);
186  }
187
188  /**
189   * Add a test set listener
190   *
191   * @param tsl a <code>TestSetListener</code> value
192   */
193  public void addTestSetListener(TestSetListener tsl) {
194    m_testSetListeners.addElement(tsl);
195//  pass on any format that we might have determined so far
196    if (m_format != null) {
197      TestSetEvent e = new TestSetEvent(this, m_format);
198      tsl.acceptTestSet(e);
199    }
200  }
201
202  /**
203   * Remove a test set listener
204   *
205   * @param tsl a <code>TestSetListener</code> value
206   */
207  public void removeTestSetListener(TestSetListener tsl) {
208    m_testSetListeners.removeElement(tsl);
209  }
210 
211  /**
212   * Add a datasource listener
213   *
214   * @param dsl a <code>DataSourceListener</code> value
215   */
216  public synchronized void addDataSourceListener(DataSourceListener dsl) {
217    m_dataSourceListeners.addElement(dsl);
218    // pass on any format that we might have determined so far
219    if (m_format != null) {
220      DataSetEvent e = new DataSetEvent(this, m_format);
221      dsl.acceptDataSet(e);
222    }
223  }
224 
225  /**
226   * Remove a datasource listener
227   *
228   * @param dsl a <code>DataSourceListener</code> value
229   */
230  public synchronized void removeDataSourceListener(DataSourceListener dsl) {
231    m_dataSourceListeners.remove(dsl);
232  }
233
234  /**
235   * Add an instance listener
236   *
237   * @param dsl a <code>InstanceListener</code> value
238   */
239  public synchronized void addInstanceListener(InstanceListener dsl) {
240    m_instanceListeners.addElement(dsl);
241    // pass on any format that we might have determined so far
242    if (m_format != null) {
243      InstanceEvent e = new InstanceEvent(this, m_format);
244      dsl.acceptInstance(e);
245    }
246  }
247 
248  /**
249   * Remove an instance listener
250   *
251   * @param dsl a <code>InstanceListener</code> value
252   */
253  public synchronized void removeInstanceListener(InstanceListener dsl) {
254    m_instanceListeners.remove(dsl);
255  }
256
257  /**
258   * Set the visual for this data source
259   *
260   * @param newVisual a <code>BeanVisual</code> value
261   */
262  public void setVisual(BeanVisual newVisual) {
263    m_visual = newVisual;
264  }
265
266  /**
267   * Get the visual being used by this data source.
268   *
269   */
270  public BeanVisual getVisual() {
271    return m_visual;
272  }
273
274  /**
275   * Use the default images for a data source
276   *
277   */
278  public void useDefaultVisual() {
279    m_visual.loadIcons(BeanVisual.ICON_PATH+"PredictionAppender.gif",
280                       BeanVisual.ICON_PATH+"PredictionAppender_animated.gif");
281  }
282
283  protected InstanceEvent m_instanceEvent;
284
285 
286  /**
287   * Accept and process an incremental classifier event
288   *
289   * @param e an <code>IncrementalClassifierEvent</code> value
290   */
291  public void acceptClassifier(IncrementalClassifierEvent e) {
292    weka.classifiers.Classifier classifier = e.getClassifier();
293    Instance currentI = e.getCurrentInstance();
294    int status = e.getStatus();
295    int oldNumAtts = 0;
296    if (status == IncrementalClassifierEvent.NEW_BATCH) {
297      oldNumAtts = e.getStructure().numAttributes();
298    } else {
299      oldNumAtts = currentI.dataset().numAttributes();
300    }
301    if (status == IncrementalClassifierEvent.NEW_BATCH) {
302      m_instanceEvent = new InstanceEvent(this, null, 0);
303      // create new header structure
304      Instances oldStructure = new Instances(e.getStructure(), 0);
305      //String relationNameModifier = oldStructure.relationName()
306        //+"_with predictions";
307      String relationNameModifier = "_with predictions";
308        //+"_with predictions";
309       if (!m_appendProbabilities
310           || oldStructure.classAttribute().isNumeric()) {
311         try {
312           m_format = makeDataSetClass(oldStructure, oldStructure, classifier,
313                                                     relationNameModifier);
314         } catch (Exception ex) {
315           ex.printStackTrace();
316           return;
317         }
318       } else if (m_appendProbabilities) {
319         try {
320           m_format = 
321             makeDataSetProbabilities(oldStructure, oldStructure, classifier,
322                                      relationNameModifier);
323
324         } catch (Exception ex) {
325           ex.printStackTrace();
326           return;
327         }
328       }
329       // Pass on the structure
330       m_instanceEvent.setStructure(m_format);
331       notifyInstanceAvailable(m_instanceEvent);
332       return;
333    }
334
335    double[] instanceVals = new double [m_format.numAttributes()];
336    Instance newInst = null;
337    try {
338      // process the actual instance
339      for (int i = 0; i < oldNumAtts; i++) {
340        instanceVals[i] = currentI.value(i);
341      }
342      if (!m_appendProbabilities
343          || currentI.dataset().classAttribute().isNumeric()) {
344        double predClass = 
345          classifier.classifyInstance(currentI);
346        instanceVals[instanceVals.length - 1] = predClass;
347      } else if (m_appendProbabilities) {
348        double [] preds = classifier.distributionForInstance(currentI);
349        for (int i = oldNumAtts; i < instanceVals.length; i++) {
350          instanceVals[i] = preds[i-oldNumAtts];
351        }     
352      }     
353    } catch (Exception ex) {
354      ex.printStackTrace();
355      return;
356    } finally {
357      newInst = new DenseInstance(currentI.weight(), instanceVals);
358      newInst.setDataset(m_format);
359      m_instanceEvent.setInstance(newInst);
360      m_instanceEvent.setStatus(status);
361      // notify listeners
362      notifyInstanceAvailable(m_instanceEvent);
363    }
364
365    if (status == IncrementalClassifierEvent.BATCH_FINISHED) {
366      // clean up
367      //      m_incrementalStructure = null;
368      m_instanceEvent = null;
369    }
370  }
371
372  /**
373   * Accept and process a batch classifier event
374   *
375   * @param e a <code>BatchClassifierEvent</code> value
376   */
377  public void acceptClassifier(BatchClassifierEvent e) {
378    if (m_dataSourceListeners.size() > 0 
379        || m_trainingSetListeners.size() > 0
380        || m_testSetListeners.size() > 0) {
381
382      if (e.getTestSet() == null) {
383        // can't append predictions
384        return;
385      }
386
387      Instances testSet = e.getTestSet().getDataSet();
388      Instances trainSet = e.getTrainSet().getDataSet();
389      int setNum = e.getSetNumber();
390      int maxNum = e.getMaxSetNumber();
391
392      weka.classifiers.Classifier classifier = e.getClassifier();
393      String relationNameModifier = "_set_"+e.getSetNumber()+"_of_"
394        +e.getMaxSetNumber();
395      if (!m_appendProbabilities || testSet.classAttribute().isNumeric()) {
396        try {
397          Instances newTestSetInstances = makeDataSetClass(testSet, trainSet, 
398              classifier, relationNameModifier);
399          Instances newTrainingSetInstances = makeDataSetClass(trainSet, trainSet, 
400              classifier, relationNameModifier);
401         
402          if (m_trainingSetListeners.size() > 0) {
403            TrainingSetEvent tse = new TrainingSetEvent(this,
404                new Instances(newTrainingSetInstances, 0));
405            tse.m_setNumber = setNum;
406            tse.m_maxSetNumber = maxNum;
407            notifyTrainingSetAvailable(tse);
408            // fill in predicted values
409            for (int i = 0; i < trainSet.numInstances(); i++) {
410              double predClass = 
411                classifier.classifyInstance(trainSet.instance(i));
412              newTrainingSetInstances.instance(i).setValue(newTrainingSetInstances.numAttributes()-1,
413                  predClass);
414            }
415            tse = new TrainingSetEvent(this,
416                newTrainingSetInstances);
417            tse.m_setNumber = setNum;
418            tse.m_maxSetNumber = maxNum;
419            notifyTrainingSetAvailable(tse);
420          }
421         
422          if (m_testSetListeners.size() > 0) {
423            TestSetEvent tse = new TestSetEvent(this,
424                new Instances(newTestSetInstances, 0));
425            tse.m_setNumber = setNum;
426            tse.m_maxSetNumber = maxNum;
427            notifyTestSetAvailable(tse);
428          }
429          if (m_dataSourceListeners.size() > 0) {
430            notifyDataSetAvailable(new DataSetEvent(this, new Instances(newTestSetInstances,0)));
431          }
432          if (e.getTestSet().isStructureOnly()) {
433            m_format = newTestSetInstances;
434          }
435          if (m_dataSourceListeners.size() > 0 || m_testSetListeners.size() > 0) {
436            // fill in predicted values
437            for (int i = 0; i < testSet.numInstances(); i++) {
438              Instance tempInst = testSet.instance(i);
439             
440              // if the class value is missing, then copy the instance
441              // and set the data set to the training data. This is
442              // just in case this test data was loaded from a CSV file
443              // with all missing values for a nominal class (in this
444              // case we have no information on the legal class values
445              // in the test data)
446              if (tempInst.isMissing(tempInst.classIndex())) {
447                tempInst = (Instance)testSet.instance(i).copy();
448                tempInst.setDataset(trainSet);
449              }
450              double predClass = 
451                classifier.classifyInstance(tempInst);
452              newTestSetInstances.instance(i).setValue(newTestSetInstances.numAttributes()-1,
453                  predClass);
454            }
455          }
456          // notify listeners
457          if (m_testSetListeners.size() > 0) {
458            TestSetEvent tse = new TestSetEvent(this, newTestSetInstances);
459            tse.m_setNumber = setNum;
460            tse.m_maxSetNumber = maxNum;
461            notifyTestSetAvailable(tse);
462          }
463          if (m_dataSourceListeners.size() > 0) {
464            notifyDataSetAvailable(new DataSetEvent(this, newTestSetInstances));           
465          }
466          return;
467        } catch (Exception ex) {
468          ex.printStackTrace();
469        }
470      }
471      if (m_appendProbabilities) {
472        try {
473          Instances newTestSetInstances = 
474            makeDataSetProbabilities(testSet, trainSet,
475                                     classifier,relationNameModifier);
476          Instances newTrainingSetInstances = 
477            makeDataSetProbabilities(trainSet, trainSet,
478                                     classifier,relationNameModifier);
479          if (m_trainingSetListeners.size() > 0) {
480            TrainingSetEvent tse = new TrainingSetEvent(this,
481                new Instances(newTrainingSetInstances, 0));
482            tse.m_setNumber = setNum;
483            tse.m_maxSetNumber = maxNum;
484            notifyTrainingSetAvailable(tse);
485//          fill in predicted probabilities
486            for (int i = 0; i < trainSet.numInstances(); i++) {
487              double [] preds = classifier.
488              distributionForInstance(trainSet.instance(i));
489              for (int j = 0; j < trainSet.classAttribute().numValues(); j++) {
490                newTrainingSetInstances.instance(i).setValue(trainSet.numAttributes()+j,
491                    preds[j]);
492              }
493            }
494            tse = new TrainingSetEvent(this,
495                newTrainingSetInstances);
496            tse.m_setNumber = setNum;
497            tse.m_maxSetNumber = maxNum;
498            notifyTrainingSetAvailable(tse);
499          }
500          if (m_testSetListeners.size() > 0) {
501            TestSetEvent tse = new TestSetEvent(this,
502                new Instances(newTestSetInstances, 0));
503            tse.m_setNumber = setNum;
504            tse.m_maxSetNumber = maxNum;
505            notifyTestSetAvailable(tse);
506          }
507          if (m_dataSourceListeners.size() > 0) {
508            notifyDataSetAvailable(new DataSetEvent(this, new Instances(newTestSetInstances,0)));
509          }
510          if (e.getTestSet().isStructureOnly()) {
511            m_format = newTestSetInstances;
512          }
513          if (m_dataSourceListeners.size() > 0 || m_testSetListeners.size() > 0) {
514            // fill in predicted probabilities
515            for (int i = 0; i < testSet.numInstances(); i++) {
516              Instance tempInst = testSet.instance(i);
517             
518              // if the class value is missing, then copy the instance
519              // and set the data set to the training data. This is
520              // just in case this test data was loaded from a CSV file
521              // with all missing values for a nominal class (in this
522              // case we have no information on the legal class values
523              // in the test data)
524              if (tempInst.isMissing(tempInst.classIndex())) {
525                tempInst = (Instance)testSet.instance(i).copy();
526                tempInst.setDataset(trainSet);
527              }
528             
529              double [] preds = classifier.
530              distributionForInstance(tempInst);
531              for (int j = 0; j < tempInst.classAttribute().numValues(); j++) {
532                newTestSetInstances.instance(i).setValue(testSet.numAttributes()+j,
533                    preds[j]);
534              }
535            }
536          }
537         
538          // notify listeners
539          if (m_testSetListeners.size() > 0) {
540            TestSetEvent tse = new TestSetEvent(this, newTestSetInstances);
541            tse.m_setNumber = setNum;
542            tse.m_maxSetNumber = maxNum;
543            notifyTestSetAvailable(tse);
544          }
545          if (m_dataSourceListeners.size() > 0) {
546            notifyDataSetAvailable(new DataSetEvent(this, newTestSetInstances));
547          }
548        } catch (Exception ex) {
549          ex.printStackTrace();
550        }
551      }
552    }
553  }
554 
555 
556  /**
557   * Accept and process a batch clusterer event
558   *
559   * @param e a <code>BatchClassifierEvent</code> value
560   */
561  public void acceptClusterer(BatchClustererEvent e) {
562    if (m_dataSourceListeners.size() > 0
563        || m_trainingSetListeners.size() > 0
564        || m_testSetListeners.size() > 0) {
565
566      if(e.getTestSet().isStructureOnly()) {
567        return;
568      }
569      Instances testSet = e.getTestSet().getDataSet();
570
571      weka.clusterers.Clusterer clusterer = e.getClusterer();
572      String test;
573      if(e.getTestOrTrain() == 0) {
574        test = "test";
575      } else {
576        test = "training";
577      }
578      String relationNameModifier = "_"+test+"_"+e.getSetNumber()+"_of_"
579        +e.getMaxSetNumber();
580      if (!m_appendProbabilities || !(clusterer instanceof DensityBasedClusterer)) {
581        if(m_appendProbabilities && !(clusterer instanceof DensityBasedClusterer)){
582          System.err.println("Only density based clusterers can append probabilities. Instead cluster will be assigned for each instance.");
583          if (m_logger != null) {
584            m_logger.logMessage("[PredictionAppender] "
585                + statusMessagePrefix() + " Only density based clusterers can "
586                +"append probabilities. Instead cluster will be assigned for each "
587                +"instance.");
588            m_logger.statusMessage(statusMessagePrefix()
589                +"WARNING: Only density based clusterers can append probabilities. "
590                +"Instead cluster will be assigned for each instance.");
591          }
592        }
593        try {
594          Instances newInstances = makeClusterDataSetClass(testSet, clusterer,
595                                                           relationNameModifier);
596
597          // data source listeners get both train and test sets
598          if (m_dataSourceListeners.size() > 0) {
599            notifyDataSetAvailable(new DataSetEvent(this, new Instances(newInstances,0)));
600          }
601
602          if (m_trainingSetListeners.size() > 0 && e.getTestOrTrain() > 0) {
603             TrainingSetEvent tse = 
604               new TrainingSetEvent(this, new Instances(newInstances, 0));
605             tse.m_setNumber = e.getSetNumber();
606             tse.m_maxSetNumber = e.getMaxSetNumber();
607            notifyTrainingSetAvailable(tse);
608          }
609
610          if (m_testSetListeners.size() > 0 && e.getTestOrTrain() == 0) {
611             TestSetEvent tse = 
612               new TestSetEvent(this, new Instances(newInstances, 0));
613             tse.m_setNumber = e.getSetNumber();
614             tse.m_maxSetNumber = e.getMaxSetNumber();
615            notifyTestSetAvailable(tse);
616          }
617         
618          // fill in predicted values
619          for (int i = 0; i < testSet.numInstances(); i++) {
620            double predCluster = 
621              clusterer.clusterInstance(testSet.instance(i));
622            newInstances.instance(i).setValue(newInstances.numAttributes()-1,
623                                              predCluster);
624          }
625          // notify listeners
626          if (m_dataSourceListeners.size() > 0) {
627            notifyDataSetAvailable(new DataSetEvent(this, newInstances));
628          }
629          if (m_trainingSetListeners.size() > 0 && e.getTestOrTrain() > 0) {
630             TrainingSetEvent tse = 
631               new TrainingSetEvent(this, newInstances);
632             tse.m_setNumber = e.getSetNumber();
633             tse.m_maxSetNumber = e.getMaxSetNumber();
634            notifyTrainingSetAvailable(tse);
635          }
636          if (m_testSetListeners.size() > 0 && e.getTestOrTrain() == 0) {
637             TestSetEvent tse = 
638               new TestSetEvent(this, newInstances);
639             tse.m_setNumber = e.getSetNumber();
640             tse.m_maxSetNumber = e.getMaxSetNumber();
641            notifyTestSetAvailable(tse);
642          }
643
644          return;
645        } catch (Exception ex) {
646          ex.printStackTrace();
647        }
648      }
649      else{
650        try {
651          Instances newInstances = 
652            makeClusterDataSetProbabilities(testSet,
653                                            clusterer,relationNameModifier);
654          notifyDataSetAvailable(new DataSetEvent(this, new Instances(newInstances,0)));
655         
656          // fill in predicted probabilities
657          for (int i = 0; i < testSet.numInstances(); i++) {
658            double [] probs = clusterer.
659              distributionForInstance(testSet.instance(i));
660            for (int j = 0; j < clusterer.numberOfClusters(); j++) {
661              newInstances.instance(i).setValue(testSet.numAttributes()+j,
662                                                probs[j]);
663            }
664          }
665          // notify listeners
666          notifyDataSetAvailable(new DataSetEvent(this, newInstances));
667        } catch (Exception ex) {
668          ex.printStackTrace();
669        }
670      }
671    }
672  }
673
674  private Instances
675    makeDataSetProbabilities(Instances insts, Instances format,
676                             weka.classifiers.Classifier classifier,
677                             String relationNameModifier) 
678  throws Exception {
679    String classifierName = classifier.getClass().getName();
680    classifierName = classifierName.
681      substring(classifierName.lastIndexOf('.')+1, classifierName.length());
682    int numOrigAtts = insts.numAttributes();
683    Instances newInstances = new Instances(insts);
684    for (int i = 0; i < format.classAttribute().numValues(); i++) {
685      weka.filters.unsupervised.attribute.Add addF = new
686        weka.filters.unsupervised.attribute.Add();
687      addF.setAttributeIndex("last");
688      addF.setAttributeName(classifierName+"_prob_"+format.classAttribute().value(i));
689      addF.setInputFormat(newInstances);
690      newInstances = weka.filters.Filter.useFilter(newInstances, addF);
691    }
692    newInstances.setRelationName(insts.relationName()+relationNameModifier);
693    return newInstances;
694  }
695
696  private Instances makeDataSetClass(Instances insts, Instances structure,
697                                     weka.classifiers.Classifier classifier,
698                                     String relationNameModifier) 
699  throws Exception {
700   
701    weka.filters.unsupervised.attribute.Add addF = new
702      weka.filters.unsupervised.attribute.Add();
703    addF.setAttributeIndex("last");
704    String classifierName = classifier.getClass().getName();
705    classifierName = classifierName.
706      substring(classifierName.lastIndexOf('.')+1, classifierName.length());
707    addF.setAttributeName("class_predicted_by: "+classifierName);
708    if (structure.classAttribute().isNominal()) {
709      String classLabels = "";
710      Enumeration enu = structure.classAttribute().enumerateValues();
711      classLabels += (String)enu.nextElement();
712      while (enu.hasMoreElements()) {
713        classLabels += ","+(String)enu.nextElement();
714      }
715      addF.setNominalLabels(classLabels);
716    }
717    addF.setInputFormat(insts);
718
719
720    Instances newInstances = 
721      weka.filters.Filter.useFilter(insts, addF);
722    newInstances.setRelationName(insts.relationName()+relationNameModifier);
723    return newInstances;
724  }
725 
726  private Instances
727    makeClusterDataSetProbabilities(Instances format,
728                             weka.clusterers.Clusterer clusterer,
729                             String relationNameModifier) 
730  throws Exception {
731    int numOrigAtts = format.numAttributes();
732    Instances newInstances = new Instances(format);
733    for (int i = 0; i < clusterer.numberOfClusters(); i++) {
734      weka.filters.unsupervised.attribute.Add addF = new
735        weka.filters.unsupervised.attribute.Add();
736      addF.setAttributeIndex("last");
737      addF.setAttributeName("prob_cluster"+i);
738      addF.setInputFormat(newInstances);
739      newInstances = weka.filters.Filter.useFilter(newInstances, addF);
740    }
741    newInstances.setRelationName(format.relationName()+relationNameModifier);
742    return newInstances;
743  }
744
745  private Instances makeClusterDataSetClass(Instances format,
746                                     weka.clusterers.Clusterer clusterer,
747                                     String relationNameModifier) 
748  throws Exception {
749   
750    weka.filters.unsupervised.attribute.Add addF = new
751      weka.filters.unsupervised.attribute.Add();
752    addF.setAttributeIndex("last");
753    String clustererName = clusterer.getClass().getName();
754    clustererName = clustererName.
755      substring(clustererName.lastIndexOf('.')+1, clustererName.length());
756    addF.setAttributeName("assigned_cluster: "+clustererName);
757    //if (format.classAttribute().isNominal()) {
758    String clusterLabels = "0";
759      /*Enumeration enu = format.classAttribute().enumerateValues();
760      clusterLabels += (String)enu.nextElement();
761      while (enu.hasMoreElements()) {
762        clusterLabels += ","+(String)enu.nextElement();
763      }*/
764    for(int i = 1; i <= clusterer.numberOfClusters()-1; i++)
765        clusterLabels += ","+i;
766    addF.setNominalLabels(clusterLabels);
767    //}
768    addF.setInputFormat(format);
769
770
771    Instances newInstances = 
772      weka.filters.Filter.useFilter(format, addF);
773    newInstances.setRelationName(format.relationName()+relationNameModifier);
774    return newInstances;
775  }
776
777  /**
778   * Notify all instance listeners that an instance is available
779   *
780   * @param e an <code>InstanceEvent</code> value
781   */
782  protected void notifyInstanceAvailable(InstanceEvent e) {
783    Vector l;
784    synchronized (this) {
785      l = (Vector)m_instanceListeners.clone();
786    }
787   
788    if (l.size() > 0) {
789      for(int i = 0; i < l.size(); i++) {
790        ((InstanceListener)l.elementAt(i)).acceptInstance(e);
791      }
792    }
793  }
794
795  /**
796   * Notify all Data source listeners that a data set is available
797   *
798   * @param e a <code>DataSetEvent</code> value
799   */
800  protected void notifyDataSetAvailable(DataSetEvent e) {
801    Vector l;
802    synchronized (this) {
803      l = (Vector)m_dataSourceListeners.clone();
804    }
805   
806    if (l.size() > 0) {
807      for(int i = 0; i < l.size(); i++) {
808        ((DataSourceListener)l.elementAt(i)).acceptDataSet(e);
809      }
810    }
811  }
812 
813  /**
814   * Notify all test set listeners that a test set is available
815   *
816   * @param e a <code>TestSetEvent</code> value
817   */
818  protected void notifyTestSetAvailable(TestSetEvent e) {
819    Vector l;
820    synchronized (this) {
821      l = (Vector)m_testSetListeners.clone();
822    }
823   
824    if (l.size() > 0) {
825      for(int i = 0; i < l.size(); i++) {
826        ((TestSetListener)l.elementAt(i)).acceptTestSet(e);
827      }
828    }
829  }
830 
831  /**
832   * Notify all test set listeners that a test set is available
833   *
834   * @param e a <code>TestSetEvent</code> value
835   */
836  protected void notifyTrainingSetAvailable(TrainingSetEvent e) {
837    Vector l;
838    synchronized (this) {
839      l = (Vector)m_trainingSetListeners.clone();
840    }
841   
842    if (l.size() > 0) {
843      for(int i = 0; i < l.size(); i++) {
844        ((TrainingSetListener)l.elementAt(i)).acceptTrainingSet(e);
845      }
846    }
847  }
848
849  /**
850   * Set a logger
851   *
852   * @param logger a <code>weka.gui.Logger</code> value
853   */
854  public void setLog(weka.gui.Logger logger) {
855    m_logger = logger;
856  }
857
858  public void stop() {
859    // tell the listenee (upstream bean) to stop
860    if (m_listenee instanceof BeanCommon) {
861      ((BeanCommon)m_listenee).stop();
862    }
863  }
864 
865  /**
866   * Returns true if. at this time, the bean is busy with some
867   * (i.e. perhaps a worker thread is performing some calculation).
868   *
869   * @return true if the bean is busy.
870   */
871  public boolean isBusy() {
872    return false;
873  }
874
875  /**
876   * Returns true if, at this time,
877   * the object will accept a connection according to the supplied
878   * event name
879   *
880   * @param eventName the event
881   * @return true if the object will accept a connection
882   */
883  public boolean connectionAllowed(String eventName) {
884    return (m_listenee == null);
885  }
886
887  /**
888   * Returns true if, at this time,
889   * the object will accept a connection according to the supplied
890   * EventSetDescriptor
891   *
892   * @param esd the EventSetDescriptor
893   * @return true if the object will accept a connection
894   */
895  public boolean connectionAllowed(EventSetDescriptor esd) {
896    return connectionAllowed(esd.getName());
897  }
898
899  /**
900   * Notify this object that it has been registered as a listener with
901   * a source with respect to the supplied event name
902   *
903   * @param eventName
904   * @param source the source with which this object has been registered as
905   * a listener
906   */
907  public synchronized void connectionNotification(String eventName,
908                                                  Object source) {
909    if (connectionAllowed(eventName)) {
910      m_listenee = source;
911    }
912  }
913
914  /**
915   * Notify this object that it has been deregistered as a listener with
916   * a source with respect to the supplied event name
917   *
918   * @param eventName the event name
919   * @param source the source with which this object has been registered as
920   * a listener
921   */
922  public synchronized void disconnectionNotification(String eventName,
923                                                     Object source) {
924    if (m_listenee == source) {
925      m_listenee = null;
926      m_format = null; // assume any calculated instance format if now invalid
927    }
928  }
929
930  /**
931   * Returns true, if at the current time, the named event could
932   * be generated. Assumes that supplied event names are names of
933   * events that could be generated by this bean.
934   *
935   * @param eventName the name of the event in question
936   * @return true if the named event could be generated at this point in
937   * time
938   */
939  public boolean eventGeneratable(String eventName) {
940    if (m_listenee == null) {
941      return false;
942    }
943
944    if (m_listenee instanceof EventConstraints) {
945      if (eventName.equals("instance")) {
946        if (!((EventConstraints)m_listenee).
947            eventGeneratable("incrementalClassifier")) {
948          return false;
949        }
950      }
951      if (eventName.equals("dataSet") 
952          || eventName.equals("trainingSet") 
953          || eventName.equals("testSet")) {
954        if (((EventConstraints)m_listenee).
955            eventGeneratable("batchClassifier")) {
956          return true;
957        }
958        if (((EventConstraints)m_listenee).eventGeneratable("batchClusterer")) {
959          return true;
960        }
961        return false;
962      }
963    }
964    return true;
965  }
966 
967  private String statusMessagePrefix() {
968    return getCustomName() + "$" + hashCode() + "|";
969  }
970}
Note: See TracBrowser for help on using the repository browser.