Coverage Report - weka.classifiers.BVDecompose
 
Classes in this File Line Coverage Branch Coverage Complexity
BVDecompose
0%
0/201
0%
0/66
2.556
 
 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  
  *    BVDecompose.java
 18  
  *    Copyright (C) 1999-2012 University of Waikato, Hamilton, New Zealand
 19  
  *
 20  
  */
 21  
 
 22  
 package weka.classifiers;
 23  
 
 24  
 import java.io.BufferedReader;
 25  
 import java.io.FileReader;
 26  
 import java.io.Reader;
 27  
 import java.util.Enumeration;
 28  
 import java.util.Random;
 29  
 import java.util.Vector;
 30  
 
 31  
 import weka.core.Attribute;
 32  
 import weka.core.Instance;
 33  
 import weka.core.Instances;
 34  
 import weka.core.Option;
 35  
 import weka.core.OptionHandler;
 36  
 import weka.core.RevisionHandler;
 37  
 import weka.core.RevisionUtils;
 38  
 import weka.core.TechnicalInformation;
 39  
 import weka.core.TechnicalInformation.Field;
 40  
 import weka.core.TechnicalInformation.Type;
 41  
 import weka.core.TechnicalInformationHandler;
 42  
 import weka.core.Utils;
 43  
 
 44  
 /**
 45  
  <!-- globalinfo-start -->
 46  
  * Class for performing a Bias-Variance decomposition on any classifier using the method specified in:<br/>
 47  
  * <br/>
 48  
  * Ron Kohavi, David H. Wolpert: Bias Plus Variance Decomposition for Zero-One Loss Functions. In: Machine Learning: Proceedings of the Thirteenth International Conference, 275-283, 1996.
 49  
  * <p/>
 50  
  <!-- globalinfo-end -->
 51  
  *
 52  
  <!-- technical-bibtex-start -->
 53  
  * BibTeX:
 54  
  * <pre>
 55  
  * &#64;inproceedings{Kohavi1996,
 56  
  *    author = {Ron Kohavi and David H. Wolpert},
 57  
  *    booktitle = {Machine Learning: Proceedings of the Thirteenth International Conference},
 58  
  *    editor = {Lorenza Saitta},
 59  
  *    pages = {275-283},
 60  
  *    publisher = {Morgan Kaufmann},
 61  
  *    title = {Bias Plus Variance Decomposition for Zero-One Loss Functions},
 62  
  *    year = {1996},
 63  
  *    PS = {http://robotics.stanford.edu/\~ronnyk/biasVar.ps}
 64  
  * }
 65  
  * </pre>
 66  
  * <p/>
 67  
  <!-- technical-bibtex-end -->
 68  
  *
 69  
  <!-- options-start -->
 70  
  * Valid options are: <p/>
 71  
  *
 72  
  * <pre> -c &lt;class index&gt;
 73  
  *  The index of the class attribute.
 74  
  *  (default last)</pre>
 75  
  *
 76  
  * <pre> -t &lt;name of arff file&gt;
 77  
  *  The name of the arff file used for the decomposition.</pre>
 78  
  *
 79  
  * <pre> -T &lt;training pool size&gt;
 80  
  *  The number of instances placed in the training pool.
 81  
  *  The remainder will be used for testing. (default 100)</pre>
 82  
  *
 83  
  * <pre> -s &lt;seed&gt;
 84  
  *  The random number seed used.</pre>
 85  
  *
 86  
  * <pre> -x &lt;num&gt;
 87  
  *  The number of training repetitions used.
 88  
  *  (default 50)</pre>
 89  
  *
 90  
  * <pre> -D
 91  
  *  Turn on debugging output.</pre>
 92  
  *
 93  
  * <pre> -W &lt;classifier class name&gt;
 94  
  *  Full class name of the learner used in the decomposition.
 95  
  *  eg: weka.classifiers.bayes.NaiveBayes</pre>
 96  
  *
 97  
  * <pre>
 98  
  * Options specific to learner weka.classifiers.rules.ZeroR:
 99  
  * </pre>
 100  
  *
 101  
  * <pre> -D
 102  
  *  If set, classifier is run in debug mode and
 103  
  *  may output additional info to the console</pre>
 104  
  *
 105  
  <!-- options-end -->
 106  
  *
 107  
  * Options after -- are passed to the designated sub-learner. <p>
 108  
  *
 109  
  * @author Len Trigg (trigg@cs.waikato.ac.nz)
 110  
  * @version $Revision: 8034 $
 111  
  */
 112  0
 public class BVDecompose
 113  
   implements OptionHandler, TechnicalInformationHandler, RevisionHandler {
 114  
 
 115  
   /** Debugging mode, gives extra output if true */
 116  
   protected boolean m_Debug;
 117  
 
 118  
   /** An instantiated base classifier used for getting and testing options. */
 119  0
   protected Classifier m_Classifier = new weka.classifiers.rules.ZeroR();
 120  
 
 121  
   /** The options to be passed to the base classifier. */
 122  
   protected String [] m_ClassifierOptions;
 123  
 
 124  
   /** The number of train iterations */
 125  0
   protected int m_TrainIterations = 50;
 126  
 
 127  
   /** The name of the data file used for the decomposition */
 128  
   protected String m_DataFileName;
 129  
 
 130  
   /** The index of the class attribute */
 131  0
   protected int m_ClassIndex = -1;
 132  
 
 133  
   /** The random number seed */
 134  0
   protected int m_Seed = 1;
 135  
 
 136  
   /** The calculated bias (squared) */
 137  
   protected double m_Bias;
 138  
 
 139  
   /** The calculated variance */
 140  
   protected double m_Variance;
 141  
 
 142  
   /** The calculated sigma (squared) */
 143  
   protected double m_Sigma;
 144  
 
 145  
   /** The error rate */
 146  
   protected double m_Error;
 147  
 
 148  
   /** The number of instances used in the training pool */
 149  0
   protected int m_TrainPoolSize = 100;
 150  
 
 151  
   /**
 152  
    * Returns a string describing this object
 153  
    * @return a description of the classifier suitable for
 154  
    * displaying in the explorer/experimenter gui
 155  
    */
 156  
   public String globalInfo() {
 157  
 
 158  0
     return
 159  
         "Class for performing a Bias-Variance decomposition on any classifier "
 160  
       + "using the method specified in:\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.INPROCEEDINGS);
 175  0
     result.setValue(Field.AUTHOR, "Ron Kohavi and David H. Wolpert");
 176  0
     result.setValue(Field.YEAR, "1996");
 177  0
     result.setValue(Field.TITLE, "Bias Plus Variance Decomposition for Zero-One Loss Functions");
 178  0
     result.setValue(Field.BOOKTITLE, "Machine Learning: Proceedings of the Thirteenth International Conference");
 179  0
     result.setValue(Field.PUBLISHER, "Morgan Kaufmann");
 180  0
     result.setValue(Field.EDITOR, "Lorenza Saitta");
 181  0
     result.setValue(Field.PAGES, "275-283");
 182  0
     result.setValue(Field.PS, "http://robotics.stanford.edu/~ronnyk/biasVar.ps");
 183  
 
 184  0
     return result;
 185  
   }
 186  
 
 187  
   /**
 188  
    * Returns an enumeration describing the available options.
 189  
    *
 190  
    * @return an enumeration of all the available options.
 191  
    */
 192  
   public Enumeration listOptions() {
 193  
 
 194  0
     Vector newVector = new Vector(7);
 195  
 
 196  0
     newVector.addElement(new Option(
 197  
           "\tThe index of the class attribute.\n"+
 198  
           "\t(default last)",
 199  
           "c", 1, "-c <class index>"));
 200  0
     newVector.addElement(new Option(
 201  
           "\tThe name of the arff file used for the decomposition.",
 202  
           "t", 1, "-t <name of arff file>"));
 203  0
     newVector.addElement(new Option(
 204  
           "\tThe number of instances placed in the training pool.\n"
 205  
           + "\tThe remainder will be used for testing. (default 100)",
 206  
           "T", 1, "-T <training pool size>"));
 207  0
     newVector.addElement(new Option(
 208  
           "\tThe random number seed used.",
 209  
           "s", 1, "-s <seed>"));
 210  0
     newVector.addElement(new Option(
 211  
           "\tThe number of training repetitions used.\n"
 212  
           +"\t(default 50)",
 213  
           "x", 1, "-x <num>"));
 214  0
     newVector.addElement(new Option(
 215  
           "\tTurn on debugging output.",
 216  
           "D", 0, "-D"));
 217  0
     newVector.addElement(new Option(
 218  
           "\tFull class name of the learner used in the decomposition.\n"
 219  
           +"\teg: weka.classifiers.bayes.NaiveBayes",
 220  
           "W", 1, "-W <classifier class name>"));
 221  
 
 222  0
     if ((m_Classifier != null) &&
 223  
         (m_Classifier instanceof OptionHandler)) {
 224  0
       newVector.addElement(new Option(
 225  
             "",
 226  
             "", 0, "\nOptions specific to learner "
 227  
             + m_Classifier.getClass().getName()
 228  
             + ":"));
 229  0
       Enumeration enu = ((OptionHandler)m_Classifier).listOptions();
 230  0
       while (enu.hasMoreElements()) {
 231  0
         newVector.addElement(enu.nextElement());
 232  
       }
 233  
     }
 234  0
     return newVector.elements();
 235  
   }
 236  
 
 237  
   /**
 238  
    * Parses a given list of options. <p/>
 239  
    *
 240  
    <!-- options-start -->
 241  
    * Valid options are: <p/>
 242  
    *
 243  
    * <pre> -c &lt;class index&gt;
 244  
    *  The index of the class attribute.
 245  
    *  (default last)</pre>
 246  
    *
 247  
    * <pre> -t &lt;name of arff file&gt;
 248  
    *  The name of the arff file used for the decomposition.</pre>
 249  
    *
 250  
    * <pre> -T &lt;training pool size&gt;
 251  
    *  The number of instances placed in the training pool.
 252  
    *  The remainder will be used for testing. (default 100)</pre>
 253  
    *
 254  
    * <pre> -s &lt;seed&gt;
 255  
    *  The random number seed used.</pre>
 256  
    *
 257  
    * <pre> -x &lt;num&gt;
 258  
    *  The number of training repetitions used.
 259  
    *  (default 50)</pre>
 260  
    *
 261  
    * <pre> -D
 262  
    *  Turn on debugging output.</pre>
 263  
    *
 264  
    * <pre> -W &lt;classifier class name&gt;
 265  
    *  Full class name of the learner used in the decomposition.
 266  
    *  eg: weka.classifiers.bayes.NaiveBayes</pre>
 267  
    *
 268  
    * <pre>
 269  
    * Options specific to learner weka.classifiers.rules.ZeroR:
 270  
    * </pre>
 271  
    *
 272  
    * <pre> -D
 273  
    *  If set, classifier is run in debug mode and
 274  
    *  may output additional info to the console</pre>
 275  
    *
 276  
    <!-- options-end -->
 277  
    *
 278  
    * Options after -- are passed to the designated sub-learner. <p>
 279  
    *
 280  
    * @param options the list of options as an array of strings
 281  
    * @throws Exception if an option is not supported
 282  
    */
 283  
   public void setOptions(String[] options) throws Exception {
 284  
 
 285  0
     setDebug(Utils.getFlag('D', options));
 286  
 
 287  0
     String classIndex = Utils.getOption('c', options);
 288  0
     if (classIndex.length() != 0) {
 289  0
       if (classIndex.toLowerCase().equals("last")) {
 290  0
         setClassIndex(0);
 291  0
       } else if (classIndex.toLowerCase().equals("first")) {
 292  0
         setClassIndex(1);
 293  
       } else {
 294  0
         setClassIndex(Integer.parseInt(classIndex));
 295  
       }
 296  
     } else {
 297  0
       setClassIndex(0);
 298  
     }
 299  
 
 300  0
     String trainIterations = Utils.getOption('x', options);
 301  0
     if (trainIterations.length() != 0) {
 302  0
       setTrainIterations(Integer.parseInt(trainIterations));
 303  
     } else {
 304  0
       setTrainIterations(50);
 305  
     }
 306  
 
 307  0
     String trainPoolSize = Utils.getOption('T', options);
 308  0
     if (trainPoolSize.length() != 0) {
 309  0
       setTrainPoolSize(Integer.parseInt(trainPoolSize));
 310  
     } else {
 311  0
       setTrainPoolSize(100);
 312  
     }
 313  
 
 314  0
     String seedString = Utils.getOption('s', options);
 315  0
     if (seedString.length() != 0) {
 316  0
       setSeed(Integer.parseInt(seedString));
 317  
     } else {
 318  0
       setSeed(1);
 319  
     }
 320  
 
 321  0
     String dataFile = Utils.getOption('t', options);
 322  0
     if (dataFile.length() == 0) {
 323  0
       throw new Exception("An arff file must be specified"
 324  
           + " with the -t option.");
 325  
     }
 326  0
     setDataFileName(dataFile);
 327  
 
 328  0
     String classifierName = Utils.getOption('W', options);
 329  0
     if (classifierName.length() == 0) {
 330  0
       throw new Exception("A learner must be specified with the -W option.");
 331  
     }
 332  0
     setClassifier(AbstractClassifier.forName(classifierName,
 333  
           Utils.partitionOptions(options)));
 334  0
   }
 335  
 
 336  
   /**
 337  
    * Gets the current settings of the CheckClassifier.
 338  
    *
 339  
    * @return an array of strings suitable for passing to setOptions
 340  
    */
 341  
   public String [] getOptions() {
 342  
 
 343  0
     String [] classifierOptions = new String [0];
 344  0
     if ((m_Classifier != null) &&
 345  
         (m_Classifier instanceof OptionHandler)) {
 346  0
       classifierOptions = ((OptionHandler)m_Classifier).getOptions();
 347  
         }
 348  0
     String [] options = new String [classifierOptions.length + 14];
 349  0
     int current = 0;
 350  0
     if (getDebug()) {
 351  0
       options[current++] = "-D";
 352  
     }
 353  0
     options[current++] = "-c"; options[current++] = "" + getClassIndex();
 354  0
     options[current++] = "-x"; options[current++] = "" + getTrainIterations();
 355  0
     options[current++] = "-T"; options[current++] = "" + getTrainPoolSize();
 356  0
     options[current++] = "-s"; options[current++] = "" + getSeed();
 357  0
     if (getDataFileName() != null) {
 358  0
       options[current++] = "-t"; options[current++] = "" + getDataFileName();
 359  
     }
 360  0
     if (getClassifier() != null) {
 361  0
       options[current++] = "-W";
 362  0
       options[current++] = getClassifier().getClass().getName();
 363  
     }
 364  0
     options[current++] = "--";
 365  0
     System.arraycopy(classifierOptions, 0, options, current,
 366  
         classifierOptions.length);
 367  0
     current += classifierOptions.length;
 368  0
     while (current < options.length) {
 369  0
       options[current++] = "";
 370  
     }
 371  0
     return options;
 372  
   }
 373  
 
 374  
   /**
 375  
    * Get the number of instances in the training pool.
 376  
    *
 377  
    * @return number of instances in the training pool.
 378  
    */
 379  
   public int getTrainPoolSize() {
 380  
 
 381  0
     return m_TrainPoolSize;
 382  
   }
 383  
 
 384  
   /**
 385  
    * Set the number of instances in the training pool.
 386  
    *
 387  
    * @param numTrain number of instances in the training pool.
 388  
    */
 389  
   public void setTrainPoolSize(int numTrain) {
 390  
 
 391  0
     m_TrainPoolSize = numTrain;
 392  0
   }
 393  
 
 394  
   /**
 395  
    * Set the classifiers being analysed
 396  
    *
 397  
    * @param newClassifier the Classifier to use.
 398  
    */
 399  
   public void setClassifier(Classifier newClassifier) {
 400  
 
 401  0
     m_Classifier = newClassifier;
 402  0
   }
 403  
 
 404  
   /**
 405  
    * Gets the name of the classifier being analysed
 406  
    *
 407  
    * @return the classifier being analysed.
 408  
    */
 409  
   public Classifier getClassifier() {
 410  
 
 411  0
     return m_Classifier;
 412  
   }
 413  
 
 414  
   /**
 415  
    * Sets debugging mode
 416  
    *
 417  
    * @param debug true if debug output should be printed
 418  
    */
 419  
   public void setDebug(boolean debug) {
 420  
 
 421  0
     m_Debug = debug;
 422  0
   }
 423  
 
 424  
   /**
 425  
    * Gets whether debugging is turned on
 426  
    *
 427  
    * @return true if debugging output is on
 428  
    */
 429  
   public boolean getDebug() {
 430  
 
 431  0
     return m_Debug;
 432  
   }
 433  
 
 434  
   /**
 435  
    * Sets the random number seed
 436  
    *
 437  
    * @param seed the random number seed
 438  
    */
 439  
   public void setSeed(int seed) {
 440  
 
 441  0
     m_Seed = seed;
 442  0
   }
 443  
 
 444  
   /**
 445  
    * Gets the random number seed
 446  
    *
 447  
    * @return the random number seed
 448  
    */
 449  
   public int getSeed() {
 450  
 
 451  0
     return m_Seed;
 452  
   }
 453  
 
 454  
   /**
 455  
    * Sets the maximum number of boost iterations
 456  
    *
 457  
    * @param trainIterations the number of boost iterations
 458  
    */
 459  
   public void setTrainIterations(int trainIterations) {
 460  
 
 461  0
     m_TrainIterations = trainIterations;
 462  0
   }
 463  
 
 464  
   /**
 465  
    * Gets the maximum number of boost iterations
 466  
    *
 467  
    * @return the maximum number of boost iterations
 468  
    */
 469  
   public int getTrainIterations() {
 470  
 
 471  0
     return m_TrainIterations;
 472  
   }
 473  
 
 474  
   /**
 475  
    * Sets the name of the data file used for the decomposition
 476  
    *
 477  
    * @param dataFileName the data file to use
 478  
    */
 479  
   public void setDataFileName(String dataFileName) {
 480  
 
 481  0
     m_DataFileName = dataFileName;
 482  0
   }
 483  
 
 484  
   /**
 485  
    * Get the name of the data file used for the decomposition
 486  
    *
 487  
    * @return the name of the data file
 488  
    */
 489  
   public String getDataFileName() {
 490  
 
 491  0
     return m_DataFileName;
 492  
   }
 493  
 
 494  
   /**
 495  
    * Get the index (starting from 1) of the attribute used as the class.
 496  
    *
 497  
    * @return the index of the class attribute
 498  
    */
 499  
   public int getClassIndex() {
 500  
 
 501  0
     return m_ClassIndex + 1;
 502  
   }
 503  
 
 504  
   /**
 505  
    * Sets index of attribute to discretize on
 506  
    *
 507  
    * @param classIndex the index (starting from 1) of the class attribute
 508  
    */
 509  
   public void setClassIndex(int classIndex) {
 510  
 
 511  0
     m_ClassIndex = classIndex - 1;
 512  0
   }
 513  
 
 514  
   /**
 515  
    * Get the calculated bias squared
 516  
    *
 517  
    * @return the bias squared
 518  
    */
 519  
   public double getBias() {
 520  
 
 521  0
     return m_Bias;
 522  
   }
 523  
 
 524  
   /**
 525  
    * Get the calculated variance
 526  
    *
 527  
    * @return the variance
 528  
    */
 529  
   public double getVariance() {
 530  
 
 531  0
     return m_Variance;
 532  
   }
 533  
 
 534  
   /**
 535  
    * Get the calculated sigma squared
 536  
    *
 537  
    * @return the sigma squared
 538  
    */
 539  
   public double getSigma() {
 540  
 
 541  0
     return m_Sigma;
 542  
   }
 543  
 
 544  
   /**
 545  
    * Get the calculated error rate
 546  
    *
 547  
    * @return the error rate
 548  
    */
 549  
   public double getError() {
 550  
 
 551  0
     return m_Error;
 552  
   }
 553  
 
 554  
   /**
 555  
    * Carry out the bias-variance decomposition
 556  
    *
 557  
    * @throws Exception if the decomposition couldn't be carried out
 558  
    */
 559  
   public void decompose() throws Exception {
 560  
 
 561  0
     Reader dataReader = new BufferedReader(new FileReader(m_DataFileName));
 562  0
     Instances data = new Instances(dataReader);
 563  
 
 564  0
     if (m_ClassIndex < 0) {
 565  0
       data.setClassIndex(data.numAttributes() - 1);
 566  
     } else {
 567  0
       data.setClassIndex(m_ClassIndex);
 568  
     }
 569  0
     if (data.classAttribute().type() != Attribute.NOMINAL) {
 570  0
       throw new Exception("Class attribute must be nominal");
 571  
     }
 572  0
     int numClasses = data.numClasses();
 573  
 
 574  0
     data.deleteWithMissingClass();
 575  0
     if (data.checkForStringAttributes()) {
 576  0
       throw new Exception("Can't handle string attributes!");
 577  
     }
 578  
 
 579  0
     if (data.numInstances() < 2 * m_TrainPoolSize) {
 580  0
       throw new Exception("The dataset must contain at least "
 581  
           + (2 * m_TrainPoolSize) + " instances");
 582  
     }
 583  0
     Random random = new Random(m_Seed);
 584  0
     data.randomize(random);
 585  0
     Instances trainPool = new Instances(data, 0, m_TrainPoolSize);
 586  0
     Instances test = new Instances(data, m_TrainPoolSize,
 587  
         data.numInstances() - m_TrainPoolSize);
 588  0
     int numTest = test.numInstances();
 589  0
     double [][] instanceProbs = new double [numTest][numClasses];
 590  
 
 591  0
     m_Error = 0;
 592  0
     for (int i = 0; i < m_TrainIterations; i++) {
 593  0
       if (m_Debug) {
 594  0
         System.err.println("Iteration " + (i + 1));
 595  
       }
 596  0
       trainPool.randomize(random);
 597  0
       Instances train = new Instances(trainPool, 0, m_TrainPoolSize / 2);
 598  
 
 599  0
       Classifier current = AbstractClassifier.makeCopy(m_Classifier);
 600  0
       current.buildClassifier(train);
 601  
 
 602  
       //// Evaluate the classifier on test, updating BVD stats
 603  0
       for (int j = 0; j < numTest; j++) {
 604  0
         int pred = (int)current.classifyInstance(test.instance(j));
 605  0
         if (pred != test.instance(j).classValue()) {
 606  0
           m_Error++;
 607  
         }
 608  0
         instanceProbs[j][pred]++;
 609  
       }
 610  
     }
 611  0
     m_Error /= (m_TrainIterations * numTest);
 612  
 
 613  
     // Average the BV over each instance in test.
 614  0
     m_Bias = 0;
 615  0
     m_Variance = 0;
 616  0
     m_Sigma = 0;
 617  0
     for (int i = 0; i < numTest; i++) {
 618  0
       Instance current = test.instance(i);
 619  0
       double [] predProbs = instanceProbs[i];
 620  
       double pActual, pPred;
 621  0
       double bsum = 0, vsum = 0, ssum = 0;
 622  0
       for (int j = 0; j < numClasses; j++) {
 623  0
         pActual = (current.classValue() == j) ? 1 : 0; // Or via 1NN from test data?
 624  0
         pPred = predProbs[j] / m_TrainIterations;
 625  0
         bsum += (pActual - pPred) * (pActual - pPred)
 626  
           - pPred * (1 - pPred) / (m_TrainIterations - 1);
 627  0
         vsum += pPred * pPred;
 628  0
         ssum += pActual * pActual;
 629  
       }
 630  0
       m_Bias += bsum;
 631  0
       m_Variance += (1 - vsum);
 632  0
       m_Sigma += (1 - ssum);
 633  
     }
 634  0
     m_Bias /= (2 * numTest);
 635  0
     m_Variance /= (2 * numTest);
 636  0
     m_Sigma /= (2 * numTest);
 637  
 
 638  0
     if (m_Debug) {
 639  0
       System.err.println("Decomposition finished");
 640  
     }
 641  0
   }
 642  
 
 643  
 
 644  
   /**
 645  
    * Returns description of the bias-variance decomposition results.
 646  
    *
 647  
    * @return the bias-variance decomposition results as a string
 648  
    */
 649  
   public String toString() {
 650  
 
 651  0
     String result = "\nBias-Variance Decomposition\n";
 652  
 
 653  0
     if (getClassifier() == null) {
 654  0
       return "Invalid setup";
 655  
     }
 656  
 
 657  0
     result += "\nClassifier   : " + getClassifier().getClass().getName();
 658  0
     if (getClassifier() instanceof OptionHandler) {
 659  0
       result += Utils.joinOptions(((OptionHandler)m_Classifier).getOptions());
 660  
     }
 661  0
     result += "\nData File    : " + getDataFileName();
 662  0
     result += "\nClass Index  : ";
 663  0
     if (getClassIndex() == 0) {
 664  0
       result += "last";
 665  
     } else {
 666  0
       result += getClassIndex();
 667  
     }
 668  0
     result += "\nTraining Pool: " + getTrainPoolSize();
 669  0
     result += "\nIterations   : " + getTrainIterations();
 670  0
     result += "\nSeed         : " + getSeed();
 671  0
     result += "\nError        : " + Utils.doubleToString(getError(), 6, 4);
 672  0
     result += "\nSigma^2      : " + Utils.doubleToString(getSigma(), 6, 4);
 673  0
     result += "\nBias^2       : " + Utils.doubleToString(getBias(), 6, 4);
 674  0
     result += "\nVariance     : " + Utils.doubleToString(getVariance(), 6, 4);
 675  
 
 676  0
     return result + "\n";
 677  
   }
 678  
 
 679  
   /**
 680  
    * Returns the revision string.
 681  
    *
 682  
    * @return                the revision
 683  
    */
 684  
   public String getRevision() {
 685  0
     return RevisionUtils.extract("$Revision: 8034 $");
 686  
   }
 687  
 
 688  
   /**
 689  
    * Test method for this class
 690  
    *
 691  
    * @param args the command line arguments
 692  
    */
 693  
   public static void main(String [] args) {
 694  
 
 695  
     try {
 696  0
       BVDecompose bvd = new BVDecompose();
 697  
 
 698  
       try {
 699  0
         bvd.setOptions(args);
 700  0
         Utils.checkForRemainingOptions(args);
 701  0
       } catch (Exception ex) {
 702  0
         String result = ex.getMessage() + "\nBVDecompose Options:\n\n";
 703  0
         Enumeration enu = bvd.listOptions();
 704  0
         while (enu.hasMoreElements()) {
 705  0
           Option option = (Option) enu.nextElement();
 706  0
           result += option.synopsis() + "\n" + option.description() + "\n";
 707  0
         }
 708  0
         throw new Exception(result);
 709  0
       }
 710  
 
 711  0
       bvd.decompose();
 712  0
       System.out.println(bvd.toString());
 713  0
     } catch (Exception ex) {
 714  0
       System.err.println(ex.getMessage());
 715  0
     }
 716  0
   }
 717  
 }