RegressionByDiscretization.java
Upload User: rhdiban
Upload Date: 2013-08-09
Package Size: 15085k
Code Size: 11k
Category:

Windows Develop

Development Platform:

Java

  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.  *    RegressionByDiscretization.java
  18.  *    Copyright (C) 1999 Len Trigg
  19.  *
  20.  */
  21. package weka.classifiers;
  22. import java.io.*;
  23. import java.util.*;
  24. import weka.core.*;
  25. import weka.estimators.*;
  26. import weka.filters.*;
  27. /**
  28.  * Class for a regression scheme that employs any distribution
  29.  * classifier on a copy of the data that has the class attribute
  30.  * discretized. The predicted value is the expected value of the 
  31.  * mean class value for each discretized interval (based on the 
  32.  * predicted probabilities for each interval).<p>
  33.  *
  34.  * Valid options are:<p>
  35.  *
  36.  * -D <br>
  37.  * Produce debugging output. <p>
  38.  *
  39.  * -W classname <br>
  40.  * Specify the full class name of a classifier as the basis for 
  41.  * regression (required).<p>
  42.  *
  43.  * -B num <br>
  44.  * The number of bins the class attribute will be discretized into.
  45.  * (default 10) <p>
  46.  *
  47.  * -O <br>
  48.  * Optimize number of bins (values up to and including the -B option will
  49.  * be considered). (default no debugging output) <p>
  50.  *
  51.  * Any options after -- will be passed to the sub-classifier. <p>
  52.  *
  53.  * @author Len Trigg (trigg@cs.waikato.ac.nz)
  54.  * @version $Revision: 1.13 $
  55.  */
  56. public class RegressionByDiscretization extends Classifier 
  57.   implements OptionHandler {
  58.   /** The subclassifier. */
  59.   protected DistributionClassifier m_Classifier = new weka.classifiers.ZeroR();
  60.   
  61.   /** The discretization filter. */
  62.   protected DiscretizeFilter m_Discretizer;
  63.   /** The number of classes in the Discretized training data. */
  64.   protected int m_NumBins = 10;
  65.   /** The mean values for each Discretized class interval. */
  66.   protected double [] m_ClassMeans;
  67.   /** Whether debugging output will be printed */
  68.   protected boolean m_Debug;
  69.   /** Whether the Discretizer will optimise the number of bins */
  70.   protected boolean m_OptimizeBins;
  71.   /**
  72.    * Generates the classifier.
  73.    *
  74.    * @param instances set of instances serving as training data 
  75.    * @exception Exception if the classifier has not been generated successfully
  76.    */
  77.   public void buildClassifier(Instances instances) throws Exception {
  78.     if (!instances.classAttribute().isNumeric()) {
  79.       throw new Exception ("Class attribute has to be numeric");
  80.     }
  81.     // Discretize the training data
  82.     m_Discretizer = new DiscretizeFilter();
  83.     m_Discretizer.setBins(m_NumBins);
  84.     if (m_OptimizeBins) {
  85.       m_Discretizer.setFindNumBins(true);
  86.     }
  87.     m_Discretizer.setUseMDL(false);
  88.     m_Discretizer.setAttributeIndices(""+ (instances.classIndex() + 1));
  89.     m_Discretizer.setInputFormat(instances);
  90.     Instances newTrain = Filter.useFilter(instances, m_Discretizer);
  91.     int numClasses = newTrain.numClasses();
  92.     // Calculate the mean value for each bin of the new class attribute
  93.     m_ClassMeans = new double [numClasses];
  94.     int [] classCounts = new int [numClasses];
  95.     for (int i = 0; i < instances.numInstances(); i++) {
  96.       int classVal = (int) newTrain.instance(i).classValue();
  97.       classCounts[classVal]++;
  98.       m_ClassMeans[classVal] += instances.instance(i).classValue();
  99.     }
  100.     for (int i = 0; i < numClasses; i++) {
  101.       if (classCounts[i] > 0) {
  102. m_ClassMeans[i] /= classCounts[i];
  103.       }
  104.     }
  105.     if (m_Debug) {
  106.       System.out.println("Boundaries    Bin Mean");
  107.       System.out.println("======================");
  108.       System.out.println("-infinity");
  109.       double [] cutPoints = m_Discretizer.getCutPoints(instances.classIndex());
  110.       if (cutPoints != null) {
  111. for (int i = 0; i < cutPoints.length; i++) {
  112.   System.out.println("              " + m_ClassMeans[i]);
  113.   System.out.println("" + cutPoints[i]);
  114. }
  115.       }
  116.       System.out.println("              " 
  117.  + m_ClassMeans[m_ClassMeans.length - 1]);
  118.       System.out.println("infinity");
  119.     }
  120.     // Train the sub-classifier
  121.     m_Classifier.buildClassifier(newTrain);
  122.   }
  123.   /**
  124.    * Returns a predicted class for the test instance.
  125.    *
  126.    * @param instance the instance to be classified
  127.    * @return predicted class value
  128.    * @exception Exception if the prediction couldn't be made
  129.    */
  130.   public double classifyInstance(Instance instance) 
  131.        throws Exception {  
  132.     // Discretize the test instance
  133.     if (m_Discretizer.numPendingOutput() > 0) {
  134.       throw new Exception("DiscretizeFilter output queue not empty");
  135.     }
  136.     if (m_Discretizer.input(instance)) {
  137.       m_Discretizer.batchFinished();
  138.       Instance newInstance = m_Discretizer.output();
  139.       double [] probs = m_Classifier.distributionForInstance(newInstance);
  140.       
  141.       double prediction = 0, probSum = 0;
  142.       for (int j = 0; j < probs.length; j++) {
  143. prediction += probs[j] * m_ClassMeans[j];
  144. probSum += probs[j];
  145.       }
  146.       
  147.       return prediction / probSum;
  148.       
  149.     } else {
  150.       throw new Exception("DiscretizeFilter didn't make the test instance"
  151.   + " immediately available");
  152.     }
  153.   }
  154.   /**
  155.    * Returns an enumeration describing the available options
  156.    *
  157.    * @return an enumeration of all the available options
  158.    */
  159.   public Enumeration listOptions() {
  160.     Vector newVector = new Vector(3);
  161.     newVector.addElement(new Option("tProduce debugging output."
  162.     + "t(default no debugging output)",
  163.     "D", 0,"-D"));
  164.     newVector.addElement(new Option("tNumber of bins the class attribute will"
  165.     + " be discretized into.n"
  166.     + "t(default 10)",
  167.     "B", 1,"-B"));
  168.     newVector.addElement(new Option("tOptimize number of bins (values"
  169.     + " up to and including the -B option will"
  170.     + " be considered)n"
  171.     + "t(default no debugging output)",
  172.     "O", 0,"-O"));
  173.     newVector.addElement(new Option("tFull class name of sub-classifier to"
  174.     + " use for the regression.n"
  175.     + "teg: weka.classifiers.NaiveBayes",
  176.     "W", 1,"-W"));
  177.     return newVector.elements();
  178.   }
  179.   /**
  180.    * Parses a given list of options. Valid options are:<p>
  181.    *
  182.    * -D <br>
  183.    * Produce debugging output. <p>
  184.    *
  185.    * -W classname <br>
  186.    * Specify the full class name of a classifier as the basis for 
  187.    * regression (required).<p>
  188.    *
  189.    * -B num <br>
  190.    * The number of bins the class attribute will be discretized into.
  191.    * (default 10) <p>
  192.    *
  193.    * -O <br>
  194.    * Optimize number of bins (values up to and including the -B option will
  195.    * be considered). (default no debugging output) <p>
  196.    *
  197.    * Any options after -- will be passed to the sub-classifier. <p>
  198.    *
  199.    * @param options the list of options as an array of strings
  200.    * @exception Exception if an option is not supported
  201.    */
  202.   public void setOptions(String[] options) throws Exception {
  203.     String binString = Utils.getOption('B', options);
  204.     if (binString.length() != 0) {
  205.       setNumBins(Integer.parseInt(binString));
  206.     } else {
  207.       setNumBins(10);
  208.     }
  209.     setDebug(Utils.getFlag('D', options));
  210.     setOptimizeBins(Utils.getFlag('O', options));
  211.     String classifierName = Utils.getOption('W', options);
  212.     if (classifierName.length() == 0) {
  213.       throw new Exception("A classifier must be specified with"
  214.   + " the -W option.");
  215.     }
  216.     setClassifier(Classifier.forName(classifierName,
  217.      Utils.partitionOptions(options)));
  218.   }
  219.   /**
  220.    * Gets the current settings of the Classifier.
  221.    *
  222.    * @return an array of strings suitable for passing to setOptions
  223.    */
  224.   public String [] getOptions() {
  225.     String [] classifierOptions = new String [0];
  226.     if ((m_Classifier != null) && 
  227. (m_Classifier instanceof OptionHandler)) {
  228.       classifierOptions = ((OptionHandler)m_Classifier).getOptions();
  229.     }
  230.     String [] options = new String [classifierOptions.length + 7];
  231.     int current = 0;
  232.     if (getDebug()) {
  233.       options[current++] = "-D";
  234.     }
  235.     if (getOptimizeBins()) {
  236.       options[current++] = "-O";
  237.     }
  238.     options[current++] = "-B"; options[current++] = "" + getNumBins();
  239.     if (getClassifier() != null) {
  240.       options[current++] = "-W";
  241.       options[current++] = getClassifier().getClass().getName();
  242.     }
  243.     options[current++] = "--";
  244.     System.arraycopy(classifierOptions, 0, options, current, 
  245.      classifierOptions.length);
  246.     current += classifierOptions.length;
  247.     while (current < options.length) {
  248.       options[current++] = "";
  249.     }
  250.     return options;
  251.   }
  252.   
  253.   /**
  254.    * Set the classifier for boosting. 
  255.    *
  256.    * @param newClassifier the Classifier to use.
  257.    */
  258.   public void setClassifier(Classifier newClassifier) {
  259.     m_Classifier = (DistributionClassifier)newClassifier;
  260.   }
  261.   /**
  262.    * Get the classifier used as the classifier
  263.    *
  264.    * @return the classifier used as the classifier
  265.    */
  266.   public Classifier getClassifier() {
  267.     return m_Classifier;
  268.   }
  269.   /**
  270.    * Sets whether the discretizer optimizes the number of bins
  271.    *
  272.    * @param optimize true if the discretizer should optimize the number of bins
  273.    */
  274.   public void setOptimizeBins(boolean optimize) {
  275.     m_OptimizeBins = optimize;
  276.   }
  277.   /**
  278.    * Gets whether the discretizer optimizes the number of bins
  279.    *
  280.    * @return true if the discretizer should optimize the number of bins
  281.    */
  282.   public boolean getOptimizeBins() {
  283.     return m_OptimizeBins;
  284.   }
  285.   /**
  286.    * Sets whether debugging output will be printed
  287.    *
  288.    * @param debug true if debug output should be printed
  289.    */
  290.   public void setDebug(boolean debug) {
  291.     m_Debug = debug;
  292.   }
  293.   /**
  294.    * Gets whether debugging output will be printed
  295.    *
  296.    * @return true if debug output should be printed
  297.    */
  298.   public boolean getDebug() {
  299.     return m_Debug;
  300.   }
  301.   /**
  302.    * Sets the number of bins the class attribute will be discretized into.
  303.    *
  304.    * @param numBins the number of bins to use
  305.    */
  306.   public void setNumBins(int numBins) {
  307.     m_NumBins = numBins;
  308.   }
  309.   /**
  310.    * Gets the number of bins the class attribute will be discretized into.
  311.    *
  312.    * @return the number of bins to use
  313.    */
  314.   public int getNumBins() {
  315.     return m_NumBins;
  316.   }
  317.   /**
  318.    * Returns a description of the classifier.
  319.    *
  320.    * @return a description of the classifier as a string.
  321.    */
  322.   public String toString() {
  323.     StringBuffer text = new StringBuffer();
  324.     int attIndex;
  325.     text.append("Regression by discretization");
  326.     if (m_Classifier == null) {
  327.       text.append(": No model built yet.");
  328.     } else {
  329.       text.append("nnClass attribute discretized into " 
  330.   + m_ClassMeans.length + " valuesn");
  331.       text.append("nSubclassifier: " + m_Classifier.getClass().getName() 
  332.   + "nn");
  333.       text.append(m_Classifier.toString());
  334.     }
  335.     return text.toString();
  336.   }
  337.  
  338.   /**
  339.    * Main method for testing this class.
  340.    *
  341.    * @param argv the options
  342.    */
  343.   public static void main(String [] argv) {
  344.     try {
  345.       System.out.println(Evaluation.evaluateModel(
  346.  new RegressionByDiscretization(), argv));
  347.     } catch (Exception ex) {
  348.       ex.printStackTrace();
  349.       System.out.println(ex.getMessage());
  350.     }
  351.   }
  352. }