AttributeSelectedClassifier.java
Upload User: rhdiban
Upload Date: 2013-08-09
Package Size: 15085k
Code Size: 16k
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.  *    AttributeSelectedClassifier.java
  18.  *    Copyright (C) 2000 Mark Hall
  19.  *
  20.  */
  21. package weka.classifiers.meta;
  22. import weka.classifiers.Classifier;
  23. import weka.classifiers.DistributionClassifier;
  24. import weka.classifiers.Evaluation;
  25. import weka.classifiers.bayes.NaiveBayes;
  26. import weka.classifiers.rules.ZeroR;
  27. import java.io.*;
  28. import java.util.*;
  29. import weka.core.*;
  30. import weka.attributeSelection.*;
  31. /**
  32.  * Class for running an arbitrary classifier on data that has been reduced
  33.  * through attribute selection. <p>
  34.  *
  35.  * Valid options from the command line are:<p>
  36.  *
  37.  * -B classifierstring <br>
  38.  * Classifierstring should contain the full class name of a classifier
  39.  * followed by options to the classifier.
  40.  * (required).<p>
  41.  *
  42.  * -E evaluatorstring <br>
  43.  * Evaluatorstring should contain the full class name of an attribute
  44.  * evaluator followed by any options.
  45.  * (required).<p>
  46.  *
  47.  * -S searchstring <br>
  48.  * Searchstring should contain the full class name of a search method
  49.  * followed by any options.
  50.  * (required). <p>
  51.  *
  52.  * @author Mark Hall (mhall@cs.waikato.ac.nz)
  53.  * @version $Revision: 1.9 $
  54.  */
  55. public class AttributeSelectedClassifier extends DistributionClassifier 
  56. implements OptionHandler, AdditionalMeasureProducer {
  57.   /** The classifier */
  58.   protected Classifier m_Classifier = new weka.classifiers.rules.ZeroR();
  59.   /** The attribute selection object */
  60.   protected AttributeSelection m_AttributeSelection = null;
  61.   /** The attribute evaluator to use */
  62.   protected ASEvaluation m_Evaluator = 
  63.     new weka.attributeSelection.CfsSubsetEval();
  64.   /** The search method to use */
  65.   protected ASSearch m_Search = new weka.attributeSelection.BestFirst();
  66.   /** The header of the dimensionally reduced data */
  67.   protected Instances m_ReducedHeader;
  68.   /** The number of class vals in the training data (1 if class is numeric) */
  69.   protected int m_numClasses;
  70.   /** The number of attributes selected by the attribute selection phase */
  71.   protected double m_numAttributesSelected;
  72.   /** The time taken to select attributes in milliseconds */
  73.   protected double m_selectionTime;
  74.   /** The time taken to select attributes AND build the classifier */
  75.   protected double m_totalTime;
  76.  
  77.   /**
  78.    * Returns a string describing this search method
  79.    * @return a description of the search method suitable for
  80.    * displaying in the explorer/experimenter gui
  81.    */
  82.   public String globalInfo() {
  83.     return "Dimensionality of training and test data is reduced by "
  84.       +"attribute selection before being passed on to a classifier.";
  85.   }
  86.   /**
  87.    * Returns an enumeration describing the available options.
  88.    *
  89.    * @return an enumeration of all the available options.
  90.    */
  91.   public Enumeration listOptions() {
  92.      Vector newVector = new Vector(3);
  93.     newVector.addElement(new Option(
  94.       "tFull class name of classifier to use, followedn"
  95.       + "tby scheme options. (required)n"
  96.       + "teg: "weka.classifiers.bayes.NaiveBayes -D"",
  97.       "B", 1, "-B <classifier specification>"));
  98.     
  99.     newVector.addElement(new Option(
  100.       "tFull class name of attribute evaluator, followedn"
  101.       + "tby its options. (required)n"
  102.       + "teg: "weka.attributeSelection.CfsSubsetEval -L"",
  103.       "E", 1, "-E <attribute evaluator specification>"));
  104.     newVector.addElement(new Option(
  105.       "tFull class name of search method, followedn"
  106.       + "tby its options. (required)n"
  107.       + "teg: "weka.attributeSelection.BestFirst -D 1"",
  108.       "S", 1, "-S <attribute evaluator specification>"));
  109.     return newVector.elements();
  110.   }
  111.   /**
  112.    * Parses a given list of options. Valid options are:<p>
  113.    *
  114.    * -B classifierstring <br>
  115.    * Classifierstring should contain the full class name of a classifier
  116.    * followed by options to the classifier.
  117.    * (required).<p>
  118.    *
  119.    * -E evaluatorstring <br>
  120.    * Evaluatorstring should contain the full class name of an attribute
  121.    * evaluator followed by any options.
  122.    * (required).<p>
  123.    *
  124.    * -S searchstring <br>
  125.    * Searchstring should contain the full class name of a search method
  126.    * followed by any options.
  127.    * (required). <p>
  128.    *
  129.    * @param options the list of options as an array of strings
  130.    * @exception Exception if an option is not supported
  131.    */
  132.   public void setOptions(String[] options) throws Exception {
  133.     String classifierString = Utils.getOption('B', options);
  134.     if (classifierString.length() == 0) {
  135.       throw new Exception("A classifier must be specified"
  136.   + " with the -B option.");
  137.     }
  138.     String [] classifierSpec = Utils.splitOptions(classifierString);
  139.     if (classifierSpec.length == 0) {
  140.       throw new Exception("Invalid classifier specification string");
  141.     }
  142.     String classifierName = classifierSpec[0];
  143.     classifierSpec[0] = "";
  144.     setClassifier(Classifier.forName(classifierName, classifierSpec));
  145.     // same for attribute evaluator
  146.      String evaluatorString = Utils.getOption('E', options);
  147.     if (evaluatorString.length() == 0) {
  148.       throw new Exception("An attribute evaluator must be specified"
  149.   + " with the -E option.");
  150.     }
  151.     String [] evaluatorSpec = Utils.splitOptions(evaluatorString);
  152.     if (evaluatorSpec.length == 0) {
  153.       throw new Exception("Invalid attribute evaluator specification string");
  154.     }
  155.     String evaluatorName = evaluatorSpec[0];
  156.     evaluatorSpec[0] = "";
  157.     setEvaluator(ASEvaluation.forName(evaluatorName, evaluatorSpec));
  158.     // same for search method
  159.     String searchString = Utils.getOption('S', options);
  160.     if (searchString.length() == 0) {
  161.       throw new Exception("A search method must be specified"
  162.   + " with the -S option.");
  163.     }
  164.     String [] searchSpec = Utils.splitOptions(searchString);
  165.     if (searchSpec.length == 0) {
  166.       throw new Exception("Invalid search specification string");
  167.     }
  168.     String searchName = searchSpec[0];
  169.     searchSpec[0] = "";
  170.     setSearch(ASSearch.forName(searchName, searchSpec));
  171.   }
  172.   /**
  173.    * Gets the current settings of the Classifier.
  174.    *
  175.    * @return an array of strings suitable for passing to setOptions
  176.    */
  177.   public String [] getOptions() {
  178.     String [] options = new String [6];
  179.     int current = 0;
  180.     options[current++] = "-B";
  181.     options[current++] = "" + getClassifierSpec();
  182.     // same attribute evaluator
  183.     options[current++] = "-E";
  184.     options[current++] = "" +getEvaluatorSpec();
  185.     
  186.     // same for search
  187.     options[current++] = "-S";
  188.     options[current++] = "" + getSearchSpec();
  189.     while (current < options.length) {
  190.       options[current++] = "";
  191.     }
  192.     return options;
  193.   }
  194.   /**
  195.    * Returns the tip text for this property
  196.    * @return tip text for this property suitable for
  197.    * displaying in the explorer/experimenter gui
  198.    */
  199.   public String classifierTipText() {
  200.     return "Set the classifier to use";
  201.   }
  202.   /**
  203.    * Sets the classifier
  204.    *
  205.    * @param classifier the classifier with all options set.
  206.    */
  207.   public void setClassifier(Classifier classifier) {
  208.     m_Classifier = classifier;
  209.   }
  210.   /**
  211.    * Gets the classifier used.
  212.    *
  213.    * @return the classifier
  214.    */
  215.   public Classifier getClassifier() {
  216.     return m_Classifier;
  217.   }
  218.   /**
  219.    * Gets the classifier specification string, which contains the class name of
  220.    * the classifier and any options to the classifier
  221.    *
  222.    * @return the classifier string.
  223.    */
  224.   protected String getClassifierSpec() {
  225.     
  226.     Classifier c = getClassifier();
  227.     if (c instanceof OptionHandler) {
  228.       return c.getClass().getName() + " "
  229. + Utils.joinOptions(((OptionHandler)c).getOptions());
  230.     }
  231.     return c.getClass().getName();
  232.   }
  233.   /**
  234.    * Returns the tip text for this property
  235.    * @return tip text for this property suitable for
  236.    * displaying in the explorer/experimenter gui
  237.    */
  238.   public String evaluatorTipText() {
  239.     return "Set the attribute evaluator to use. This evaluator is used "
  240.       +"during the attribute selection phase before the classifier is "
  241.       +"invoked.";
  242.   }
  243.   /**
  244.    * Sets the attribute evaluator
  245.    *
  246.    * @param evaluator the evaluator with all options set.
  247.    */
  248.   public void setEvaluator(ASEvaluation evaluator) {
  249.     m_Evaluator = evaluator;
  250.   }
  251.   /**
  252.    * Gets the attribute evaluator used
  253.    *
  254.    * @return the attribute evaluator
  255.    */
  256.   public ASEvaluation getEvaluator() {
  257.     return m_Evaluator;
  258.   }
  259.   /**
  260.    * Gets the evaluator specification string, which contains the class name of
  261.    * the attribute evaluator and any options to it
  262.    *
  263.    * @return the evaluator string.
  264.    */
  265.   protected String getEvaluatorSpec() {
  266.     
  267.     ASEvaluation e = getEvaluator();
  268.     if (e instanceof OptionHandler) {
  269.       return e.getClass().getName() + " "
  270. + Utils.joinOptions(((OptionHandler)e).getOptions());
  271.     }
  272.     return e.getClass().getName();
  273.   }
  274.   /**
  275.    * Returns the tip text for this property
  276.    * @return tip text for this property suitable for
  277.    * displaying in the explorer/experimenter gui
  278.    */
  279.   public String searchTipText() {
  280.     return "Set the search method. This search method is used "
  281.       +"during the attribute selection phase before the classifier is "
  282.       +"invoked.";
  283.   }
  284.   
  285.   /**
  286.    * Sets the search method
  287.    *
  288.    * @param search the search method with all options set.
  289.    */
  290.   public void setSearch(ASSearch search) {
  291.     m_Search = search;
  292.   }
  293.   /**
  294.    * Gets the search method used
  295.    *
  296.    * @return the search method
  297.    */
  298.   public ASSearch getSearch() {
  299.     return m_Search;
  300.   }
  301.   /**
  302.    * Gets the search specification string, which contains the class name of
  303.    * the search method and any options to it
  304.    *
  305.    * @return the search string.
  306.    */
  307.   protected String getSearchSpec() {
  308.     
  309.     ASSearch s = getSearch();
  310.     if (s instanceof OptionHandler) {
  311.       return s.getClass().getName() + " "
  312. + Utils.joinOptions(((OptionHandler)s).getOptions());
  313.     }
  314.     return s.getClass().getName();
  315.   }
  316.   /**
  317.    * Build the classifier on the dimensionally reduced data.
  318.    *
  319.    * @param data the training data
  320.    * @exception Exception if the classifier could not be built successfully
  321.    */
  322.   public void buildClassifier(Instances data) throws Exception {
  323.     if (m_Classifier == null) {
  324.       throw new Exception("No base classifier has been set!");
  325.     }
  326.     if (m_Evaluator == null) {
  327.       throw new Exception("No attribute evaluator has been set!");
  328.     }
  329.     if (m_Search == null) {
  330.       throw new Exception("No search method has been set!");
  331.     }
  332.    
  333.     Instances newData = new Instances(data);
  334.     newData.deleteWithMissingClass();
  335.     if (newData.classAttribute().isNominal()) {
  336.       m_numClasses = newData.classAttribute().numValues();
  337.     } else {
  338.       m_numClasses = 1;
  339.     }
  340.     m_AttributeSelection = new AttributeSelection();
  341.     m_AttributeSelection.setEvaluator(m_Evaluator);
  342.     m_AttributeSelection.setSearch(m_Search);
  343.     long start = System.currentTimeMillis();
  344.     m_AttributeSelection.SelectAttributes(newData);
  345.     long end = System.currentTimeMillis();
  346.     newData = m_AttributeSelection.reduceDimensionality(newData);
  347.     m_Classifier.buildClassifier(newData);
  348.     long end2 = System.currentTimeMillis();
  349.     m_numAttributesSelected = m_AttributeSelection.numberAttributesSelected();
  350.     m_ReducedHeader = new Instances(newData, 0);
  351.     m_selectionTime = (double)(end - start);
  352.     m_totalTime = (double)(end2 - start);
  353.   }
  354.   /**
  355.    * Classifies a given instance after attribute selection
  356.    *
  357.    * @param instance the instance to be classified
  358.    * @exception Exception if instance could not be classified
  359.    * successfully
  360.    */
  361.   public double [] distributionForInstance(Instance instance)
  362.     throws Exception {
  363.     if (m_AttributeSelection == null) {
  364.       throw new Exception("AttributeSelectedClassifier: No model built yet!");
  365.     }
  366.     Instance newInstance = m_AttributeSelection.reduceDimensionality(instance);
  367.     if (m_Classifier instanceof DistributionClassifier) {
  368.       return ((DistributionClassifier)m_Classifier)
  369. .distributionForInstance(newInstance);
  370.     }
  371.     double pred = m_Classifier.classifyInstance(newInstance);
  372.     double [] result = new double[m_numClasses];
  373.     if (Instance.isMissingValue(pred)) {
  374.       return result;
  375.     }
  376.     switch (instance.classAttribute().type()) {
  377.     case Attribute.NOMINAL:
  378.       result[(int) pred] = 1.0;
  379.       break;
  380.     case Attribute.NUMERIC:
  381.       result[0] = pred;
  382.       break;
  383.     default:
  384.       throw new Exception("Unknown class type");
  385.     }
  386.     return result;
  387.   }
  388.   /**
  389.    * Output a representation of this classifier
  390.    */
  391.   public String toString() {
  392.     if (m_AttributeSelection == null) {
  393.       return "AttributeSelectedClassifier: No model built yet.";
  394.     }
  395.     StringBuffer result = new StringBuffer();
  396.     result.append("AttributeSelectedClassifier:nn");
  397.     result.append(m_AttributeSelection.toResultsString());
  398.     result.append("nnHeader of reduced data:n"+m_ReducedHeader.toString());
  399.     result.append("nnClassifier Modeln"+m_Classifier.toString());
  400.     return result.toString();
  401.   }
  402.   /**
  403.    * Additional measure --- number of attributes selected
  404.    * @return the number of attributes selected
  405.    */
  406.   public double measureNumAttributesSelected() {
  407.     return m_numAttributesSelected;
  408.   }
  409.   /**
  410.    * Additional measure --- time taken (milliseconds) to select the attributes
  411.    * @return the time taken to select attributes
  412.    */
  413.   public double measureSelectionTime() {
  414.     return m_selectionTime;
  415.   }
  416.   /**
  417.    * Additional measure --- time taken (milliseconds) to select attributes
  418.    * and build the classifier
  419.    * @return the total time (select attributes + build classifier)
  420.    */
  421.   public double measureTime() {
  422.     return m_totalTime;
  423.   }
  424.   /**
  425.    * Returns an enumeration of the additional measure names
  426.    * @return an enumeration of the measure names
  427.    */
  428.   public Enumeration enumerateMeasures() {
  429.     Vector newVector = new Vector(3);
  430.     newVector.addElement("measureNumAttributesSelected");
  431.     newVector.addElement("measureSelectionTime");
  432.     newVector.addElement("measureTime");
  433.     if (m_Classifier instanceof AdditionalMeasureProducer) {
  434.       Enumeration en = ((AdditionalMeasureProducer)m_Classifier).
  435. enumerateMeasures();
  436.       while (en.hasMoreElements()) {
  437. String mname = (String)en.nextElement();
  438. newVector.addElement(mname);
  439.       }
  440.     }
  441.     return newVector.elements();
  442.   }
  443.   
  444.   /**
  445.    * Returns the value of the named measure
  446.    * @param measureName the name of the measure to query for its value
  447.    * @return the value of the named measure
  448.    * @exception IllegalArgumentException if the named measure is not supported
  449.    */
  450.   public double getMeasure(String additionalMeasureName) {
  451.     if (additionalMeasureName.compareTo("measureNumAttributesSelected") == 0) {
  452.       return measureNumAttributesSelected();
  453.     } else if (additionalMeasureName.compareTo("measureSelectionTime") == 0) {
  454.       return measureSelectionTime();
  455.     } else if (additionalMeasureName.compareTo("measureTime") == 0) {
  456.       return measureTime();
  457.     } else if (m_Classifier instanceof AdditionalMeasureProducer) {
  458.       return ((AdditionalMeasureProducer)m_Classifier).
  459. getMeasure(additionalMeasureName);
  460.     } else {
  461.       throw new IllegalArgumentException(additionalMeasureName 
  462.   + " not supported (AttributeSelectedClassifier)");
  463.     }
  464.   }
  465.   /**
  466.    * Main method for testing this class.
  467.    *
  468.    * @param argv should contain the following arguments:
  469.    * -t training file [-T test file] [-c class index]
  470.    */
  471.   public static void main(String [] argv) {
  472.     try {
  473.       System.out.println(Evaluation
  474.  .evaluateModel(new AttributeSelectedClassifier(),
  475. argv));
  476.     } catch (Exception e) {
  477.       System.err.println(e.getMessage());
  478.       e.printStackTrace();
  479.     }
  480.   }
  481. }