~ubuntu-branches/ubuntu/trusty/weka/trusty-proposed

« back to all changes in this revision

Viewing changes to weka/classifiers/rules/OneR.java

  • Committer: Bazaar Package Importer
  • Author(s): Soeren Sonnenburg
  • Date: 2008-02-24 09:18:45 UTC
  • Revision ID: james.westby@ubuntu.com-20080224091845-1l8zy6fm6xipbzsr
Tags: upstream-3.5.7+tut1
ImportĀ upstreamĀ versionĀ 3.5.7+tut1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 *    OneR.java
 
19
 *    Copyright (C) 1999 University of Waikato, Hamilton, New Zealand
 
20
 *
 
21
 */
 
22
 
 
23
package weka.classifiers.rules;
 
24
 
 
25
import weka.classifiers.Classifier;
 
26
import weka.classifiers.Sourcable;
 
27
import weka.core.Attribute;
 
28
import weka.core.Capabilities;
 
29
import weka.core.Instance;
 
30
import weka.core.Instances;
 
31
import weka.core.Option;
 
32
import weka.core.TechnicalInformation;
 
33
import weka.core.TechnicalInformationHandler;
 
34
import weka.core.Utils;
 
35
import weka.core.WekaException;
 
36
import weka.core.Capabilities.Capability;
 
37
import weka.core.TechnicalInformation.Field;
 
38
import weka.core.TechnicalInformation.Type;
 
39
 
 
40
import java.io.Serializable;
 
41
import java.util.Enumeration;
 
42
import java.util.Vector;
 
43
 
 
44
/**
 
45
 <!-- globalinfo-start -->
 
46
 * Class for building and using a 1R classifier; in other words, uses the minimum-error attribute for prediction, discretizing numeric attributes. For more information, see:<br/>
 
47
 * <br/>
 
48
 * R.C. Holte (1993). Very simple classification rules perform well on most commonly used datasets. Machine Learning. 11:63-91.
 
49
 * <p/>
 
50
 <!-- globalinfo-end -->
 
51
 *
 
52
 <!-- technical-bibtex-start -->
 
53
 * BibTeX:
 
54
 * <pre>
 
55
 * &#64;article{Holte1993,
 
56
 *    author = {R.C. Holte},
 
57
 *    journal = {Machine Learning},
 
58
 *    pages = {63-91},
 
59
 *    title = {Very simple classification rules perform well on most commonly used datasets},
 
60
 *    volume = {11},
 
61
 *    year = {1993}
 
62
 * }
 
63
 * </pre>
 
64
 * <p/>
 
65
 <!-- technical-bibtex-end -->
 
66
 *
 
67
 <!-- options-start -->
 
68
 * Valid options are: <p/>
 
69
 * 
 
70
 * <pre> -B &lt;minimum bucket size&gt;
 
71
 *  The minimum number of objects in a bucket (default: 6).</pre>
 
72
 * 
 
73
 <!-- options-end -->
 
74
 * 
 
75
 * @author Ian H. Witten (ihw@cs.waikato.ac.nz)
 
76
 * @version $Revision: 1.25 $ 
 
77
*/
 
78
public class OneR 
 
79
  extends Classifier 
 
80
  implements TechnicalInformationHandler, Sourcable {
 
81
    
 
82
  /** for serialization */
 
83
  static final long serialVersionUID = -2459427002147861445L;
 
84
  
 
85
  /**
 
86
   * Returns a string describing classifier
 
87
   * @return a description suitable for
 
88
   * displaying in the explorer/experimenter gui
 
89
   */
 
90
  public String globalInfo() {
 
91
 
 
92
    return "Class for building and using a 1R classifier; in other words, uses "
 
93
      + "the minimum-error attribute for prediction, discretizing numeric "
 
94
      + "attributes. For more information, see:\n\n"
 
95
      + getTechnicalInformation().toString();
 
96
  }
 
97
 
 
98
  /**
 
99
   * Returns an instance of a TechnicalInformation object, containing 
 
100
   * detailed information about the technical background of this class,
 
101
   * e.g., paper reference or book this class is based on.
 
102
   * 
 
103
   * @return the technical information about this class
 
104
   */
 
105
  public TechnicalInformation getTechnicalInformation() {
 
106
    TechnicalInformation        result;
 
107
    
 
108
    result = new TechnicalInformation(Type.ARTICLE);
 
109
    result.setValue(Field.AUTHOR, "R.C. Holte");
 
110
    result.setValue(Field.YEAR, "1993");
 
111
    result.setValue(Field.TITLE, "Very simple classification rules perform well on most commonly used datasets");
 
112
    result.setValue(Field.JOURNAL, "Machine Learning");
 
113
    result.setValue(Field.VOLUME, "11");
 
114
    result.setValue(Field.PAGES, "63-91");
 
115
    
 
116
    return result;
 
117
  }
 
118
 
 
119
  /**
 
120
   * Class for storing store a 1R rule.
 
121
   */
 
122
  private class OneRRule 
 
123
    implements Serializable {
 
124
    
 
125
    /** for serialization */
 
126
    static final long serialVersionUID = 1152814630957092281L;
 
127
 
 
128
    /** The class attribute. */
 
129
    private Attribute m_class;
 
130
 
 
131
    /** The number of instances used for building the rule. */
 
132
    private int m_numInst;
 
133
 
 
134
    /** Attribute to test */
 
135
    private Attribute m_attr; 
 
136
 
 
137
    /** Training set examples this rule gets right */
 
138
    private int m_correct; 
 
139
 
 
140
    /** Predicted class for each value of attr */
 
141
    private int[] m_classifications; 
 
142
 
 
143
    /** Predicted class for missing values */
 
144
    private int m_missingValueClass = -1; 
 
145
 
 
146
    /** Breakpoints (numeric attributes only) */
 
147
    private double[] m_breakpoints; 
 
148
  
 
149
    /**
 
150
     * Constructor for nominal attribute.
 
151
     * 
 
152
     * @param data the data to work with
 
153
     * @param attribute the attribute to use
 
154
     * @throws Exception if something goes wrong
 
155
     */
 
156
    public OneRRule(Instances data, Attribute attribute) throws Exception {
 
157
 
 
158
      m_class = data.classAttribute();
 
159
      m_numInst = data.numInstances();
 
160
      m_attr = attribute;
 
161
      m_correct = 0;
 
162
      m_classifications = new int[m_attr.numValues()];
 
163
    }
 
164
 
 
165
    /**
 
166
     * Constructor for numeric attribute.
 
167
     * 
 
168
     * @param data the data to work with
 
169
     * @param attribute the attribute to use
 
170
     * @param nBreaks the break point
 
171
     * @throws Exception if something goes wrong
 
172
     */
 
173
    public OneRRule(Instances data, Attribute attribute, int nBreaks) throws Exception {
 
174
 
 
175
      m_class = data.classAttribute();
 
176
      m_numInst = data.numInstances();
 
177
      m_attr = attribute;
 
178
      m_correct = 0;
 
179
      m_classifications = new int[nBreaks];
 
180
      m_breakpoints = new double[nBreaks - 1]; // last breakpoint is infinity
 
181
    }
 
182
    
 
183
    /**
 
184
     * Returns a description of the rule.
 
185
     * 
 
186
     * @return a string representation of the rule
 
187
     */
 
188
    public String toString() {
 
189
 
 
190
      try {
 
191
        StringBuffer text = new StringBuffer();
 
192
        text.append(m_attr.name() + ":\n");
 
193
        for (int v = 0; v < m_classifications.length; v++) {
 
194
          text.append("\t");
 
195
          if (m_attr.isNominal()) {
 
196
            text.append(m_attr.value(v));
 
197
          } else if (v < m_breakpoints.length) {
 
198
            text.append("< " + m_breakpoints[v]);
 
199
          } else if (v > 0) {
 
200
            text.append(">= " + m_breakpoints[v - 1]);
 
201
          } else {
 
202
            text.append("not ?");
 
203
          }
 
204
          text.append("\t-> " + m_class.value(m_classifications[v]) + "\n");
 
205
        }
 
206
        if (m_missingValueClass != -1) {
 
207
          text.append("\t?\t-> " + m_class.value(m_missingValueClass) + "\n");
 
208
        }
 
209
        text.append("(" + m_correct + "/" + m_numInst + " instances correct)\n");
 
210
        return text.toString();
 
211
      } catch (Exception e) {
 
212
        return "Can't print OneR classifier!";
 
213
      }
 
214
    }
 
215
  }
 
216
  
 
217
  /** A 1-R rule */
 
218
  private OneRRule m_rule;
 
219
 
 
220
  /** The minimum bucket size */
 
221
  private int m_minBucketSize = 6;
 
222
 
 
223
  /** a ZeroR model in case no model can be built from the data */
 
224
  private Classifier m_ZeroR;
 
225
    
 
226
  /**
 
227
   * Classifies a given instance.
 
228
   *
 
229
   * @param inst the instance to be classified
 
230
   * @return the classification of the instance
 
231
   */
 
232
  public double classifyInstance(Instance inst) throws Exception {
 
233
 
 
234
    // default model?
 
235
    if (m_ZeroR != null) {
 
236
      return m_ZeroR.classifyInstance(inst);
 
237
    }
 
238
    
 
239
    int v = 0;
 
240
    if (inst.isMissing(m_rule.m_attr)) {
 
241
      if (m_rule.m_missingValueClass != -1) {
 
242
        return m_rule.m_missingValueClass;
 
243
      } else {
 
244
        return 0;  // missing values occur in test but not training set    
 
245
      }
 
246
    }
 
247
    if (m_rule.m_attr.isNominal()) {
 
248
      v = (int) inst.value(m_rule.m_attr);
 
249
    } else {
 
250
      while (v < m_rule.m_breakpoints.length &&
 
251
             inst.value(m_rule.m_attr) >= m_rule.m_breakpoints[v]) {
 
252
        v++;
 
253
      }
 
254
    }
 
255
    return m_rule.m_classifications[v];
 
256
  }
 
257
 
 
258
  /**
 
259
   * Returns default capabilities of the classifier.
 
260
   *
 
261
   * @return      the capabilities of this classifier
 
262
   */
 
263
  public Capabilities getCapabilities() {
 
264
    Capabilities result = super.getCapabilities();
 
265
 
 
266
    // attributes
 
267
    result.enable(Capability.NOMINAL_ATTRIBUTES);
 
268
    result.enable(Capability.NUMERIC_ATTRIBUTES);
 
269
    result.enable(Capability.DATE_ATTRIBUTES);
 
270
    result.enable(Capability.MISSING_VALUES);
 
271
 
 
272
    // class
 
273
    result.enable(Capability.NOMINAL_CLASS);
 
274
    result.enable(Capability.MISSING_CLASS_VALUES);
 
275
 
 
276
    return result;
 
277
  }
 
278
 
 
279
  /**
 
280
   * Generates the classifier.
 
281
   *
 
282
   * @param instances the instances to be used for building the classifier
 
283
   * @throws Exception if the classifier can't be built successfully
 
284
   */
 
285
  public void buildClassifier(Instances instances) 
 
286
    throws Exception {
 
287
    
 
288
    boolean noRule = true;
 
289
 
 
290
    // can classifier handle the data?
 
291
    getCapabilities().testWithFail(instances);
 
292
 
 
293
    // remove instances with missing class
 
294
    Instances data = new Instances(instances);
 
295
    data.deleteWithMissingClass();
 
296
 
 
297
    // only class? -> build ZeroR model
 
298
    if (data.numAttributes() == 1) {
 
299
      System.err.println(
 
300
          "Cannot build model (only class attribute present in data!), "
 
301
          + "using ZeroR model instead!");
 
302
      m_ZeroR = new weka.classifiers.rules.ZeroR();
 
303
      m_ZeroR.buildClassifier(data);
 
304
      return;
 
305
    }
 
306
    else {
 
307
      m_ZeroR = null;
 
308
    }
 
309
    
 
310
    // for each attribute ...
 
311
    Enumeration enu = instances.enumerateAttributes();
 
312
    while (enu.hasMoreElements()) {
 
313
      try {
 
314
        OneRRule r = newRule((Attribute) enu.nextElement(), data);
 
315
 
 
316
        // if this attribute is the best so far, replace the rule
 
317
        if (noRule || r.m_correct > m_rule.m_correct) {
 
318
          m_rule = r;
 
319
        }
 
320
        noRule = false;
 
321
      } catch (Exception ex) {
 
322
      }
 
323
    }
 
324
    
 
325
    if (noRule)
 
326
      throw new WekaException("No attributes found to work with!");
 
327
  }
 
328
 
 
329
  /**
 
330
   * Create a rule branching on this attribute.
 
331
   *
 
332
   * @param attr the attribute to branch on
 
333
   * @param data the data to be used for creating the rule
 
334
   * @return the generated rule
 
335
   * @throws Exception if the rule can't be built successfully
 
336
   */
 
337
  public OneRRule newRule(Attribute attr, Instances data) throws Exception {
 
338
 
 
339
    OneRRule r;
 
340
 
 
341
    // ... create array to hold the missing value counts
 
342
    int[] missingValueCounts =
 
343
      new int [data.classAttribute().numValues()];
 
344
    
 
345
    if (attr.isNominal()) {
 
346
      r = newNominalRule(attr, data, missingValueCounts);
 
347
    } else {
 
348
      r = newNumericRule(attr, data, missingValueCounts);
 
349
    }
 
350
    r.m_missingValueClass = Utils.maxIndex(missingValueCounts);
 
351
    if (missingValueCounts[r.m_missingValueClass] == 0) {
 
352
      r.m_missingValueClass = -1; // signal for no missing value class
 
353
    } else {
 
354
      r.m_correct += missingValueCounts[r.m_missingValueClass];
 
355
    }
 
356
    return r;
 
357
  }
 
358
 
 
359
  /**
 
360
   * Create a rule branching on this nominal attribute.
 
361
   *
 
362
   * @param attr the attribute to branch on
 
363
   * @param data the data to be used for creating the rule
 
364
   * @param missingValueCounts to be filled in
 
365
   * @return the generated rule
 
366
   * @throws Exception if the rule can't be built successfully
 
367
   */
 
368
  public OneRRule newNominalRule(Attribute attr, Instances data,
 
369
                                 int[] missingValueCounts) throws Exception {
 
370
 
 
371
    // ... create arrays to hold the counts
 
372
    int[][] counts = new int [attr.numValues()]
 
373
                             [data.classAttribute().numValues()];
 
374
      
 
375
    // ... calculate the counts
 
376
    Enumeration enu = data.enumerateInstances();
 
377
    while (enu.hasMoreElements()) {
 
378
      Instance i = (Instance) enu.nextElement();
 
379
      if (i.isMissing(attr)) {
 
380
        missingValueCounts[(int) i.classValue()]++; 
 
381
      } else {
 
382
        counts[(int) i.value(attr)][(int) i.classValue()]++;
 
383
      }
 
384
    }
 
385
 
 
386
    OneRRule r = new OneRRule(data, attr); // create a new rule
 
387
    for (int value = 0; value < attr.numValues(); value++) {
 
388
      int best = Utils.maxIndex(counts[value]);
 
389
      r.m_classifications[value] = best;
 
390
      r.m_correct += counts[value][best];
 
391
    }
 
392
    return r;
 
393
  }
 
394
 
 
395
  /**
 
396
   * Create a rule branching on this numeric attribute
 
397
   *
 
398
   * @param attr the attribute to branch on
 
399
   * @param data the data to be used for creating the rule
 
400
   * @param missingValueCounts to be filled in
 
401
   * @return the generated rule
 
402
   * @throws Exception if the rule can't be built successfully
 
403
   */
 
404
  public OneRRule newNumericRule(Attribute attr, Instances data,
 
405
                             int[] missingValueCounts) throws Exception {
 
406
 
 
407
 
 
408
    // ... can't be more than numInstances buckets
 
409
    int [] classifications = new int[data.numInstances()];
 
410
    double [] breakpoints = new double[data.numInstances()];
 
411
 
 
412
    // create array to hold the counts
 
413
    int [] counts = new int[data.classAttribute().numValues()];
 
414
    int correct = 0;
 
415
    int lastInstance = data.numInstances();
 
416
 
 
417
    // missing values get sorted to the end of the instances
 
418
    data.sort(attr);
 
419
    while (lastInstance > 0 && 
 
420
           data.instance(lastInstance-1).isMissing(attr)) {
 
421
      lastInstance--;
 
422
      missingValueCounts[(int) data.instance(lastInstance).
 
423
                         classValue()]++; 
 
424
    }
 
425
    int i = 0; 
 
426
    int cl = 0; // index of next bucket to create
 
427
    int it;
 
428
    while (i < lastInstance) { // start a new bucket
 
429
      for (int j = 0; j < counts.length; j++) counts[j] = 0;
 
430
      do { // fill it until it has enough of the majority class
 
431
        it = (int) data.instance(i++).classValue();
 
432
        counts[it]++;
 
433
      } while (counts[it] < m_minBucketSize && i < lastInstance);
 
434
 
 
435
      // while class remains the same, keep on filling
 
436
      while (i < lastInstance && 
 
437
             (int) data.instance(i).classValue() == it) { 
 
438
        counts[it]++; 
 
439
        i++;
 
440
      }
 
441
      while (i < lastInstance && // keep on while attr value is the same
 
442
             (data.instance(i - 1).value(attr) 
 
443
              == data.instance(i).value(attr))) {
 
444
        counts[(int) data.instance(i++).classValue()]++;
 
445
      }
 
446
      for (int j = 0; j < counts.length; j++) {
 
447
        if (counts[j] > counts[it]) { 
 
448
          it = j;
 
449
        }
 
450
      }
 
451
      if (cl > 0) { // can we coalesce with previous class?
 
452
        if (counts[classifications[cl - 1]] == counts[it]) {
 
453
          it = classifications[cl - 1];
 
454
        }
 
455
        if (it == classifications[cl - 1]) {
 
456
          cl--; // yes!
 
457
        }
 
458
      }
 
459
      correct += counts[it];
 
460
      classifications[cl] = it;
 
461
      if (i < lastInstance) {
 
462
        breakpoints[cl] = (data.instance(i - 1).value(attr)
 
463
                           + data.instance(i).value(attr)) / 2;
 
464
      }
 
465
      cl++;
 
466
    }
 
467
    if (cl == 0) {
 
468
      throw new Exception("Only missing values in the training data!");
 
469
    }
 
470
    OneRRule r = new OneRRule(data, attr, cl); // new rule with cl branches
 
471
    r.m_correct = correct;
 
472
    for (int v = 0; v < cl; v++) {
 
473
      r.m_classifications[v] = classifications[v];
 
474
      if (v < cl-1) {
 
475
        r.m_breakpoints[v] = breakpoints[v];
 
476
      }
 
477
    }
 
478
 
 
479
    return r;
 
480
  }
 
481
 
 
482
  /**
 
483
   * Returns an enumeration describing the available options..
 
484
   *
 
485
   * @return an enumeration of all the available options.
 
486
   */
 
487
  public Enumeration listOptions() {
 
488
 
 
489
    String string = "\tThe minimum number of objects in a bucket (default: 6).";
 
490
 
 
491
    Vector newVector = new Vector(1);
 
492
 
 
493
    newVector.addElement(new Option(string, "B", 1, 
 
494
                                    "-B <minimum bucket size>"));
 
495
 
 
496
    return newVector.elements();
 
497
  }
 
498
 
 
499
  /**
 
500
   * Parses a given list of options. <p/>
 
501
   *
 
502
   <!-- options-start -->
 
503
   * Valid options are: <p/>
 
504
   * 
 
505
   * <pre> -B &lt;minimum bucket size&gt;
 
506
   *  The minimum number of objects in a bucket (default: 6).</pre>
 
507
   * 
 
508
   <!-- options-end -->
 
509
   *
 
510
   * @param options the list of options as an array of strings
 
511
   * @throws Exception if an option is not supported
 
512
   */
 
513
  public void setOptions(String[] options) throws Exception {
 
514
    
 
515
    String bucketSizeString = Utils.getOption('B', options);
 
516
    if (bucketSizeString.length() != 0) {
 
517
      m_minBucketSize = Integer.parseInt(bucketSizeString);
 
518
    } else {
 
519
      m_minBucketSize = 6;
 
520
    }
 
521
  }
 
522
 
 
523
  /**
 
524
   * Gets the current settings of the OneR classifier.
 
525
   *
 
526
   * @return an array of strings suitable for passing to setOptions
 
527
   */
 
528
  public String [] getOptions() {
 
529
 
 
530
    String [] options = new String [2];
 
531
    int current = 0;
 
532
 
 
533
    options[current++] = "-B"; options[current++] = "" + m_minBucketSize;
 
534
 
 
535
    while (current < options.length) {
 
536
      options[current++] = "";
 
537
    }
 
538
    return options;
 
539
  }
 
540
 
 
541
  /**
 
542
   * Returns a string that describes the classifier as source. The
 
543
   * classifier will be contained in a class with the given name (there may
 
544
   * be auxiliary classes),
 
545
   * and will contain a method with the signature:
 
546
   * <pre><code>
 
547
   * public static double classify(Object[] i);
 
548
   * </code></pre>
 
549
   * where the array <code>i</code> contains elements that are either
 
550
   * Double, String, with missing values represented as null. The generated
 
551
   * code is public domain and comes with no warranty.
 
552
   *
 
553
   * @param className the name that should be given to the source class.
 
554
   * @return the object source described by a string
 
555
   * @throws Exception if the souce can't be computed
 
556
   */
 
557
  public String toSource(String className) throws Exception {
 
558
    StringBuffer        result;
 
559
    int                 i;
 
560
    
 
561
    result = new StringBuffer();
 
562
    
 
563
    if (m_ZeroR != null) {
 
564
      result.append(((ZeroR) m_ZeroR).toSource(className));
 
565
    }
 
566
    else {
 
567
      result.append("class " + className + " {\n");
 
568
      result.append("  public static double classify(Object[] i) {\n");
 
569
      result.append("    // chosen attribute: " + m_rule.m_attr.name() + " (" + m_rule.m_attr.index() + ")\n");
 
570
      result.append("\n");
 
571
      // missing values
 
572
      result.append("    // missing value?\n");
 
573
      result.append("    if (i[" + m_rule.m_attr.index() + "] == null)\n");
 
574
      if (m_rule.m_missingValueClass != -1)
 
575
        result.append("      return Double.NaN;\n");
 
576
      else
 
577
        result.append("      return 0;\n");
 
578
      result.append("\n");
 
579
      
 
580
      // actual prediction
 
581
      result.append("    // prediction\n");
 
582
      result.append("    double v = 0;\n");
 
583
      result.append("    double[] classifications = new double[]{" + Utils.arrayToString(m_rule.m_classifications) + "};");
 
584
      result.append(" // ");
 
585
      for (i = 0; i < m_rule.m_classifications.length; i++) {
 
586
        if (i > 0)
 
587
          result.append(", ");
 
588
        result.append(m_rule.m_class.value(m_rule.m_classifications[i]));
 
589
      }
 
590
      result.append("\n");
 
591
      if (m_rule.m_attr.isNominal()) {
 
592
        for (i = 0; i < m_rule.m_attr.numValues(); i++) {
 
593
          result.append("    ");
 
594
          if (i > 0)
 
595
            result.append("else ");
 
596
          result.append("if (((String) i[" + m_rule.m_attr.index() + "]).equals(\"" + m_rule.m_attr.value(i) + "\"))\n");
 
597
          result.append("      v = " + i + "; // " + m_rule.m_class.value(m_rule.m_classifications[i]) + "\n");
 
598
        }
 
599
      }
 
600
      else {
 
601
        result.append("    double[] breakpoints = new double[]{" + Utils.arrayToString(m_rule.m_breakpoints) + "};\n");
 
602
        result.append("    while (v < breakpoints.length && \n");
 
603
        result.append("           ((Double) i[" + m_rule.m_attr.index() + "]) >= breakpoints[(int) v]) {\n");
 
604
        result.append("      v++;\n");
 
605
        result.append("    }\n");
 
606
      }
 
607
      result.append("    return classifications[(int) v];\n");
 
608
      
 
609
      result.append("  }\n");
 
610
      result.append("}\n");
 
611
    }
 
612
    
 
613
    return result.toString();
 
614
  }
 
615
 
 
616
  /**
 
617
   * Returns a description of the classifier
 
618
   * 
 
619
   * @return a string representation of the classifier
 
620
   */
 
621
  public String toString() {
 
622
 
 
623
    // only ZeroR model?
 
624
    if (m_ZeroR != null) {
 
625
      StringBuffer buf = new StringBuffer();
 
626
      buf.append(this.getClass().getName().replaceAll(".*\\.", "") + "\n");
 
627
      buf.append(this.getClass().getName().replaceAll(".*\\.", "").replaceAll(".", "=") + "\n\n");
 
628
      buf.append("Warning: No model could be built, hence ZeroR model is used:\n\n");
 
629
      buf.append(m_ZeroR.toString());
 
630
      return buf.toString();
 
631
    }
 
632
    
 
633
    if (m_rule == null) {
 
634
      return "OneR: No model built yet.";
 
635
    }
 
636
    return m_rule.toString();
 
637
  }
 
638
 
 
639
  /**
 
640
   * Returns the tip text for this property
 
641
   * @return tip text for this property suitable for
 
642
   * displaying in the explorer/experimenter gui
 
643
   */
 
644
  public String minBucketSizeTipText() {
 
645
    return "The minimum bucket size used for discretizing numeric "
 
646
      + "attributes.";
 
647
  }
 
648
  
 
649
  /**
 
650
   * Get the value of minBucketSize.
 
651
   * @return Value of minBucketSize.
 
652
   */
 
653
  public int getMinBucketSize() {
 
654
    
 
655
    return m_minBucketSize;
 
656
  }
 
657
  
 
658
  /**
 
659
   * Set the value of minBucketSize.
 
660
   * @param v  Value to assign to minBucketSize.
 
661
   */
 
662
  public void setMinBucketSize(int v) {
 
663
    
 
664
    m_minBucketSize = v;
 
665
  }
 
666
  
 
667
  /**
 
668
   * Main method for testing this class
 
669
   * 
 
670
   * @param argv the commandline options
 
671
   */
 
672
  public static void main(String [] argv) {
 
673
    runClassifier(new OneR(), argv);
 
674
  }
 
675
}