/*
* 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);
}
}