Coverage Report - weka.classifiers.meta.Bagging
 
Classes in this File Line Coverage Branch Coverage Complexity
Bagging
0%
0/171
0%
0/80
3.087
 
 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  
  *    Bagging.java
 18  
  *    Copyright (C) 1999-2012 University of Waikato, Hamilton, New Zealand
 19  
  *
 20  
  */
 21  
 
 22  
 package weka.classifiers.meta;
 23  
 
 24  
 import java.util.Enumeration;
 25  
 import java.util.Random;
 26  
 import java.util.Vector;
 27  
 
 28  
 import weka.classifiers.RandomizableParallelIteratedSingleClassifierEnhancer;
 29  
 import weka.core.AdditionalMeasureProducer;
 30  
 import weka.core.Instance;
 31  
 import weka.core.Instances;
 32  
 import weka.core.Option;
 33  
 import weka.core.Randomizable;
 34  
 import weka.core.RevisionUtils;
 35  
 import weka.core.TechnicalInformation;
 36  
 import weka.core.TechnicalInformation.Field;
 37  
 import weka.core.TechnicalInformation.Type;
 38  
 import weka.core.TechnicalInformationHandler;
 39  
 import weka.core.Utils;
 40  
 import weka.core.WeightedInstancesHandler;
 41  
 
 42  
 /**
 43  
  <!-- globalinfo-start -->
 44  
  * Class for bagging a classifier to reduce variance. Can do classification and regression depending on the base learner. <br/>
 45  
  * <br/>
 46  
  * For more information, see<br/>
 47  
  * <br/>
 48  
  * Leo Breiman (1996). Bagging predictors. Machine Learning. 24(2):123-140.
 49  
  * <p/>
 50  
  <!-- globalinfo-end -->
 51  
  *
 52  
  <!-- technical-bibtex-start -->
 53  
  * BibTeX:
 54  
  * <pre>
 55  
  * &#64;article{Breiman1996,
 56  
  *    author = {Leo Breiman},
 57  
  *    journal = {Machine Learning},
 58  
  *    number = {2},
 59  
  *    pages = {123-140},
 60  
  *    title = {Bagging predictors},
 61  
  *    volume = {24},
 62  
  *    year = {1996}
 63  
  * }
 64  
  * </pre>
 65  
  * <p/>
 66  
  <!-- technical-bibtex-end -->
 67  
  *
 68  
  <!-- options-start -->
 69  
  * Valid options are: <p/>
 70  
  * 
 71  
  * <pre> -P
 72  
  *  Size of each bag, as a percentage of the
 73  
  *  training set size. (default 100)</pre>
 74  
  * 
 75  
  * <pre> -O
 76  
  *  Calculate the out of bag error.</pre>
 77  
  * 
 78  
  * <pre> -S &lt;num&gt;
 79  
  *  Random number seed.
 80  
  *  (default 1)</pre>
 81  
  * 
 82  
  * <pre> -I &lt;num&gt;
 83  
  *  Number of iterations.
 84  
  *  (default 10)</pre>
 85  
  * 
 86  
  * <pre> -D
 87  
  *  If set, classifier is run in debug mode and
 88  
  *  may output additional info to the console</pre>
 89  
  * 
 90  
  * <pre> -W
 91  
  *  Full name of base classifier.
 92  
  *  (default: weka.classifiers.trees.REPTree)</pre>
 93  
  * 
 94  
  * <pre> 
 95  
  * Options specific to classifier weka.classifiers.trees.REPTree:
 96  
  * </pre>
 97  
  * 
 98  
  * <pre> -M &lt;minimum number of instances&gt;
 99  
  *  Set minimum number of instances per leaf (default 2).</pre>
 100  
  * 
 101  
  * <pre> -V &lt;minimum variance for split&gt;
 102  
  *  Set minimum numeric class variance proportion
 103  
  *  of train variance for split (default 1e-3).</pre>
 104  
  * 
 105  
  * <pre> -N &lt;number of folds&gt;
 106  
  *  Number of folds for reduced error pruning (default 3).</pre>
 107  
  * 
 108  
  * <pre> -S &lt;seed&gt;
 109  
  *  Seed for random data shuffling (default 1).</pre>
 110  
  * 
 111  
  * <pre> -P
 112  
  *  No pruning.</pre>
 113  
  * 
 114  
  * <pre> -L
 115  
  *  Maximum tree depth (default -1, no maximum)</pre>
 116  
  * 
 117  
  <!-- options-end -->
 118  
  *
 119  
  * Options after -- are passed to the designated classifier.<p>
 120  
  *
 121  
  * @author Eibe Frank (eibe@cs.waikato.ac.nz)
 122  
  * @author Len Trigg (len@reeltwo.com)
 123  
  * @author Richard Kirkby (rkirkby@cs.waikato.ac.nz)
 124  
  * @version $Revision: 8034 $
 125  
  */
 126  
 public class Bagging
 127  
   extends RandomizableParallelIteratedSingleClassifierEnhancer 
 128  
   implements WeightedInstancesHandler, AdditionalMeasureProducer,
 129  
              TechnicalInformationHandler {
 130  
 
 131  
   /** for serialization */
 132  
   static final long serialVersionUID = -505879962237199703L;
 133  
   
 134  
   /** The size of each bag sample, as a percentage of the training size */
 135  0
   protected int m_BagSizePercent = 100;
 136  
 
 137  
   /** Whether to calculate the out of bag error */
 138  0
   protected boolean m_CalcOutOfBag = false;
 139  
 
 140  
   /** The out of bag error that has been calculated */
 141  
   protected double m_OutOfBagError;  
 142  
     
 143  
   /**
 144  
    * Constructor.
 145  
    */
 146  0
   public Bagging() {
 147  
     
 148  0
     m_Classifier = new weka.classifiers.trees.REPTree();
 149  0
   }
 150  
   
 151  
   /**
 152  
    * Returns a string describing classifier
 153  
    * @return a description suitable for
 154  
    * displaying in the explorer/experimenter gui
 155  
    */
 156  
   public String globalInfo() {
 157  
  
 158  0
     return "Class for bagging a classifier to reduce variance. Can do classification "
 159  
       + "and regression depending on the base learner. \n\n"
 160  
       + "For more information, see\n\n"
 161  
       + getTechnicalInformation().toString();
 162  
   }
 163  
 
 164  
   /**
 165  
    * Returns an instance of a TechnicalInformation object, containing 
 166  
    * detailed information about the technical background of this class,
 167  
    * e.g., paper reference or book this class is based on.
 168  
    * 
 169  
    * @return the technical information about this class
 170  
    */
 171  
   public TechnicalInformation getTechnicalInformation() {
 172  
     TechnicalInformation         result;
 173  
     
 174  0
     result = new TechnicalInformation(Type.ARTICLE);
 175  0
     result.setValue(Field.AUTHOR, "Leo Breiman");
 176  0
     result.setValue(Field.YEAR, "1996");
 177  0
     result.setValue(Field.TITLE, "Bagging predictors");
 178  0
     result.setValue(Field.JOURNAL, "Machine Learning");
 179  0
     result.setValue(Field.VOLUME, "24");
 180  0
     result.setValue(Field.NUMBER, "2");
 181  0
     result.setValue(Field.PAGES, "123-140");
 182  
     
 183  0
     return result;
 184  
   }
 185  
 
 186  
   /**
 187  
    * String describing default classifier.
 188  
    * 
 189  
    * @return the default classifier classname
 190  
    */
 191  
   protected String defaultClassifierString() {
 192  
     
 193  0
     return "weka.classifiers.trees.REPTree";
 194  
   }
 195  
 
 196  
   /**
 197  
    * Returns an enumeration describing the available options.
 198  
    *
 199  
    * @return an enumeration of all the available options.
 200  
    */
 201  
   public Enumeration listOptions() {
 202  
 
 203  0
     Vector newVector = new Vector(2);
 204  
 
 205  0
     newVector.addElement(new Option(
 206  
               "\tSize of each bag, as a percentage of the\n" 
 207  
               + "\ttraining set size. (default 100)",
 208  
               "P", 1, "-P"));
 209  0
     newVector.addElement(new Option(
 210  
               "\tCalculate the out of bag error.",
 211  
               "O", 0, "-O"));
 212  
 
 213  0
     Enumeration enu = super.listOptions();
 214  0
     while (enu.hasMoreElements()) {
 215  0
       newVector.addElement(enu.nextElement());
 216  
     }
 217  0
     return newVector.elements();
 218  
   }
 219  
 
 220  
 
 221  
   /**
 222  
    * Parses a given list of options. <p/>
 223  
    *
 224  
    <!-- options-start -->
 225  
    * Valid options are: <p/>
 226  
    * 
 227  
    * <pre> -P
 228  
    *  Size of each bag, as a percentage of the
 229  
    *  training set size. (default 100)</pre>
 230  
    * 
 231  
    * <pre> -O
 232  
    *  Calculate the out of bag error.</pre>
 233  
    * 
 234  
    * <pre> -S &lt;num&gt;
 235  
    *  Random number seed.
 236  
    *  (default 1)</pre>
 237  
    * 
 238  
    * <pre> -I &lt;num&gt;
 239  
    *  Number of iterations.
 240  
    *  (default 10)</pre>
 241  
    * 
 242  
    * <pre> -D
 243  
    *  If set, classifier is run in debug mode and
 244  
    *  may output additional info to the console</pre>
 245  
    * 
 246  
    * <pre> -W
 247  
    *  Full name of base classifier.
 248  
    *  (default: weka.classifiers.trees.REPTree)</pre>
 249  
    * 
 250  
    * <pre> 
 251  
    * Options specific to classifier weka.classifiers.trees.REPTree:
 252  
    * </pre>
 253  
    * 
 254  
    * <pre> -M &lt;minimum number of instances&gt;
 255  
    *  Set minimum number of instances per leaf (default 2).</pre>
 256  
    * 
 257  
    * <pre> -V &lt;minimum variance for split&gt;
 258  
    *  Set minimum numeric class variance proportion
 259  
    *  of train variance for split (default 1e-3).</pre>
 260  
    * 
 261  
    * <pre> -N &lt;number of folds&gt;
 262  
    *  Number of folds for reduced error pruning (default 3).</pre>
 263  
    * 
 264  
    * <pre> -S &lt;seed&gt;
 265  
    *  Seed for random data shuffling (default 1).</pre>
 266  
    * 
 267  
    * <pre> -P
 268  
    *  No pruning.</pre>
 269  
    * 
 270  
    * <pre> -L
 271  
    *  Maximum tree depth (default -1, no maximum)</pre>
 272  
    * 
 273  
    <!-- options-end -->
 274  
    *
 275  
    * Options after -- are passed to the designated classifier.<p>
 276  
    *
 277  
    * @param options the list of options as an array of strings
 278  
    * @throws Exception if an option is not supported
 279  
    */
 280  
   public void setOptions(String[] options) throws Exception {
 281  
 
 282  0
     String bagSize = Utils.getOption('P', options);
 283  0
     if (bagSize.length() != 0) {
 284  0
       setBagSizePercent(Integer.parseInt(bagSize));
 285  
     } else {
 286  0
       setBagSizePercent(100);
 287  
     }
 288  
 
 289  0
     setCalcOutOfBag(Utils.getFlag('O', options));
 290  
 
 291  0
     super.setOptions(options);
 292  0
   }
 293  
 
 294  
   /**
 295  
    * Gets the current settings of the Classifier.
 296  
    *
 297  
    * @return an array of strings suitable for passing to setOptions
 298  
    */
 299  
   public String [] getOptions() {
 300  
 
 301  
 
 302  0
     String [] superOptions = super.getOptions();
 303  0
     String [] options = new String [superOptions.length + 3];
 304  
 
 305  0
     int current = 0;
 306  0
     options[current++] = "-P"; 
 307  0
     options[current++] = "" + getBagSizePercent();
 308  
 
 309  0
     if (getCalcOutOfBag()) { 
 310  0
       options[current++] = "-O";
 311  
     }
 312  
 
 313  0
     System.arraycopy(superOptions, 0, options, current, 
 314  
                      superOptions.length);
 315  
 
 316  0
     current += superOptions.length;
 317  0
     while (current < options.length) {
 318  0
       options[current++] = "";
 319  
     }
 320  0
     return options;
 321  
   }
 322  
 
 323  
   /**
 324  
    * Returns the tip text for this property
 325  
    * @return tip text for this property suitable for
 326  
    * displaying in the explorer/experimenter gui
 327  
    */
 328  
   public String bagSizePercentTipText() {
 329  0
     return "Size of each bag, as a percentage of the training set size.";
 330  
   }
 331  
 
 332  
   /**
 333  
    * Gets the size of each bag, as a percentage of the training set size.
 334  
    *
 335  
    * @return the bag size, as a percentage.
 336  
    */
 337  
   public int getBagSizePercent() {
 338  
 
 339  0
     return m_BagSizePercent;
 340  
   }
 341  
   
 342  
   /**
 343  
    * Sets the size of each bag, as a percentage of the training set size.
 344  
    *
 345  
    * @param newBagSizePercent the bag size, as a percentage.
 346  
    */
 347  
   public void setBagSizePercent(int newBagSizePercent) {
 348  
 
 349  0
     m_BagSizePercent = newBagSizePercent;
 350  0
   }
 351  
 
 352  
   /**
 353  
    * Returns the tip text for this property
 354  
    * @return tip text for this property suitable for
 355  
    * displaying in the explorer/experimenter gui
 356  
    */
 357  
   public String calcOutOfBagTipText() {
 358  0
     return "Whether the out-of-bag error is calculated.";
 359  
   }
 360  
 
 361  
   /**
 362  
    * Set whether the out of bag error is calculated.
 363  
    *
 364  
    * @param calcOutOfBag whether to calculate the out of bag error
 365  
    */
 366  
   public void setCalcOutOfBag(boolean calcOutOfBag) {
 367  
 
 368  0
     m_CalcOutOfBag = calcOutOfBag;
 369  0
   }
 370  
 
 371  
   /**
 372  
    * Get whether the out of bag error is calculated.
 373  
    *
 374  
    * @return whether the out of bag error is calculated
 375  
    */
 376  
   public boolean getCalcOutOfBag() {
 377  
 
 378  0
     return m_CalcOutOfBag;
 379  
   }
 380  
 
 381  
   /**
 382  
    * Gets the out of bag error that was calculated as the classifier
 383  
    * was built.
 384  
    *
 385  
    * @return the out of bag error 
 386  
    */
 387  
   public double measureOutOfBagError() {
 388  
     
 389  0
     return m_OutOfBagError;
 390  
   }
 391  
   
 392  
   /**
 393  
    * Returns an enumeration of the additional measure names.
 394  
    *
 395  
    * @return an enumeration of the measure names
 396  
    */
 397  
   public Enumeration enumerateMeasures() {
 398  
     
 399  0
     Vector newVector = new Vector(1);
 400  0
     newVector.addElement("measureOutOfBagError");
 401  0
     return newVector.elements();
 402  
   }
 403  
   
 404  
   /**
 405  
    * Returns the value of the named measure.
 406  
    *
 407  
    * @param additionalMeasureName the name of the measure to query for its value
 408  
    * @return the value of the named measure
 409  
    * @throws IllegalArgumentException if the named measure is not supported
 410  
    */
 411  
   public double getMeasure(String additionalMeasureName) {
 412  
     
 413  0
     if (additionalMeasureName.equalsIgnoreCase("measureOutOfBagError")) {
 414  0
       return measureOutOfBagError();
 415  
     }
 416  0
     else {throw new IllegalArgumentException(additionalMeasureName 
 417  
                                              + " not supported (Bagging)");
 418  
     }
 419  
   }
 420  
 
 421  
   /**
 422  
    * Creates a new dataset of the same size using random sampling
 423  
    * with replacement according to the given weight vector. The
 424  
    * weights of the instances in the new dataset are set to one.
 425  
    * The length of the weight vector has to be the same as the
 426  
    * number of instances in the dataset, and all weights have to
 427  
    * be positive.
 428  
    *
 429  
    * @param data the data to be sampled from
 430  
    * @param random a random number generator
 431  
    * @param sampled indicating which instance has been sampled
 432  
    * @return the new dataset
 433  
    * @throws IllegalArgumentException if the weights array is of the wrong
 434  
    * length or contains negative weights.
 435  
    */
 436  
   public final Instances resampleWithWeights(Instances data,
 437  
                                              Random random, 
 438  
                                              boolean[] sampled) {
 439  
 
 440  0
     double[] weights = new double[data.numInstances()];
 441  0
     for (int i = 0; i < weights.length; i++) {
 442  0
       weights[i] = data.instance(i).weight();
 443  
     }
 444  0
     Instances newData = new Instances(data, data.numInstances());
 445  0
     if (data.numInstances() == 0) {
 446  0
       return newData;
 447  
     }
 448  0
     double[] probabilities = new double[data.numInstances()];
 449  0
     double sumProbs = 0, sumOfWeights = Utils.sum(weights);
 450  0
     for (int i = 0; i < data.numInstances(); i++) {
 451  0
       sumProbs += random.nextDouble();
 452  0
       probabilities[i] = sumProbs;
 453  
     }
 454  0
     Utils.normalize(probabilities, sumProbs / sumOfWeights);
 455  
 
 456  
     // Make sure that rounding errors don't mess things up
 457  0
     probabilities[data.numInstances() - 1] = sumOfWeights;
 458  0
     int k = 0; int l = 0;
 459  0
     sumProbs = 0;
 460  0
     while ((k < data.numInstances() && (l < data.numInstances()))) {
 461  0
       if (weights[l] < 0) {
 462  0
         throw new IllegalArgumentException("Weights have to be positive.");
 463  
       }
 464  0
       sumProbs += weights[l];
 465  0
       while ((k < data.numInstances()) &&
 466  
              (probabilities[k] <= sumProbs)) { 
 467  0
         newData.add(data.instance(l));
 468  0
         sampled[l] = true;
 469  0
         newData.instance(k).setWeight(1);
 470  0
         k++;
 471  
       }
 472  0
       l++;
 473  
     }
 474  0
     return newData;
 475  
   }
 476  
   
 477  
   protected Random m_random;
 478  
   protected boolean[][] m_inBag;
 479  
   protected Instances m_data;
 480  
   
 481  
   /**
 482  
    * Returns a training set for a particular iteration.
 483  
    * 
 484  
    * @param iteration the number of the iteration for the requested training set.
 485  
    * @return the training set for the supplied iteration number
 486  
    * @throws Exception if something goes wrong when generating a training set.
 487  
    */
 488  
   protected synchronized Instances getTrainingSet(int iteration) throws Exception {
 489  0
     int bagSize = m_data.numInstances() * m_BagSizePercent / 100;
 490  0
     Instances bagData = null;
 491  0
     Random r = new Random(m_Seed + iteration);
 492  
 
 493  
     // create the in-bag dataset
 494  0
     if (m_CalcOutOfBag) {
 495  0
       m_inBag[iteration] = new boolean[m_data.numInstances()];
 496  0
       bagData = resampleWithWeights(m_data, r, m_inBag[iteration]);
 497  
     } else {
 498  0
       bagData = m_data.resampleWithWeights(r);
 499  0
       if (bagSize < m_data.numInstances()) {
 500  0
         bagData.randomize(r);
 501  0
         Instances newBagData = new Instances(bagData, 0, bagSize);
 502  0
         bagData = newBagData;
 503  
       }
 504  
     }
 505  
     
 506  0
     return bagData;
 507  
   }
 508  
   
 509  
   /**
 510  
    * Bagging method.
 511  
    *
 512  
    * @param data the training data to be used for generating the
 513  
    * bagged classifier.
 514  
    * @throws Exception if the classifier could not be built successfully
 515  
    */
 516  
   public void buildClassifier(Instances data) throws Exception {
 517  
 
 518  
     // can classifier handle the data?
 519  0
     getCapabilities().testWithFail(data);
 520  
 
 521  
     // remove instances with missing class
 522  0
     m_data = new Instances(data);
 523  0
     m_data.deleteWithMissingClass();
 524  
     
 525  0
     super.buildClassifier(m_data);
 526  
 
 527  0
     if (m_CalcOutOfBag && (m_BagSizePercent != 100)) {
 528  0
       throw new IllegalArgumentException("Bag size needs to be 100% if " +
 529  
                                          "out-of-bag error is to be calculated!");
 530  
     }
 531  
 
 532  0
     int bagSize = m_data.numInstances() * m_BagSizePercent / 100;
 533  0
     m_random = new Random(m_Seed);
 534  
     
 535  0
     m_inBag = null;
 536  0
     if (m_CalcOutOfBag)
 537  0
       m_inBag = new boolean[m_Classifiers.length][];
 538  
     
 539  0
     for (int j = 0; j < m_Classifiers.length; j++) {      
 540  0
       if (m_Classifier instanceof Randomizable) {
 541  0
         ((Randomizable) m_Classifiers[j]).setSeed(m_random.nextInt());
 542  
       }
 543  
     }
 544  
     
 545  0
     buildClassifiers();
 546  
     
 547  
     // calc OOB error?
 548  0
     if (getCalcOutOfBag()) {
 549  0
       double outOfBagCount = 0.0;
 550  0
       double errorSum = 0.0;
 551  0
       boolean numeric = m_data.classAttribute().isNumeric();
 552  
       
 553  0
       for (int i = 0; i < m_data.numInstances(); i++) {
 554  
         double vote;
 555  
         double[] votes;
 556  0
         if (numeric)
 557  0
           votes = new double[1];
 558  
         else
 559  0
           votes = new double[m_data.numClasses()];
 560  
         
 561  
         // determine predictions for instance
 562  0
         int voteCount = 0;
 563  0
         for (int j = 0; j < m_Classifiers.length; j++) {
 564  0
           if (m_inBag[j][i])
 565  0
             continue;
 566  
           
 567  0
           voteCount++;
 568  
 //          double pred = m_Classifiers[j].classifyInstance(m_data.instance(i));
 569  0
           if (numeric) {
 570  
             // votes[0] += pred;
 571  0
             votes[0] += m_Classifiers[j].classifyInstance(m_data.instance(i));
 572  
           } else {
 573  
             //  votes[(int) pred]++;
 574  0
             double[] newProbs = m_Classifiers[j].distributionForInstance(m_data.instance(i));
 575  
             // average the probability estimates
 576  0
             for (int k = 0; k < newProbs.length; k++) {
 577  0
               votes[k] += newProbs[k];
 578  
             }
 579  
           }
 580  
         }
 581  
         
 582  
         // "vote"
 583  0
         if (numeric) {
 584  0
           vote = votes[0];
 585  0
           if (voteCount > 0) {
 586  0
             vote  /= voteCount;    // average
 587  
           }
 588  
         } else {
 589  0
           if (Utils.eq(Utils.sum(votes), 0)) {            
 590  
           } else {
 591  0
             Utils.normalize(votes);
 592  
           }
 593  0
           vote = Utils.maxIndex(votes);   // predicted class
 594  
         }
 595  
         
 596  
         // error for instance
 597  0
         outOfBagCount += m_data.instance(i).weight();
 598  0
         if (numeric) {
 599  0
           errorSum += StrictMath.abs(vote - m_data.instance(i).classValue()) 
 600  
           * m_data.instance(i).weight();
 601  
         }
 602  
         else {
 603  0
           if (vote != m_data.instance(i).classValue())
 604  0
             errorSum += m_data.instance(i).weight();
 605  
         }
 606  
       }
 607  
       
 608  0
       m_OutOfBagError = errorSum / outOfBagCount;
 609  0
     }
 610  
     else {
 611  0
       m_OutOfBagError = 0;
 612  
     }
 613  
     
 614  
     // save memory
 615  0
     m_data = null;
 616  0
   }
 617  
 
 618  
   /**
 619  
    * Calculates the class membership probabilities for the given test
 620  
    * instance.
 621  
    *
 622  
    * @param instance the instance to be classified
 623  
    * @return preedicted class probability distribution
 624  
    * @throws Exception if distribution can't be computed successfully 
 625  
    */
 626  
   public double[] distributionForInstance(Instance instance) throws Exception {
 627  
 
 628  0
     double [] sums = new double [instance.numClasses()], newProbs; 
 629  
     
 630  0
     for (int i = 0; i < m_NumIterations; i++) {
 631  0
       if (instance.classAttribute().isNumeric() == true) {
 632  0
         sums[0] += m_Classifiers[i].classifyInstance(instance);
 633  
       } else {
 634  0
         newProbs = m_Classifiers[i].distributionForInstance(instance);
 635  0
         for (int j = 0; j < newProbs.length; j++)
 636  0
           sums[j] += newProbs[j];
 637  
       }
 638  
     }
 639  0
     if (instance.classAttribute().isNumeric() == true) {
 640  0
       sums[0] /= (double)m_NumIterations;
 641  0
       return sums;
 642  0
     } else if (Utils.eq(Utils.sum(sums), 0)) {
 643  0
       return sums;
 644  
     } else {
 645  0
       Utils.normalize(sums);
 646  0
       return sums;
 647  
     }
 648  
   }
 649  
 
 650  
   /**
 651  
    * Returns description of the bagged classifier.
 652  
    *
 653  
    * @return description of the bagged classifier as a string
 654  
    */
 655  
   public String toString() {
 656  
     
 657  0
     if (m_Classifiers == null) {
 658  0
       return "Bagging: No model built yet.";
 659  
     }
 660  0
     StringBuffer text = new StringBuffer();
 661  0
     text.append("All the base classifiers: \n\n");
 662  0
     for (int i = 0; i < m_Classifiers.length; i++)
 663  0
       text.append(m_Classifiers[i].toString() + "\n\n");
 664  
     
 665  0
     if (m_CalcOutOfBag) {
 666  0
       text.append("Out of bag error: "
 667  
                   + Utils.doubleToString(m_OutOfBagError, 4)
 668  
                   + "\n\n");
 669  
     }
 670  
 
 671  0
     return text.toString();
 672  
   }
 673  
   
 674  
   /**
 675  
    * Returns the revision string.
 676  
    * 
 677  
    * @return                the revision
 678  
    */
 679  
   public String getRevision() {
 680  0
     return RevisionUtils.extract("$Revision: 8034 $");
 681  
   }
 682  
 
 683  
   /**
 684  
    * Main method for testing this class.
 685  
    *
 686  
    * @param argv the options
 687  
    */
 688  
   public static void main(String [] argv) {
 689  0
     runClassifier(new Bagging(), argv);
 690  0
   }
 691  
 }