| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
| AbstractClassifier |
|
| 2.7142857142857144;2.714 |
| 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 3 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, see <http://www.gnu.org/licenses/>. | |
| 14 | */ | |
| 15 | ||
| 16 | /* | |
| 17 | * AbstractClassifier.java | |
| 18 | * Copyright (C) 1999-2012 University of Waikato, Hamilton, New Zealand | |
| 19 | * | |
| 20 | */ | |
| 21 | ||
| 22 | package weka.classifiers; | |
| 23 | ||
| 24 | import java.io.Serializable; | |
| 25 | import java.util.Enumeration; | |
| 26 | import java.util.Vector; | |
| 27 | ||
| 28 | import weka.core.Attribute; | |
| 29 | import weka.core.Capabilities; | |
| 30 | import weka.core.CapabilitiesHandler; | |
| 31 | import weka.core.Instance; | |
| 32 | import weka.core.Option; | |
| 33 | import weka.core.OptionHandler; | |
| 34 | import weka.core.RevisionHandler; | |
| 35 | import weka.core.RevisionUtils; | |
| 36 | import weka.core.SerializedObject; | |
| 37 | import weka.core.Utils; | |
| 38 | ||
| 39 | /** | |
| 40 | * Abstract classifier. All schemes for numeric or nominal prediction in | |
| 41 | * Weka extend this class. Note that a classifier MUST either implement | |
| 42 | * distributionForInstance() or classifyInstance(). | |
| 43 | * | |
| 44 | * @author Eibe Frank (eibe@cs.waikato.ac.nz) | |
| 45 | * @author Len Trigg (trigg@cs.waikato.ac.nz) | |
| 46 | * @version $Revision: 8034 $ | |
| 47 | */ | |
| 48 | 0 | public abstract class AbstractClassifier |
| 49 | implements Classifier, Cloneable, Serializable, OptionHandler, | |
| 50 | CapabilitiesHandler, RevisionHandler { | |
| 51 | ||
| 52 | /** for serialization */ | |
| 53 | private static final long serialVersionUID = 6502780192411755341L; | |
| 54 | ||
| 55 | /** Whether the classifier is run in debug mode. */ | |
| 56 | 0 | protected boolean m_Debug = false; |
| 57 | ||
| 58 | /** | |
| 59 | * Classifies the given test instance. The instance has to belong to a | |
| 60 | * dataset when it's being classified. Note that a classifier MUST | |
| 61 | * implement either this or distributionForInstance(). | |
| 62 | * | |
| 63 | * @param instance the instance to be classified | |
| 64 | * @return the predicted most likely class for the instance or | |
| 65 | * Utils.missingValue() if no prediction is made | |
| 66 | * @exception Exception if an error occurred during the prediction | |
| 67 | */ | |
| 68 | public double classifyInstance(Instance instance) throws Exception { | |
| 69 | ||
| 70 | 0 | double [] dist = distributionForInstance(instance); |
| 71 | 0 | if (dist == null) { |
| 72 | 0 | throw new Exception("Null distribution predicted"); |
| 73 | } | |
| 74 | 0 | switch (instance.classAttribute().type()) { |
| 75 | case Attribute.NOMINAL: | |
| 76 | 0 | double max = 0; |
| 77 | 0 | int maxIndex = 0; |
| 78 | ||
| 79 | 0 | for (int i = 0; i < dist.length; i++) { |
| 80 | 0 | if (dist[i] > max) { |
| 81 | 0 | maxIndex = i; |
| 82 | 0 | max = dist[i]; |
| 83 | } | |
| 84 | } | |
| 85 | 0 | if (max > 0) { |
| 86 | 0 | return maxIndex; |
| 87 | } else { | |
| 88 | 0 | return Utils.missingValue(); |
| 89 | } | |
| 90 | case Attribute.NUMERIC: | |
| 91 | 0 | return dist[0]; |
| 92 | default: | |
| 93 | 0 | return Utils.missingValue(); |
| 94 | } | |
| 95 | } | |
| 96 | ||
| 97 | /** | |
| 98 | * Predicts the class memberships for a given instance. If | |
| 99 | * an instance is unclassified, the returned array elements | |
| 100 | * must be all zero. If the class is numeric, the array | |
| 101 | * must consist of only one element, which contains the | |
| 102 | * predicted value. Note that a classifier MUST implement | |
| 103 | * either this or classifyInstance(). | |
| 104 | * | |
| 105 | * @param instance the instance to be classified | |
| 106 | * @return an array containing the estimated membership | |
| 107 | * probabilities of the test instance in each class | |
| 108 | * or the numeric prediction | |
| 109 | * @exception Exception if distribution could not be | |
| 110 | * computed successfully | |
| 111 | */ | |
| 112 | public double[] distributionForInstance(Instance instance) throws Exception { | |
| 113 | ||
| 114 | 0 | double[] dist = new double[instance.numClasses()]; |
| 115 | 0 | switch (instance.classAttribute().type()) { |
| 116 | case Attribute.NOMINAL: | |
| 117 | 0 | double classification = classifyInstance(instance); |
| 118 | 0 | if (Utils.isMissingValue(classification)) { |
| 119 | 0 | return dist; |
| 120 | } else { | |
| 121 | 0 | dist[(int)classification] = 1.0; |
| 122 | } | |
| 123 | 0 | return dist; |
| 124 | case Attribute.NUMERIC: | |
| 125 | 0 | dist[0] = classifyInstance(instance); |
| 126 | 0 | return dist; |
| 127 | default: | |
| 128 | 0 | return dist; |
| 129 | } | |
| 130 | } | |
| 131 | ||
| 132 | /** | |
| 133 | * Creates a new instance of a classifier given it's class name and | |
| 134 | * (optional) arguments to pass to it's setOptions method. If the | |
| 135 | * classifier implements OptionHandler and the options parameter is | |
| 136 | * non-null, the classifier will have it's options set. | |
| 137 | * | |
| 138 | * @param classifierName the fully qualified class name of the classifier | |
| 139 | * @param options an array of options suitable for passing to setOptions. May | |
| 140 | * be null. | |
| 141 | * @return the newly created classifier, ready for use. | |
| 142 | * @exception Exception if the classifier name is invalid, or the options | |
| 143 | * supplied are not acceptable to the classifier | |
| 144 | */ | |
| 145 | public static Classifier forName(String classifierName, | |
| 146 | String [] options) throws Exception { | |
| 147 | ||
| 148 | 0 | return ((AbstractClassifier)Utils.forName(Classifier.class, |
| 149 | classifierName, | |
| 150 | options)); | |
| 151 | } | |
| 152 | ||
| 153 | /** | |
| 154 | * Creates a deep copy of the given classifier using serialization. | |
| 155 | * | |
| 156 | * @param model the classifier to copy | |
| 157 | * @return a deep copy of the classifier | |
| 158 | * @exception Exception if an error occurs | |
| 159 | */ | |
| 160 | public static Classifier makeCopy(Classifier model) throws Exception { | |
| 161 | ||
| 162 | 0 | return (Classifier)new SerializedObject(model).getObject(); |
| 163 | } | |
| 164 | ||
| 165 | /** | |
| 166 | * Creates a given number of deep copies of the given classifier using serialization. | |
| 167 | * | |
| 168 | * @param model the classifier to copy | |
| 169 | * @param num the number of classifier copies to create. | |
| 170 | * @return an array of classifiers. | |
| 171 | * @exception Exception if an error occurs | |
| 172 | */ | |
| 173 | public static Classifier [] makeCopies(Classifier model, int num) throws Exception { | |
| 174 | ||
| 175 | 0 | if (model == null) { |
| 176 | 0 | throw new Exception("No model classifier set"); |
| 177 | } | |
| 178 | 0 | Classifier [] classifiers = new Classifier [num]; |
| 179 | 0 | SerializedObject so = new SerializedObject(model); |
| 180 | 0 | for(int i = 0; i < classifiers.length; i++) { |
| 181 | 0 | classifiers[i] = (Classifier) so.getObject(); |
| 182 | } | |
| 183 | 0 | return classifiers; |
| 184 | } | |
| 185 | ||
| 186 | /** | |
| 187 | * Returns an enumeration describing the available options. | |
| 188 | * | |
| 189 | * @return an enumeration of all the available options. | |
| 190 | */ | |
| 191 | public Enumeration listOptions() { | |
| 192 | ||
| 193 | 0 | Vector newVector = new Vector(1); |
| 194 | ||
| 195 | 0 | newVector.addElement(new Option( |
| 196 | "\tIf set, classifier is run in debug mode and\n" | |
| 197 | + "\tmay output additional info to the console", | |
| 198 | "D", 0, "-D")); | |
| 199 | 0 | return newVector.elements(); |
| 200 | } | |
| 201 | ||
| 202 | /** | |
| 203 | * Parses a given list of options. Valid options are:<p> | |
| 204 | * | |
| 205 | * -D <br> | |
| 206 | * If set, classifier is run in debug mode and | |
| 207 | * may output additional info to the console.<p> | |
| 208 | * | |
| 209 | * @param options the list of options as an array of strings | |
| 210 | * @exception Exception if an option is not supported | |
| 211 | */ | |
| 212 | public void setOptions(String[] options) throws Exception { | |
| 213 | ||
| 214 | 0 | setDebug(Utils.getFlag('D', options)); |
| 215 | 0 | } |
| 216 | ||
| 217 | /** | |
| 218 | * Gets the current settings of the Classifier. | |
| 219 | * | |
| 220 | * @return an array of strings suitable for passing to setOptions | |
| 221 | */ | |
| 222 | public String [] getOptions() { | |
| 223 | ||
| 224 | String [] options; | |
| 225 | 0 | if (getDebug()) { |
| 226 | 0 | options = new String[1]; |
| 227 | 0 | options[0] = "-D"; |
| 228 | } else { | |
| 229 | 0 | options = new String[0]; |
| 230 | } | |
| 231 | 0 | return options; |
| 232 | } | |
| 233 | ||
| 234 | /** | |
| 235 | * Set debugging mode. | |
| 236 | * | |
| 237 | * @param debug true if debug output should be printed | |
| 238 | */ | |
| 239 | public void setDebug(boolean debug) { | |
| 240 | ||
| 241 | 0 | m_Debug = debug; |
| 242 | 0 | } |
| 243 | ||
| 244 | /** | |
| 245 | * Get whether debugging is turned on. | |
| 246 | * | |
| 247 | * @return true if debugging output is on | |
| 248 | */ | |
| 249 | public boolean getDebug() { | |
| 250 | ||
| 251 | 0 | return m_Debug; |
| 252 | } | |
| 253 | ||
| 254 | /** | |
| 255 | * Returns the tip text for this property | |
| 256 | * @return tip text for this property suitable for | |
| 257 | * displaying in the explorer/experimenter gui | |
| 258 | */ | |
| 259 | public String debugTipText() { | |
| 260 | 0 | return "If set to true, classifier may output additional info to " + |
| 261 | "the console."; | |
| 262 | } | |
| 263 | ||
| 264 | /** | |
| 265 | * Returns the Capabilities of this classifier. Maximally permissive | |
| 266 | * capabilities are allowed by default. Derived classifiers should | |
| 267 | * override this method and first disable all capabilities and then | |
| 268 | * enable just those capabilities that make sense for the scheme. | |
| 269 | * | |
| 270 | * @return the capabilities of this object | |
| 271 | * @see Capabilities | |
| 272 | */ | |
| 273 | public Capabilities getCapabilities() { | |
| 274 | 0 | Capabilities result = new Capabilities(this); |
| 275 | 0 | result.enableAll(); |
| 276 | ||
| 277 | 0 | return result; |
| 278 | } | |
| 279 | ||
| 280 | /** | |
| 281 | * Returns the revision string. | |
| 282 | * | |
| 283 | * @return the revision | |
| 284 | */ | |
| 285 | public String getRevision() { | |
| 286 | 0 | return RevisionUtils.extract("$Revision: 8034 $"); |
| 287 | } | |
| 288 | ||
| 289 | /** | |
| 290 | * runs the classifier instance with the given options. | |
| 291 | * | |
| 292 | * @param classifier the classifier to run | |
| 293 | * @param options the commandline options | |
| 294 | */ | |
| 295 | public static void runClassifier(Classifier classifier, String[] options) { | |
| 296 | try { | |
| 297 | 0 | System.out.println(Evaluation.evaluateModel(classifier, options)); |
| 298 | } | |
| 299 | 0 | catch (Exception e) { |
| 300 | 0 | if ( ((e.getMessage() != null) && (e.getMessage().indexOf("General options") == -1)) |
| 301 | || (e.getMessage() == null) ) | |
| 302 | 0 | e.printStackTrace(); |
| 303 | else | |
| 304 | 0 | System.err.println(e.getMessage()); |
| 305 | 0 | } |
| 306 | 0 | } |
| 307 | } | |
| 308 |