source: src/main/java/weka/classifiers/bayes/AODE.java @ 9

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

Import di weka.

File size: 23.8 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 *    AODE.java
19 *    Copyright (C) 2003
20 *    Algorithm developed by: Geoff Webb
21 *    Code written by: Janice Boughton & Zhihai Wang
22 */
23
24package weka.classifiers.bayes;
25
26import weka.classifiers.Classifier;
27import weka.classifiers.AbstractClassifier;
28import weka.classifiers.UpdateableClassifier;
29import weka.core.Capabilities;
30import weka.core.Instance;
31import weka.core.Instances;
32import weka.core.Option;
33import weka.core.OptionHandler;
34import weka.core.RevisionUtils;
35import weka.core.TechnicalInformation;
36import weka.core.TechnicalInformationHandler;
37import weka.core.Utils;
38import weka.core.WeightedInstancesHandler;
39import weka.core.Capabilities.Capability;
40import weka.core.TechnicalInformation.Field;
41import weka.core.TechnicalInformation.Type;
42
43import java.util.Enumeration;
44import java.util.Vector;
45
46/**
47 <!-- globalinfo-start -->
48 * AODE achieves highly accurate classification by averaging over all of a small space of alternative naive-Bayes-like models that have weaker (and hence less detrimental) independence assumptions than naive Bayes. The resulting algorithm is computationally efficient while delivering highly accurate classification on many learning  tasks.<br/>
49 * <br/>
50 * For more information, see<br/>
51 * <br/>
52 * G. Webb, J. Boughton, Z. Wang (2005). Not So Naive Bayes: Aggregating One-Dependence Estimators. Machine Learning. 58(1):5-24.<br/>
53 * <br/>
54 * Further papers are available at<br/>
55 *   http://www.csse.monash.edu.au/~webb/.<br/>
56 * <br/>
57 * Can use an m-estimate for smoothing base probability estimates in place of the Laplace correction (via option -M).<br/>
58 * Default frequency limit set to 1.
59 * <p/>
60 <!-- globalinfo-end -->
61 *
62 <!-- technical-bibtex-start -->
63 * BibTeX:
64 * <pre>
65 * &#64;article{Webb2005,
66 *    author = {G. Webb and J. Boughton and Z. Wang},
67 *    journal = {Machine Learning},
68 *    number = {1},
69 *    pages = {5-24},
70 *    title = {Not So Naive Bayes: Aggregating One-Dependence Estimators},
71 *    volume = {58},
72 *    year = {2005}
73 * }
74 * </pre>
75 * <p/>
76 <!-- technical-bibtex-end -->
77 *
78 <!-- options-start -->
79 * Valid options are: <p/>
80 *
81 * <pre> -D
82 *  Output debugging information
83 * </pre>
84 *
85 * <pre> -F &lt;int&gt;
86 *  Impose a frequency limit for superParents
87 *  (default is 1)</pre>
88 *
89 * <pre> -M
90 *  Use m-estimate instead of laplace correction
91 * </pre>
92 *
93 * <pre> -W &lt;int&gt;
94 *  Specify a weight to use with m-estimate
95 *  (default is 1)</pre>
96 *
97 <!-- options-end -->
98 *
99 * @author Janice Boughton (jrbought@csse.monash.edu.au)
100 * @author Zhihai Wang (zhw@csse.monash.edu.au)
101 * @version $Revision: 5928 $
102 */
103public class AODE
104    extends AbstractClassifier
105    implements OptionHandler, WeightedInstancesHandler, UpdateableClassifier, 
106               TechnicalInformationHandler {
107   
108  /** for serialization */
109  static final long serialVersionUID = 9197439980415113523L;
110 
111  /**
112   * 3D array (m_NumClasses * m_TotalAttValues * m_TotalAttValues)
113   * of attribute counts, i.e., the number of times an attribute value occurs
114   * in conjunction with another attribute value and a class value. 
115   */
116  private double [][][] m_CondiCounts;
117   
118  /** The number of times each class value occurs in the dataset */
119  private double [] m_ClassCounts;
120   
121  /** The sums of attribute-class counts 
122   *    -- if there are no missing values for att, then
123   *       m_SumForCounts[classVal][att] will be the same as
124   *       m_ClassCounts[classVal]
125   */
126  private double [][] m_SumForCounts;
127
128  /** The number of classes */
129  private int m_NumClasses;
130   
131  /** The number of attributes in dataset, including class */
132  private int m_NumAttributes;
133   
134  /** The number of instances in the dataset */
135  private int m_NumInstances;
136   
137  /** The index of the class attribute */
138  private int m_ClassIndex;
139   
140  /** The dataset */
141  private Instances m_Instances;
142   
143  /**
144   * The total number of values (including an extra for each attribute's
145   * missing value, which are included in m_CondiCounts) for all attributes
146   * (not including class). E.g., for three atts each with two possible values,
147   * m_TotalAttValues would be 9 (6 values + 3 missing).
148   * This variable is used when allocating space for m_CondiCounts matrix.
149   */
150  private int m_TotalAttValues;
151   
152  /** The starting index (in the m_CondiCounts matrix) of the values for each
153   * attribute */
154  private int [] m_StartAttIndex;
155   
156  /** The number of values for each attribute */
157  private int [] m_NumAttValues;
158   
159  /** The frequency of each attribute value for the dataset */
160  private double [] m_Frequencies;
161
162  /** The number of valid class values observed in dataset
163   *  -- with no missing classes, this number is the same as m_NumInstances.
164   */
165  private double m_SumInstances;
166
167  /** An att's frequency must be this value or more to be a superParent */
168  private int m_Limit = 1;
169
170  /** If true, outputs debugging info */
171  private boolean m_Debug = false;
172
173  /** flag for using m-estimates */
174  private boolean m_MEstimates = false;
175
176  /** value for m in m-estimate */
177  private int m_Weight = 1;
178
179 
180  /**
181   * Returns a string describing this classifier
182   * @return a description of the classifier suitable for
183   * displaying in the explorer/experimenter gui
184   */
185  public String globalInfo() {
186
187    return "AODE achieves highly accurate classification by averaging over "
188      +"all of a small space of alternative naive-Bayes-like models that have "
189      +"weaker (and hence less detrimental) independence assumptions than "
190      +"naive Bayes. The resulting algorithm is computationally efficient "
191      +"while delivering highly accurate classification on many learning  "
192      +"tasks.\n\n"
193      +"For more information, see\n\n"
194      + getTechnicalInformation().toString() + "\n\n"
195      +"Further papers are available at\n"
196      +"  http://www.csse.monash.edu.au/~webb/.\n\n"
197      + "Can use an m-estimate for smoothing base probability estimates "
198      + "in place of the Laplace correction (via option -M).\n"
199      + "Default frequency limit set to 1.";
200  }
201
202  /**
203   * Returns an instance of a TechnicalInformation object, containing
204   * detailed information about the technical background of this class,
205   * e.g., paper reference or book this class is based on.
206   *
207   * @return the technical information about this class
208   */
209  public TechnicalInformation getTechnicalInformation() {
210    TechnicalInformation        result;
211   
212    result = new TechnicalInformation(Type.ARTICLE);
213    result.setValue(Field.AUTHOR, "G. Webb and J. Boughton and Z. Wang");
214    result.setValue(Field.YEAR, "2005");
215    result.setValue(Field.TITLE, "Not So Naive Bayes: Aggregating One-Dependence Estimators");
216    result.setValue(Field.JOURNAL, "Machine Learning");
217    result.setValue(Field.VOLUME, "58");
218    result.setValue(Field.NUMBER, "1");
219    result.setValue(Field.PAGES, "5-24");
220
221    return result;
222  }
223
224  /**
225   * Returns default capabilities of the classifier.
226   *
227   * @return      the capabilities of this classifier
228   */
229  public Capabilities getCapabilities() {
230    Capabilities result = super.getCapabilities();
231    result.disableAll();
232
233    // attributes
234    result.enable(Capability.NOMINAL_ATTRIBUTES);
235    result.enable(Capability.MISSING_VALUES);
236
237    // class
238    result.enable(Capability.NOMINAL_CLASS);
239    result.enable(Capability.MISSING_CLASS_VALUES);
240
241    // instances
242    result.setMinimumNumberInstances(0);
243   
244    return result;
245  }
246 
247  /**
248   * Generates the classifier.
249   *
250   * @param instances set of instances serving as training data
251   * @throws Exception if the classifier has not been generated
252   * successfully
253   */
254  public void buildClassifier(Instances instances) throws Exception {
255
256    // can classifier handle the data?
257    getCapabilities().testWithFail(instances);
258
259    // remove instances with missing class
260    m_Instances = new Instances(instances);
261    m_Instances.deleteWithMissingClass();
262
263    // reset variable for this fold
264    m_SumInstances = 0;
265    m_ClassIndex = instances.classIndex();
266    m_NumInstances = m_Instances.numInstances();
267    m_NumAttributes = m_Instances.numAttributes();
268    m_NumClasses = m_Instances.numClasses();
269 
270    // allocate space for attribute reference arrays
271    m_StartAttIndex = new int[m_NumAttributes];
272    m_NumAttValues = new int[m_NumAttributes];
273 
274    m_TotalAttValues = 0;
275    for(int i = 0; i < m_NumAttributes; i++) {
276       if(i != m_ClassIndex) {
277          m_StartAttIndex[i] = m_TotalAttValues;
278          m_NumAttValues[i] = m_Instances.attribute(i).numValues();
279          m_TotalAttValues += m_NumAttValues[i] + 1;
280          // + 1 so room for missing value count
281       } else {
282          // m_StartAttIndex[i] = -1;  // class isn't included
283          m_NumAttValues[i] = m_NumClasses;
284       }
285    }
286
287    // allocate space for counts and frequencies
288    m_CondiCounts = new double[m_NumClasses][m_TotalAttValues][m_TotalAttValues];
289    m_ClassCounts = new double[m_NumClasses];
290    m_SumForCounts = new double[m_NumClasses][m_NumAttributes];
291    m_Frequencies = new double[m_TotalAttValues];
292
293    // calculate the counts
294    for(int k = 0; k < m_NumInstances; k++) {
295       addToCounts((Instance)m_Instances.instance(k));
296    }
297
298    // free up some space
299    m_Instances = new Instances(m_Instances, 0);
300  }
301 
302
303  /**
304   * Updates the classifier with the given instance.
305   *
306   * @param instance the new training instance to include in the model
307   */
308    public void updateClassifier(Instance instance) {
309        this.addToCounts(instance);
310    }
311
312    /**
313     * Puts an instance's values into m_CondiCounts, m_ClassCounts and
314     * m_SumInstances.
315     *
316     * @param instance  the instance whose values are to be put into the counts
317     *                  variables
318     */
319  private void addToCounts(Instance instance) {
320 
321    double [] countsPointer;
322 
323    if(instance.classIsMissing())
324       return;   // ignore instances with missing class
325
326    int classVal = (int)instance.classValue();
327    double weight = instance.weight();
328 
329    m_ClassCounts[classVal] += weight;
330    m_SumInstances += weight;
331   
332    // store instance's att val indexes in an array, b/c accessing it
333    // in loop(s) is more efficient
334    int [] attIndex = new int[m_NumAttributes];
335    for(int i = 0; i < m_NumAttributes; i++) {
336       if(i == m_ClassIndex)
337          attIndex[i] = -1;  // we don't use the class attribute in counts
338       else {
339          if(instance.isMissing(i))
340             attIndex[i] = m_StartAttIndex[i] + m_NumAttValues[i];
341          else
342             attIndex[i] = m_StartAttIndex[i] + (int)instance.value(i);
343       }
344    }
345
346    for(int Att1 = 0; Att1 < m_NumAttributes; Att1++) {
347       if(attIndex[Att1] == -1)
348          continue;   // avoid pointless looping as Att1 is currently the class attribute
349
350       m_Frequencies[attIndex[Att1]] += weight;
351       
352       // if this is a missing value, we don't want to increase sumforcounts
353       if(!instance.isMissing(Att1))
354          m_SumForCounts[classVal][Att1] += weight;
355
356       // save time by referencing this now, rather than do it repeatedly in the loop
357       countsPointer = m_CondiCounts[classVal][attIndex[Att1]];
358
359       for(int Att2 = 0; Att2 < m_NumAttributes; Att2++) {
360          if(attIndex[Att2] != -1) {
361             countsPointer[attIndex[Att2]] += weight;
362          }
363       }
364    }
365  }
366 
367 
368  /**
369   * Calculates the class membership probabilities for the given test
370   * instance.
371   *
372   * @param instance the instance to be classified
373   * @return predicted class probability distribution
374   * @throws Exception if there is a problem generating the prediction
375   */
376  public double [] distributionForInstance(Instance instance) throws Exception {
377 
378    // accumulates posterior probabilities for each class
379    double [] probs = new double[m_NumClasses];
380
381    // index for parent attribute value, and a count of parents used
382    int pIndex, parentCount;
383 
384    // pointers for efficiency
385    // for current class, point to joint frequency for any pair of att values
386    double [][] countsForClass;
387    // for current class & parent, point to joint frequency for any att value
388    double [] countsForClassParent;
389
390    // store instance's att indexes in an int array, so accessing them
391    // is more efficient in loop(s).
392    int [] attIndex = new int[m_NumAttributes];
393    for(int att = 0; att < m_NumAttributes; att++) {
394       if(instance.isMissing(att) || att == m_ClassIndex)
395          attIndex[att] = -1;   // can't use class or missing values in calculations
396       else
397          attIndex[att] = m_StartAttIndex[att] + (int)instance.value(att);
398    }
399
400    // calculate probabilities for each possible class value
401    for(int classVal = 0; classVal < m_NumClasses; classVal++) {
402 
403       probs[classVal] = 0;
404       double spodeP = 0;  // P(X,y) for current parent and class
405       parentCount = 0;
406 
407       countsForClass = m_CondiCounts[classVal];
408
409       // each attribute has a turn of being the parent
410       for(int parent = 0; parent < m_NumAttributes; parent++) {
411          if(attIndex[parent] == -1)
412             continue;  // skip class attribute or missing value
413
414          // determine correct index for the parent in m_CondiCounts matrix
415          pIndex = attIndex[parent];
416
417          // check that the att value has a frequency of m_Limit or greater
418          if(m_Frequencies[pIndex] < m_Limit) 
419             continue;
420
421          countsForClassParent = countsForClass[pIndex];
422
423          // block the parent from being its own child
424          attIndex[parent] = -1;
425
426          parentCount++;
427
428          // joint frequency of class and parent
429          double classparentfreq = countsForClassParent[pIndex];
430
431          // find the number of missing values for parent's attribute
432          double missing4ParentAtt = 
433              m_Frequencies[m_StartAttIndex[parent] + m_NumAttValues[parent]];
434
435          // calculate the prior probability -- P(parent & classVal)
436          if (!m_MEstimates) {
437             spodeP = (classparentfreq + 1.0)
438                / ((m_SumInstances - missing4ParentAtt) + m_NumClasses
439                   * m_NumAttValues[parent]);
440          } else {
441             spodeP = (classparentfreq + ((double)m_Weight
442                        / (double)(m_NumClasses * m_NumAttValues[parent])))
443                / ((m_SumInstances - missing4ParentAtt) + m_Weight);
444          }
445
446          // take into account the value of each attribute
447          for(int att = 0; att < m_NumAttributes; att++) {
448             if(attIndex[att] == -1)
449                continue;
450 
451             double missingForParentandChildAtt = 
452              countsForClassParent[m_StartAttIndex[att] + m_NumAttValues[att]];
453
454             if(!m_MEstimates) {
455                spodeP *= (countsForClassParent[attIndex[att]] + 1.0)
456                    / ((classparentfreq - missingForParentandChildAtt)
457                       + m_NumAttValues[att]);
458             } else {
459                spodeP *= (countsForClassParent[attIndex[att]]
460                           + ((double)m_Weight / (double)m_NumAttValues[att]))
461                    / ((classparentfreq - missingForParentandChildAtt)
462                       + m_Weight);
463             }
464          }
465
466          // add this probability to the overall probability
467          probs[classVal] += spodeP;
468 
469          // unblock the parent
470          attIndex[parent] = pIndex;
471       }
472 
473       // check that at least one att was a parent
474       if(parentCount < 1) {
475
476          // do plain naive bayes conditional prob
477          probs[classVal] = NBconditionalProb(instance, classVal);
478
479       } else {
480 
481          // divide by number of parent atts to get the mean
482          probs[classVal] /= (double)(parentCount);
483       }
484    }
485 
486    Utils.normalize(probs);
487    return probs;
488  }
489
490
491  /**
492   * Calculates the probability of the specified class for the given test
493   * instance, using naive Bayes.
494   *
495   * @param instance the instance to be classified
496   * @param classVal the class for which to calculate the probability
497   * @return predicted class probability
498   */
499  public double NBconditionalProb(Instance instance, int classVal) {
500   
501    double prob;
502    double [][] pointer;
503
504    // calculate the prior probability
505    if(!m_MEstimates) {
506       prob = (m_ClassCounts[classVal] + 1.0) / (m_SumInstances + m_NumClasses);
507    } else {
508       prob = (m_ClassCounts[classVal]
509               + ((double)m_Weight / (double)m_NumClasses))
510             / (m_SumInstances + m_Weight);
511    }
512    pointer = m_CondiCounts[classVal];
513   
514    // consider effect of each att value
515    for(int att = 0; att < m_NumAttributes; att++) {
516       if(att == m_ClassIndex || instance.isMissing(att))
517          continue;
518
519       // determine correct index for att in m_CondiCounts
520       int aIndex = m_StartAttIndex[att] + (int)instance.value(att);
521
522       if(!m_MEstimates) {
523          prob *= (double)(pointer[aIndex][aIndex] + 1.0)
524              / ((double)m_SumForCounts[classVal][att] + m_NumAttValues[att]);
525       } else {
526          prob *= (double)(pointer[aIndex][aIndex] 
527                    + ((double)m_Weight / (double)m_NumAttValues[att]))
528                 / (double)(m_SumForCounts[classVal][att] + m_Weight);
529       }
530    }
531    return prob;
532  }
533
534
535  /**
536   * Returns an enumeration describing the available options
537   *
538   * @return an enumeration of all the available options
539   */
540  public Enumeration listOptions() {
541       
542    Vector newVector = new Vector(4);
543       
544    newVector.addElement(
545       new Option("\tOutput debugging information\n",
546                  "D", 0,"-D"));
547    newVector.addElement(
548       new Option("\tImpose a frequency limit for superParents\n"
549                  + "\t(default is 1)", "F", 1,"-F <int>"));
550    newVector.addElement(
551       new Option("\tUse m-estimate instead of laplace correction\n",
552                  "M", 0,"-M"));
553    newVector.addElement(
554       new Option("\tSpecify a weight to use with m-estimate\n"
555                  + "\t(default is 1)", "W", 1,"-W <int>"));
556    return newVector.elements();
557  }
558
559   
560  /**
561   * Parses a given list of options. <p/>
562   *
563   <!-- options-start -->
564   * Valid options are: <p/>
565   *
566   * <pre> -D
567   *  Output debugging information
568   * </pre>
569   *
570   * <pre> -F &lt;int&gt;
571   *  Impose a frequency limit for superParents
572   *  (default is 1)</pre>
573   *
574   * <pre> -M
575   *  Use m-estimate instead of laplace correction
576   * </pre>
577   *
578   * <pre> -W &lt;int&gt;
579   *  Specify a weight to use with m-estimate
580   *  (default is 1)</pre>
581   *
582   <!-- options-end -->
583   *
584   * @param options the list of options as an array of strings
585   * @throws Exception if an option is not supported
586   */
587  public void setOptions(String[] options) throws Exception {
588
589    m_Debug = Utils.getFlag('D', options);
590
591    String Freq = Utils.getOption('F', options);
592    if (Freq.length() != 0) 
593       m_Limit = Integer.parseInt(Freq);
594    else
595       m_Limit = 1;
596 
597    m_MEstimates = Utils.getFlag('M', options);
598    String weight = Utils.getOption('W', options);
599    if (weight.length() != 0) {
600       if (!m_MEstimates)
601          throw new Exception("Can't use Laplace AND m-estimate weight. Choose one.");
602       m_Weight = Integer.parseInt(weight);
603    } 
604    else {
605       if (m_MEstimates)
606          m_Weight = 1;
607    }
608
609    Utils.checkForRemainingOptions(options);
610  }
611   
612  /**
613   * Gets the current settings of the classifier.
614   *
615   * @return an array of strings suitable for passing to setOptions
616   */
617  public String [] getOptions() {
618    Vector result  = new Vector();
619
620    if (m_Debug)
621       result.add("-D");
622       
623    result.add("-F");
624    result.add("" + m_Limit);
625
626    if (m_MEstimates) {
627       result.add("-M");
628       result.add("-W");
629       result.add("" + m_Weight);
630    }
631   
632    return (String[]) result.toArray(new String[result.size()]);
633  }
634   
635  /**
636   * Returns the tip text for this property
637   * @return tip text for this property suitable for
638   * displaying in the explorer/experimenter gui
639   */
640  public String weightTipText() {
641    return "Set the weight for m-estimate.";
642  }
643
644  /**
645   * Sets the weight for m-estimate
646   *
647   * @param w the weight
648   */
649  public void setWeight(int w) {
650    if (!getUseMEstimates()) {
651      System.out.println(
652          "Weight is only used in conjunction with m-estimate - ignored!");
653    }
654    else {
655      if (w > 0)
656        m_Weight = w;
657      else
658        System.out.println("Weight must be greater than 0!");
659    }
660  }
661
662  /**
663   * Gets the weight used in m-estimate
664   *
665   * @return the frequency limit
666   */
667  public int getWeight() {
668    return m_Weight;
669  }
670
671  /**
672   * Returns the tip text for this property
673   * @return tip text for this property suitable for
674   * displaying in the explorer/experimenter gui
675   */
676  public String useMEstimatesTipText() {
677    return "Use m-estimate instead of laplace correction.";
678  }
679
680  /**
681   * Gets if m-estimaces is being used.
682   *
683   * @return Value of m_MEstimates.
684   */
685  public boolean getUseMEstimates() {
686    return m_MEstimates;
687  }
688
689  /**
690   * Sets if m-estimates is to be used.
691   *
692   * @param value     Value to assign to m_MEstimates.
693   */
694  public void setUseMEstimates(boolean value) {
695    m_MEstimates = value;
696  }
697
698  /**
699   * Returns the tip text for this property
700   * @return tip text for this property suitable for
701   * displaying in the explorer/experimenter gui
702   */
703  public String frequencyLimitTipText() {
704    return "Attributes with a frequency in the train set below "
705           + "this value aren't used as parents.";
706  }
707
708  /**
709   * Sets the frequency limit
710   *
711   * @param f the frequency limit
712   */
713  public void setFrequencyLimit(int f) {
714    m_Limit = f;
715  }
716
717  /**
718   * Gets the frequency limit.
719   *
720   * @return the frequency limit
721   */
722  public int getFrequencyLimit() {
723    return m_Limit;
724  }
725
726  /**
727   * Returns a description of the classifier.
728   *
729   * @return a description of the classifier as a string.
730   */
731  public String toString() {
732 
733    StringBuffer text = new StringBuffer();
734       
735    text.append("The AODE Classifier");
736    if (m_Instances == null) {
737       text.append(": No model built yet.");
738    } else {
739       try {
740          for (int i = 0; i < m_NumClasses; i++) {
741             // print to string, the prior probabilities of class values
742             text.append("\nClass " + m_Instances.classAttribute().value(i) +
743                       ": Prior probability = " + Utils.
744                          doubleToString(((m_ClassCounts[i] + 1)
745                       /(m_SumInstances + m_NumClasses)), 4, 2)+"\n\n");
746          }
747               
748          text.append("Dataset: " + m_Instances.relationName() + "\n"
749                      + "Instances: " + m_NumInstances + "\n"
750                      + "Attributes: " + m_NumAttributes + "\n"
751                      + "Frequency limit for superParents: " + m_Limit + "\n");
752          text.append("Correction: ");
753          if (!m_MEstimates)
754             text.append("laplace\n");
755          else
756             text.append("m-estimate (m=" + m_Weight + ")\n");
757               
758       } catch (Exception ex) {
759          text.append(ex.getMessage());
760       }
761    }
762       
763    return text.toString();
764  }
765 
766  /**
767   * Returns the revision string.
768   *
769   * @return            the revision
770   */
771  public String getRevision() {
772    return RevisionUtils.extract("$Revision: 5928 $");
773  }
774   
775  /**
776   * Main method for testing this class.
777   *
778   * @param argv the options
779   */
780  public static void main(String [] argv) {
781    runClassifier(new AODE(), argv);
782  }
783}
Note: See TracBrowser for help on using the repository browser.