/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * MOA.java * Copyright (C) 2009 University of Waikato, Hamilton, New Zealand */ package weka.classifiers.meta; import tr.gov.ulakbim.jDenetX.classifiers.Classifier; import tr.gov.ulakbim.jDenetX.classifiers.DecisionStump; import tr.gov.ulakbim.jDenetX.options.ClassOption; import weka.classifiers.UpdateableClassifier; import weka.core.*; import weka.core.Capabilities.Capability; import java.util.Enumeration; import java.util.Vector; /** <!-- globalinfo-start --> * Wrapper for MOA classifiers.<br/> * <br/> * Since MOA doesn't offer a mechanism to query a classifier for the types of attributes and classes it can handle, the capabilities of this wrapper are hard-coded: nominal and numeric attributes and only nominal class attributes are allowed. * <p/> <!-- globalinfo-end --> * <!-- options-start --> * Valid options are: <p/> * * <pre> -B <classname + options> * The MOA classifier to use. * (default: moa.classifiers.DecisionStump)</pre> * * <pre> -D * If set, classifier is run in debug mode and * may output additional info to the console</pre> * <!-- options-end --> * * @author fracpete (fracpete at waikato dot ac dot nz) * @version $Revision$ */ public class MOA extends weka.classifiers.AbstractClassifier implements UpdateableClassifier { /** for serialization. */ private static final long serialVersionUID = 2605797948130310166L; /** the actual moa classifier to use for learning. */ protected Classifier m_ActualClassifier = new DecisionStump(); /** the moa classifier option (this object is used in the GenericObjectEditor). */ protected ClassOption m_Classifier = new ClassOption( "classifier", 'B', "The MOA classifier to use from within WEKA.", Classifier.class, m_ActualClassifier.getClass().getSimpleName(), m_ActualClassifier.getClass().getName()); /** * Returns a string describing the classifier. * * @return a description suitable for * displaying in the explorer/experimenter gui */ public String globalInfo() { return "Wrapper for MOA classifiers.\n\n" + "Since MOA doesn't offer a mechanism to query a classifier for the " + "types of attributes and classes it can handle, the capabilities of " + "this wrapper are hard-coded: nominal and numeric attributes and " + "only nominal class attributes are allowed."; } /** * Returns an enumeration describing the available options. * * @return an enumeration of all the available options. */ public Enumeration listOptions() { Vector result = new Vector(); result.addElement(new Option( "\tThe MOA classifier to use.\n" + "\t(default: " + MOAUtils.toCommandLine(new DecisionStump()) + ")", "B", 1, "-B <classname + options>")); Enumeration en = super.listOptions(); while (en.hasMoreElements()) result.addElement(en.nextElement()); return result.elements(); } /** * Parses a given list of options. <p/> * <!-- options-start --> * Valid options are: <p/> * * <pre> -B <classname + options> * The MOA classifier to use. * (default: moa.classifiers.DecisionStump)</pre> * * <pre> -D * If set, classifier is run in debug mode and * may output additional info to the console</pre> * <!-- options-end --> * * @param options the list of options as an array of strings * @throws Exception if an option is not supported */ public void setOptions(String[] options) throws Exception { String tmpStr; ClassOption option; tmpStr = Utils.getOption('B', options); option = (ClassOption) m_Classifier.copy(); if (tmpStr.length() == 0) option.setCurrentObject(new DecisionStump()); else option.setCurrentObject(MOAUtils.fromCommandLine(m_Classifier, tmpStr)); setClassifier(option); super.setOptions(options); } /** * Gets the current settings of the Classifier. * * @return an array of strings suitable for passing to setOptions */ public String[] getOptions() { Vector<String> result; String[] options; int i; result = new Vector<String>(); result.add("-B"); result.add(MOAUtils.toCommandLine(m_ActualClassifier)); options = super.getOptions(); for (i = 0; i < options.length; i++) result.add(options[i]); return result.toArray(new String[result.size()]); } /** * Sets the MOA classifier to use. * * @param value the classifier to use */ public void setClassifier(ClassOption value) { m_Classifier = value; m_ActualClassifier = (Classifier) MOAUtils.fromOption(m_Classifier); } /** * Returns the current MOA classifier in use. * * @return the classifier in use */ public ClassOption getClassifier() { return m_Classifier; } /** * Returns the tooltip displayed in the GUI. * * @return the tooltip */ public String classifierTipText() { return "The MOA classifier to use."; } /** * Returns the Capabilities of this classifier. Maximally permissive * capabilities are allowed by default. MOA doesn't specify what * * @return the capabilities of this object * @see Capabilities */ public Capabilities getCapabilities() { Capabilities result = new Capabilities(this); // attributes result.enable(Capability.NOMINAL_ATTRIBUTES); result.enable(Capability.NUMERIC_ATTRIBUTES); result.enable(Capability.MISSING_VALUES); // class result.enable(Capability.NOMINAL_CLASS); result.enable(Capability.MISSING_CLASS_VALUES); result.setMinimumNumberInstances(0); return result; } /** * Generates a classifier. * * @param data set of instances serving as training data * @throws Exception if the classifier has not been * generated successfully */ public void buildClassifier(Instances data) throws Exception { getCapabilities().testWithFail(data); data = new Instances(data); data.deleteWithMissingClass(); m_ActualClassifier.resetLearning(); for (int i = 0; i < data.numInstances(); i++) updateClassifier(data.instance(i)); } /** * Updates a classifier using the given instance. * * @param instance the instance to included * @throws Exception if instance could not be incorporated * successfully */ public void updateClassifier(Instance instance) throws Exception { m_ActualClassifier.trainOnInstance(instance); } /** * Predicts the class memberships for a given instance. If * an instance is unclassified, the returned array elements * must be all zero. If the class is numeric, the array * must consist of only one element, which contains the * predicted value. * * @param instance the instance to be classified * @return an array containing the estimated membership * probabilities of the test instance in each class * or the numeric prediction * @throws Exception if distribution could not be * computed successfully */ public double[] distributionForInstance(Instance instance) throws Exception { double[] result; result = m_ActualClassifier.getVotesForInstance(instance); // ensure that the array has as many elements as there are // class values! if (result.length < instance.numClasses()) { double[] newResult = new double[instance.numClasses()]; System.arraycopy(result, 0, newResult, 0, result.length); result = newResult; } try { Utils.normalize(result); } catch (Exception e) { result = new double[instance.numClasses()]; } return result; } /** * Returns the revision string. * * @return the revision */ public String getRevision() { return RevisionUtils.extract("$Revision$"); } /** * Returns a string representation of the model. * * @return the string representation */ public String toString() { StringBuilder result; result = new StringBuilder(); m_ActualClassifier.getDescription(result, 0); return result.toString(); } /** * Main method for testing this class. * * @param args the options */ public static void main(String [] args) { runClassifier(new MOA(), args); } }