OrdinalClassClassifier.java
Upload User: rhdiban
Upload Date: 2013-08-09
Package Size: 15085k
Code Size: 10k
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.  *    OrdinalClassClassifier.java
  18.  *    Copyright (C) 2001 Mark Hall
  19.  *
  20.  */
  21. package weka.classifiers.meta;
  22. import weka.classifiers.Evaluation;
  23. import weka.classifiers.Classifier;
  24. import weka.classifiers.DistributionClassifier;
  25. import weka.classifiers.rules.ZeroR;
  26. import java.io.Serializable;
  27. import weka.core.*;
  28. import weka.filters.unsupervised.attribute.MakeIndicator;
  29. import weka.filters.Filter;
  30. import java.util.BitSet;
  31. import java.util.Enumeration;
  32. import java.util.Vector;
  33. /**
  34.  * Meta classifier for transforming an ordinal class problem to a series
  35.  * of binary class problems. For more information see: <p>
  36.  *
  37.  * Frank, E. and Hall, M. (in press). <i>A simple approach to ordinal 
  38.  * prediction.</i> 12th European Conference on Machine Learning. 
  39.  * Freiburg, Germany. <p>
  40.  *
  41.  * Valid options are: <p>
  42.  *
  43.  * -W classname <br>
  44.  * Specify the full class name of a learner as the basis for 
  45.  * the ordinalclassclassifier (required).<p>
  46.  *
  47.  * @author <a href="mailto:mhall@cs.waikato.ac.nz">Mark Hall</a>
  48.  * @version $Revision 1.0 $
  49.  * @see DistributionClassifier
  50.  * @see OptionHandler
  51.  */
  52. public class OrdinalClassClassifier extends DistributionClassifier 
  53. implements OptionHandler {
  54.   /** The classifiers. (One for each class.) */
  55.   private Classifier [] m_Classifiers;
  56.   /** The filters used to transform the class. */
  57.   private MakeIndicator[] m_ClassFilters;
  58.   /** The class name of the base classifier. */
  59.   private DistributionClassifier m_Classifier = new weka.classifiers.rules.ZeroR();
  60.   /** Internal copy of the class attribute for output purposes */
  61.   private Attribute m_ClassAttribute;
  62.   /** ZeroR classifier for when all base classifier return zero probability. */
  63.   private ZeroR m_ZeroR;
  64.   /**
  65.    * Returns a string describing this attribute evaluator
  66.    * @return a description of the evaluator suitable for
  67.    * displaying in the explorer/experimenter gui
  68.    */
  69.   public String globalInfo() {
  70.     return " Meta classifier that allows standard classification algorithms "
  71.       +"to be applied to ordinal class problems.  For more information see: "
  72.       +"Frank, E. and Hall, M. (in press). A simple approach to ordinal "
  73.       +"prediction. 12th European Conference on Machine Learning. Freiburg, "
  74.       +"Germany.";
  75.   }
  76.   /**
  77.    * Builds the classifiers.
  78.    *
  79.    * @param insts the training data.
  80.    * @exception Exception if a classifier can't be built
  81.    */
  82.   public void buildClassifier(Instances insts) throws Exception {
  83.     Instances newInsts;
  84.     
  85.     if (m_Classifier == null) {
  86.       throw new Exception("No base classifier has been set!");
  87.     }
  88.     m_ZeroR = new ZeroR();
  89.     m_ZeroR.buildClassifier(insts);
  90.     int numClassifiers = insts.numClasses() - 1;
  91.     numClassifiers = (numClassifiers == 0) ? 1 : numClassifiers;
  92.     if (numClassifiers == 1) {
  93.       m_Classifiers = Classifier.makeCopies(m_Classifier, 1);
  94.       m_Classifiers[0].buildClassifier(insts);
  95.     } else {
  96.       m_Classifiers = Classifier.makeCopies(m_Classifier, numClassifiers);
  97.       m_ClassFilters = new MakeIndicator[numClassifiers];
  98.       for (int i = 0; i < m_Classifiers.length; i++) {
  99. m_ClassFilters[i] = new MakeIndicator();
  100. m_ClassFilters[i].setAttributeIndex(insts.classIndex());
  101. m_ClassFilters[i].setValueIndices(""+(i+2)+"-last");
  102. m_ClassFilters[i].setNumeric(false);
  103. m_ClassFilters[i].setInputFormat(insts);
  104. newInsts = Filter.useFilter(insts, m_ClassFilters[i]);
  105. m_Classifiers[i].buildClassifier(newInsts);
  106.       }
  107.     }
  108.     m_ClassAttribute = insts.classAttribute();
  109.   }
  110.   
  111.   /**
  112.    * Returns the distribution for an instance.
  113.    *
  114.    * @exception Exception if the distribution can't be computed successfully
  115.    */
  116.   public double [] distributionForInstance(Instance inst) throws Exception {
  117.     
  118.     if (m_Classifiers.length == 1) {
  119.       return ((DistributionClassifier)m_Classifiers[0])
  120.         .distributionForInstance(inst);
  121.     }
  122.     double [] probs = new double[inst.numClasses()];
  123.     
  124.     double [][] distributions = new double[m_ClassFilters.length][0];
  125.     for(int i = 0; i < m_ClassFilters.length; i++) {
  126.       m_ClassFilters[i].input(inst);
  127.       m_ClassFilters[i].batchFinished();
  128.       
  129.       distributions[i] = ((DistributionClassifier)m_Classifiers[i])
  130. .distributionForInstance(m_ClassFilters[i].output());
  131.       
  132.     }
  133.     for (int i = 0; i < inst.numClasses(); i++) {
  134.       if (i == 0) {
  135. probs[i] = distributions[0][0];
  136.       } else if (i == inst.numClasses() - 1) {
  137. probs[i] = distributions[i - 1][1];
  138.       } else {
  139. probs[i] = distributions[i - 1][1] - distributions[i][1];
  140. if (!(probs[i] > 0)) {
  141.   System.err.println("Warning: estimated probability " + probs[i] +
  142.      ". Rounding to 0.");
  143.   probs[i] = 0;
  144. }
  145.       }
  146.     }
  147.     if (Utils.gr(Utils.sum(probs), 0)) {
  148.       Utils.normalize(probs);
  149.       return probs;
  150.     } else {
  151.       return m_ZeroR.distributionForInstance(inst);
  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 vec = new Vector(1);
  161.     Object c;
  162.     
  163.     vec.addElement(new Option(
  164.        "tSets the base classifier.",
  165.        "W", 1, "-W <base classifier>"));
  166.     
  167.     if (m_Classifier != null) {
  168.       try {
  169. vec.addElement(new Option("",
  170.   "", 0, "nOptions specific to classifier "
  171.   + m_Classifier.getClass().getName() + ":"));
  172. Enumeration enum = ((OptionHandler)m_Classifier).listOptions();
  173. while (enum.hasMoreElements()) {
  174.   vec.addElement(enum.nextElement());
  175. }
  176.       } catch (Exception e) {
  177.       }
  178.     }
  179.     return vec.elements();
  180.   }
  181.   /**
  182.    * Parses a given list of options. Valid options are:<p>
  183.    *
  184.    * -W classname <br>
  185.    * Specify the full class name of a learner as the basis for 
  186.    * the ordinalclassclassifier (required).<p>
  187.    *
  188.    * @param options the list of options as an array of strings
  189.    * @exception Exception if an option is not supported
  190.    */
  191.   public void setOptions(String[] options) throws Exception {
  192.   
  193.     String classifierName = Utils.getOption('W', options);
  194.     if (classifierName.length() == 0) {
  195.       throw new Exception("A classifier must be specified with"
  196.   + " the -W option.");
  197.     }
  198.     setDistributionClassifier((DistributionClassifier)
  199.                               Classifier.forName(classifierName,
  200.                                                  Utils.partitionOptions(options)));
  201.   }
  202.   /**
  203.    * Gets the current settings of the Classifier.
  204.    *
  205.    * @return an array of strings suitable for passing to setOptions
  206.    */
  207.   public String [] getOptions() {
  208.     
  209.     String [] classifierOptions = new String [0];
  210.     if ((m_Classifier != null) &&
  211. (m_Classifier instanceof OptionHandler)) {
  212.       classifierOptions = ((OptionHandler)m_Classifier).getOptions();
  213.     }
  214.     String [] options = new String [classifierOptions.length + 3];
  215.     int current = 0;
  216.     if (getDistributionClassifier() != null) {
  217.       options[current++] = "-W";
  218.       options[current++] = getDistributionClassifier().getClass().getName();
  219.     }
  220.     options[current++] = "--";
  221.     System.arraycopy(classifierOptions, 0, options, current, 
  222.      classifierOptions.length);
  223.     current += classifierOptions.length;
  224.     while (current < options.length) {
  225.       options[current++] = "";
  226.     }
  227.     return options;
  228.   }
  229.   
  230.   /**
  231.    * @return tip text for this property suitable for
  232.    * displaying in the explorer/experimenter gui
  233.    */
  234.   public String distributionClassifierTipText() {
  235.     return "Sets the DistributionClassifier used as the basis for "
  236.       + "the multi-class classifier.";
  237.   }
  238.   /**
  239.    * Set the base classifier. 
  240.    *
  241.    * @param newClassifier the Classifier to use.
  242.    */
  243.   public void setDistributionClassifier(DistributionClassifier newClassifier) {
  244.     m_Classifier = newClassifier;
  245.   }
  246.   /**
  247.    * Get the classifier used as the classifier
  248.    *
  249.    * @return the classifier used as the classifier
  250.    */
  251.   public DistributionClassifier getDistributionClassifier() {
  252.     return m_Classifier;
  253.   }
  254.   /**
  255.    * Prints the classifiers.
  256.    */
  257.   public String toString() {
  258.     
  259.     if (m_Classifiers == null) {
  260.       return "OrdinalClassClassifier: No model built yet.";
  261.     }
  262.     StringBuffer text = new StringBuffer();
  263.     text.append("OrdinalClassClassifiernn");
  264.     for (int i = 0; i < m_Classifiers.length; i++) {
  265.       text.append("Classifier ").append(i + 1);
  266.       if (m_Classifiers[i] != null) {
  267.  if ((m_ClassFilters != null) && (m_ClassFilters[i] != null)) {
  268.           text.append(", using indicator values: ");
  269.           text.append(m_ClassFilters[i].getValueRange());
  270.         }
  271.         text.append('n');
  272.         text.append(m_Classifiers[i].toString() + "n");
  273.       } else {
  274.         text.append(" Skipped (no training examples)n");
  275.       }
  276.     }
  277.     return text.toString();
  278.   }
  279.   /**
  280.    * Main method for testing this class.
  281.    *
  282.    * @param argv the options
  283.    */
  284.   public static void main(String [] argv) {
  285.     DistributionClassifier scheme;
  286.     try {
  287.       scheme = new OrdinalClassClassifier();
  288.       System.out.println(Evaluation.evaluateModel(scheme, argv));
  289.     } catch (Exception e) {
  290.       e.printStackTrace();
  291.       System.err.println(e.getMessage());
  292.     }
  293.   }
  294. }