/* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* * AttributeSelection.java * Copyright (C) 1999-2012 University of Waikato, Hamilton, New Zealand * */ package weka.attributeSelection; import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.MethodDescriptor; import java.beans.PropertyDescriptor; import java.io.Serializable; import java.lang.reflect.Method; import java.util.Enumeration; import java.util.Random; import weka.core.Instance; import weka.core.Instances; import weka.core.Option; import weka.core.OptionHandler; import weka.core.RevisionHandler; import weka.core.RevisionUtils; import weka.core.Utils; import weka.core.converters.ConverterUtils.DataSource; import weka.filters.Filter; import weka.filters.unsupervised.attribute.Remove; /** * Attribute selection class. Takes the name of a search class and * an evaluation class on the command line. <p/> * * Valid options are: <p/> * * -h <br/> * Display help. <p/> * * -i <name of input file> <br/> * Specify the training data file. <p/> * * -c <class index> <br/> * The index of the attribute to use as the class. <p/> * * -s <search method> <br/> * The full class name of the search method followed by search method options * (if any).<br/> * Eg. -s "weka.attributeSelection.BestFirst -N 10" <p/> * * -x <number of folds> <br/> * Perform a cross validation. <p/> * * -n <random number seed> <br/> * Specify a random number seed. Use in conjuction with -x. (Default = 1). <p/> * * ------------------------------------------------------------------------ <p/> * * Example usage as the main of an attribute evaluator (called FunkyEvaluator): * <pre> * public static void main(String [] args) { * runEvaluator(new FunkyEvaluator(), args); * } * </pre> * <p/> * * ------------------------------------------------------------------------ <p/> * * @author Mark Hall (mhall@cs.waikato.ac.nz) * @version $Revision: 8034 $ */ public class AttributeSelection implements Serializable, RevisionHandler { /** for serialization */ static final long serialVersionUID = 4170171824147584330L; /** the instances to select attributes from */ private Instances m_trainInstances; /** the attribute/subset evaluator */ private ASEvaluation m_ASEvaluator; /** the search method */ private ASSearch m_searchMethod; /** the number of folds to use for cross validation */ private int m_numFolds; /** holds a string describing the results of the attribute selection */ private StringBuffer m_selectionResults; /** rank features (if allowed by the search method) */ private boolean m_doRank; /** do cross validation */ private boolean m_doXval; /** seed used to randomly shuffle instances for cross validation */ private int m_seed; /** number of attributes requested from ranked results */ private int m_numToSelect; /** the selected attributes */ private int [] m_selectedAttributeSet; /** the attribute indexes and associated merits if a ranking is produced */ private double [][] m_attributeRanking; /** if a feature selection run involves an attribute transformer */ private AttributeTransformer m_transformer = null; /** the attribute filter for processing instances with respect to the most recent feature selection run */ private Remove m_attributeFilter = null; /** hold statistics for repeated feature selection, such as under cross validation */ private double [][] m_rankResults = null; private double [] m_subsetResults = null; private int m_trials = 0; /** * Return the number of attributes selected from the most recent * run of attribute selection * @return the number of attributes selected */ public int numberAttributesSelected() throws Exception { int [] att = selectedAttributes(); return att.length-1; } /** * get the final selected set of attributes. * @return an array of attribute indexes * @exception Exception if attribute selection has not been performed yet */ public int [] selectedAttributes () throws Exception { if (m_selectedAttributeSet == null) { throw new Exception("Attribute selection has not been performed yet!"); } return m_selectedAttributeSet; } /** * get the final ranking of the attributes. * @return a two dimensional array of ranked attribute indexes and their * associated merit scores as doubles. * @exception Exception if a ranking has not been produced */ public double [][] rankedAttributes () throws Exception { if (m_attributeRanking == null) { throw new Exception("Ranking has not been performed"); } return m_attributeRanking; } /** * set the attribute/subset evaluator * @param evaluator the evaluator to use */ public void setEvaluator (ASEvaluation evaluator) { m_ASEvaluator = evaluator; } /** * set the search method * @param search the search method to use */ public void setSearch (ASSearch search) { m_searchMethod = search; if (m_searchMethod instanceof RankedOutputSearch) { setRanking(((RankedOutputSearch)m_searchMethod).getGenerateRanking()); } } /** * set the number of folds for cross validation * @param folds the number of folds */ public void setFolds (int folds) { m_numFolds = folds; } /** * produce a ranking (if possible with the set search and evaluator) * @param r true if a ranking is to be produced */ public void setRanking (boolean r) { m_doRank = r; } /** * do a cross validation * @param x true if a cross validation is to be performed */ public void setXval (boolean x) { m_doXval = x; } /** * set the seed for use in cross validation * @param s the seed */ public void setSeed (int s) { m_seed = s; } /** * get a description of the attribute selection * @return a String describing the results of attribute selection */ public String toResultsString() { return m_selectionResults.toString(); } /** * reduce the dimensionality of a set of instances to include only those * attributes chosen by the last run of attribute selection. * @param in the instances to be reduced * @return a dimensionality reduced set of instances * @exception Exception if the instances can't be reduced */ public Instances reduceDimensionality(Instances in) throws Exception { if (m_attributeFilter == null) { throw new Exception("No feature selection has been performed yet!"); } if (m_transformer != null) { Instances transformed = new Instances(m_transformer.transformedHeader(), in.numInstances()); for (int i=0;i<in.numInstances();i++) { transformed.add(m_transformer.convertInstance(in.instance(i))); } return Filter.useFilter(transformed, m_attributeFilter); } return Filter.useFilter(in, m_attributeFilter); } /** * reduce the dimensionality of a single instance to include only those * attributes chosen by the last run of attribute selection. * @param in the instance to be reduced * @return a dimensionality reduced instance * @exception Exception if the instance can't be reduced */ public Instance reduceDimensionality(Instance in) throws Exception { if (m_attributeFilter == null) { throw new Exception("No feature selection has been performed yet!"); } if (m_transformer != null) { in = m_transformer.convertInstance(in); } m_attributeFilter.input(in); m_attributeFilter.batchFinished(); Instance result = m_attributeFilter.output(); return result; } /** * constructor. Sets defaults for each member varaible. Default * attribute evaluator is CfsSubsetEval; default search method is * BestFirst. */ public AttributeSelection () { setFolds(10); setRanking(false); setXval(false); setSeed(1); setEvaluator(new CfsSubsetEval()); setSearch(new GreedyStepwise()); m_selectionResults = new StringBuffer(); m_selectedAttributeSet = null; m_attributeRanking = null; } /** * Perform attribute selection with a particular evaluator and * a set of options specifying search method and input file etc. * * @param ASEvaluator an evaluator object * @param options an array of options, not only for the evaluator * but also the search method (if any) and an input data file * @return the results of attribute selection as a String * @exception Exception if no training file is set */ public static String SelectAttributes (ASEvaluation ASEvaluator, String[] options) throws Exception { String trainFileName, searchName; Instances train = null; ASSearch searchMethod = null; String[] optionsTmp = (String[]) options.clone(); boolean helpRequested = false; try { // get basic options (options the same for all attribute selectors trainFileName = Utils.getOption('i', options); helpRequested = Utils.getFlag('h', optionsTmp); if (helpRequested || (trainFileName.length() == 0)) { searchName = Utils.getOption('s', optionsTmp); if (searchName.length() != 0) { String[] searchOptions = Utils.splitOptions(searchName); searchMethod = (ASSearch)Class.forName(searchOptions[0]).newInstance(); } if (helpRequested) throw new Exception("Help requested."); else throw new Exception("No training file given."); } } catch (Exception e) { throw new Exception('\n' + e.getMessage() + makeOptionString(ASEvaluator, searchMethod)); } DataSource source = new DataSource(trainFileName); train = source.getDataSet(); return SelectAttributes(ASEvaluator, options, train); } /** * returns a string summarizing the results of repeated attribute * selection runs on splits of a dataset. * @return a summary of attribute selection results * @exception Exception if no attribute selection has been performed. */ public String CVResultsString () throws Exception { StringBuffer CvString = new StringBuffer(); if ((m_subsetResults == null && m_rankResults == null) || ( m_trainInstances == null)) { throw new Exception("Attribute selection has not been performed yet!"); } int fieldWidth = (int)(Math.log(m_trainInstances.numAttributes()) +1.0); CvString.append("\n\n=== Attribute selection " + m_numFolds + " fold cross-validation "); if (!(m_ASEvaluator instanceof UnsupervisedSubsetEvaluator) && !(m_ASEvaluator instanceof UnsupervisedAttributeEvaluator) && (m_trainInstances.classAttribute().isNominal())) { CvString.append("(stratified), seed: "); CvString.append(m_seed+" ===\n\n"); } else { CvString.append("seed: "+m_seed+" ===\n\n"); } if ((m_searchMethod instanceof RankedOutputSearch) && (m_doRank == true)) { CvString.append("average merit average rank attribute\n"); // calcualte means and std devs for (int i = 0; i < m_rankResults[0].length; i++) { m_rankResults[0][i] /= m_numFolds; // mean merit double var = m_rankResults[0][i]*m_rankResults[0][i]*m_numFolds; var = (m_rankResults[2][i] - var); var /= m_numFolds; if (var <= 0.0) { var = 0.0; m_rankResults[2][i] = 0; } else { m_rankResults[2][i] = Math.sqrt(var); } m_rankResults[1][i] /= m_numFolds; // mean rank var = m_rankResults[1][i]*m_rankResults[1][i]*m_numFolds; var = (m_rankResults[3][i] - var); var /= m_numFolds; if (var <= 0.0) { var = 0.0; m_rankResults[3][i] = 0; } else { m_rankResults[3][i] = Math.sqrt(var); } } // now sort them by mean rank int[] s = Utils.sort(m_rankResults[1]); for (int i=0; i<s.length; i++) { if (m_rankResults[1][s[i]] > 0) { CvString.append(Utils.doubleToString(/*Math. abs(*/m_rankResults[0][s[i]]/*)*/, 6, 3) + " +-" + Utils.doubleToString(m_rankResults[2][s[i]], 6, 3) + " " + Utils.doubleToString(m_rankResults[1][s[i]], fieldWidth+2, 1) + " +-" + Utils.doubleToString(m_rankResults[3][s[i]], 5, 2) +" " + Utils.doubleToString(((double)(s[i] + 1)), fieldWidth, 0) + " " + m_trainInstances.attribute(s[i]).name() + "\n"); } } } else { CvString.append("number of folds (%) attribute\n"); for (int i = 0; i < m_subsetResults.length; i++) { if ((m_ASEvaluator instanceof UnsupervisedSubsetEvaluator) || (i != m_trainInstances.classIndex())) { CvString.append(Utils.doubleToString(m_subsetResults[i], 12, 0) + "(" + Utils.doubleToString((m_subsetResults[i] / m_numFolds * 100.0) , 3, 0) + " %) " + Utils.doubleToString(((double)(i + 1)), fieldWidth, 0) + " " + m_trainInstances.attribute(i).name() + "\n"); } } } return CvString.toString(); } /** * Select attributes for a split of the data. Calling this function * updates the statistics on attribute selection. CVResultsString() * returns a string summarizing the results of repeated calls to * this function. Assumes that splits are from the same dataset--- * ie. have the same number and types of attributes as previous * splits. * * @param split the instances to select attributes from * @exception Exception if an error occurs */ public void selectAttributesCVSplit(Instances split) throws Exception { double[][] attributeRanking = null; // if the train instances are null then set equal to this split. // If this is the case then this function is more than likely being // called from outside this class in order to obtain CV statistics // and all we need m_trainIstances for is to get at attribute names // and types etc. if (m_trainInstances == null) { m_trainInstances = split; } // create space to hold statistics if (m_rankResults == null && m_subsetResults == null) { m_subsetResults = new double[split.numAttributes()]; m_rankResults = new double[4][split.numAttributes()]; } m_ASEvaluator.buildEvaluator(split); // Do the search int[] attributeSet = m_searchMethod.search(m_ASEvaluator, split); // Do any postprocessing that a attribute selection method might // require attributeSet = m_ASEvaluator.postProcess(attributeSet); if ((m_searchMethod instanceof RankedOutputSearch) && (m_doRank == true)) { attributeRanking = ((RankedOutputSearch)m_searchMethod). rankedAttributes(); // System.out.println(attributeRanking[0][1]); for (int j = 0; j < attributeRanking.length; j++) { // merit m_rankResults[0][(int)attributeRanking[j][0]] += attributeRanking[j][1]; // squared merit m_rankResults[2][(int)attributeRanking[j][0]] += (attributeRanking[j][1]*attributeRanking[j][1]); // rank m_rankResults[1][(int)attributeRanking[j][0]] += (j + 1); // squared rank m_rankResults[3][(int)attributeRanking[j][0]] += (j + 1)*(j + 1); // += (attributeRanking[j][0] * attributeRanking[j][0]); } } else { for (int j = 0; j < attributeSet.length; j++) { m_subsetResults[attributeSet[j]]++; } } m_trials++; } /** * Perform a cross validation for attribute selection. With subset * evaluators the number of times each attribute is selected over * the cross validation is reported. For attribute evaluators, the * average merit and average ranking + std deviation is reported for * each attribute. * * @return the results of cross validation as a String * @exception Exception if an error occurs during cross validation */ public String CrossValidateAttributes () throws Exception { Instances cvData = new Instances(m_trainInstances); Instances train; Random random = new Random(m_seed); cvData.randomize(random); if (!(m_ASEvaluator instanceof UnsupervisedSubsetEvaluator) && !(m_ASEvaluator instanceof UnsupervisedAttributeEvaluator)) { if (cvData.classAttribute().isNominal()) { cvData.stratify(m_numFolds); } } for (int i = 0; i < m_numFolds; i++) { // Perform attribute selection train = cvData.trainCV(m_numFolds, i, random); selectAttributesCVSplit(train); } return CVResultsString(); } /** * Perform attribute selection on the supplied training instances. * * @param data the instances to select attributes from * @exception Exception if there is a problem during selection */ public void SelectAttributes (Instances data) throws Exception { int [] attributeSet; m_transformer = null; m_attributeFilter = null; m_trainInstances = data; if (m_doXval == true && (m_ASEvaluator instanceof AttributeTransformer)) { throw new Exception("Can't cross validate an attribute transformer."); } if (m_ASEvaluator instanceof SubsetEvaluator && m_searchMethod instanceof Ranker) { throw new Exception(m_ASEvaluator.getClass().getName() +" must use a search method other than Ranker"); } if (m_ASEvaluator instanceof AttributeEvaluator && !(m_searchMethod instanceof Ranker)) { // System.err.println("AttributeEvaluators must use a Ranker search " // +"method. Switching to Ranker..."); // m_searchMethod = new Ranker(); throw new Exception("AttributeEvaluators must use the Ranker search " + "method"); } if (m_searchMethod instanceof RankedOutputSearch) { m_doRank = ((RankedOutputSearch)m_searchMethod).getGenerateRanking(); } if (m_ASEvaluator instanceof UnsupervisedAttributeEvaluator || m_ASEvaluator instanceof UnsupervisedSubsetEvaluator) { // unset the class index // m_trainInstances.setClassIndex(-1); } else { // check that a class index has been set if (m_trainInstances.classIndex() < 0) { m_trainInstances.setClassIndex(m_trainInstances.numAttributes()-1); } } // Initialize the attribute evaluator m_ASEvaluator.buildEvaluator(m_trainInstances); if (m_ASEvaluator instanceof AttributeTransformer) { m_trainInstances = ((AttributeTransformer)m_ASEvaluator).transformedHeader(); m_transformer = (AttributeTransformer)m_ASEvaluator; } int fieldWidth = (int)(Math.log(m_trainInstances.numAttributes()) +1.0); // Do the search attributeSet = m_searchMethod.search(m_ASEvaluator, m_trainInstances); // try and determine if the search method uses an attribute transformer--- // this is a bit of a hack to make things work properly with RankSearch // using PrincipalComponents as its attribute ranker try { BeanInfo bi = Introspector.getBeanInfo(m_searchMethod.getClass()); PropertyDescriptor properties[]; MethodDescriptor methods[]; // methods = bi.getMethodDescriptors(); properties = bi.getPropertyDescriptors(); for (int i=0;i<properties.length;i++) { String name = properties[i].getDisplayName(); Method meth = properties[i].getReadMethod(); Object retType = meth.getReturnType(); if (retType.equals(ASEvaluation.class)) { Class args [] = { }; ASEvaluation tempEval = (ASEvaluation)(meth.invoke(m_searchMethod, (Object[])args)); if (tempEval instanceof AttributeTransformer) { // grab the transformed data header m_trainInstances = ((AttributeTransformer)tempEval).transformedHeader(); m_transformer = (AttributeTransformer)tempEval; } } } } catch (IntrospectionException ex) { System.err.println("AttributeSelection: Couldn't " +"introspect"); } // Do any postprocessing that a attribute selection method might require attributeSet = m_ASEvaluator.postProcess(attributeSet); if (!m_doRank) { m_selectionResults.append(printSelectionResults()); } if ((m_searchMethod instanceof RankedOutputSearch) && m_doRank == true) { m_attributeRanking = ((RankedOutputSearch)m_searchMethod).rankedAttributes(); m_selectionResults.append(printSelectionResults()); m_selectionResults.append("Ranked attributes:\n"); // retrieve the number of attributes to retain m_numToSelect = ((RankedOutputSearch)m_searchMethod).getCalculatedNumToSelect(); // determine fieldwidth for merit int f_p=0; int w_p=0; for (int i = 0; i < m_numToSelect; i++) { double precision = (Math.abs(m_attributeRanking[i][1]) - (int)(Math.abs(m_attributeRanking[i][1]))); double intPart = (int)(Math.abs(m_attributeRanking[i][1])); if (precision > 0) { precision = Math.abs((Math.log(Math.abs(precision)) / Math.log(10)))+3; } if (precision > f_p) { f_p = (int)precision; } if (intPart == 0) { if (w_p < 2) { w_p = 2; } } else if ((Math.abs((Math.log(Math.abs(m_attributeRanking[i][1])) / Math.log(10)))+1) > w_p) { if (m_attributeRanking[i][1] > 0) { w_p = (int)Math.abs((Math.log(Math.abs(m_attributeRanking[i][1])) / Math.log(10)))+1; } } } for (int i = 0; i < m_numToSelect; i++) { m_selectionResults. append(Utils.doubleToString(m_attributeRanking[i][1], f_p+w_p+1,f_p) + Utils.doubleToString((m_attributeRanking[i][0] + 1), fieldWidth+1,0) + " " + m_trainInstances. attribute((int)m_attributeRanking[i][0]).name() + "\n"); } // set up the selected attributes array - usable by a filter or // whatever if (m_trainInstances.classIndex() >= 0) { if ((!(m_ASEvaluator instanceof UnsupervisedSubsetEvaluator) && !(m_ASEvaluator instanceof UnsupervisedAttributeEvaluator)) || m_ASEvaluator instanceof AttributeTransformer) { // one more for the class m_selectedAttributeSet = new int[m_numToSelect + 1]; m_selectedAttributeSet[m_numToSelect] = m_trainInstances.classIndex(); } else { m_selectedAttributeSet = new int[m_numToSelect]; } } else { m_selectedAttributeSet = new int[m_numToSelect]; } m_selectionResults.append("\nSelected attributes: "); for (int i = 0; i < m_numToSelect; i++) { m_selectedAttributeSet[i] = (int)m_attributeRanking[i][0]; if (i == m_numToSelect - 1) { m_selectionResults.append(((int)m_attributeRanking[i][0] + 1) + " : " + (i + 1) + "\n"); } else { m_selectionResults.append(((int)m_attributeRanking[i][0] + 1)); m_selectionResults.append(","); } } } else { // set up the selected attributes array - usable by a filter or // whatever if ((!(m_ASEvaluator instanceof UnsupervisedSubsetEvaluator) && !(m_ASEvaluator instanceof UnsupervisedAttributeEvaluator)) || m_trainInstances.classIndex() >= 0) // one more for the class { m_selectedAttributeSet = new int[attributeSet.length + 1]; m_selectedAttributeSet[attributeSet.length] = m_trainInstances.classIndex(); } else { m_selectedAttributeSet = new int[attributeSet.length]; } for (int i = 0; i < attributeSet.length; i++) { m_selectedAttributeSet[i] = attributeSet[i]; } m_selectionResults.append("Selected attributes: "); for (int i = 0; i < attributeSet.length; i++) { if (i == (attributeSet.length - 1)) { m_selectionResults.append((attributeSet[i] + 1) + " : " + attributeSet.length + "\n"); } else { m_selectionResults.append((attributeSet[i] + 1) + ","); } } for (int i=0;i<attributeSet.length;i++) { m_selectionResults.append(" " +m_trainInstances .attribute(attributeSet[i]).name() +"\n"); } } // Cross validation should be called from here if (m_doXval == true) { m_selectionResults.append(CrossValidateAttributes()); } // set up the attribute filter with the selected attributes if (m_selectedAttributeSet != null && !m_doXval) { m_attributeFilter = new Remove(); m_attributeFilter.setAttributeIndicesArray(m_selectedAttributeSet); m_attributeFilter.setInvertSelection(true); m_attributeFilter.setInputFormat(m_trainInstances); } // Save space m_trainInstances = new Instances(m_trainInstances, 0); } /** * Perform attribute selection with a particular evaluator and * a set of options specifying search method and options for the * search method and evaluator. * * @param ASEvaluator an evaluator object * @param options an array of options, not only for the evaluator * but also the search method (if any) and an input data file * @param train the input instances * @return the results of attribute selection as a String * @exception Exception if incorrect options are supplied */ public static String SelectAttributes (ASEvaluation ASEvaluator, String[] options, Instances train) throws Exception { int seed = 1, folds = 10; String foldsString, seedString, searchName; String classString; String searchClassName; String[] searchOptions = null; //new String [1]; ASSearch searchMethod = null; boolean doCrossVal = false; int classIndex = -1; boolean helpRequested = false; AttributeSelection trainSelector = new AttributeSelection(); try { if (Utils.getFlag('h', options)) { helpRequested = true; } // does data already have a class attribute set? if (train.classIndex() != -1) classIndex = train.classIndex() + 1; // get basic options (options the same for all attribute selectors classString = Utils.getOption('c', options); if (classString.length() != 0) { if (classString.equals("first")) { classIndex = 1; } else if (classString.equals("last")) { classIndex = train.numAttributes(); } else { classIndex = Integer.parseInt(classString); } } if ((classIndex != -1) && ((classIndex == 0) || (classIndex > train.numAttributes()))) { throw new Exception("Class index out of range."); } if (classIndex != -1) { train.setClassIndex(classIndex - 1); } else { // classIndex = train.numAttributes(); // train.setClassIndex(classIndex - 1); } foldsString = Utils.getOption('x', options); if (foldsString.length() != 0) { folds = Integer.parseInt(foldsString); doCrossVal = true; } trainSelector.setFolds(folds); trainSelector.setXval(doCrossVal); seedString = Utils.getOption('n', options); if (seedString.length() != 0) { seed = Integer.parseInt(seedString); } trainSelector.setSeed(seed); searchName = Utils.getOption('s', options); if ((searchName.length() == 0) && (!(ASEvaluator instanceof AttributeEvaluator))) { throw new Exception("No search method given."); } if (searchName.length() != 0) { searchName = searchName.trim(); // split off any search options int breakLoc = searchName.indexOf(' '); searchClassName = searchName; String searchOptionsString = ""; if (breakLoc != -1) { searchClassName = searchName.substring(0, breakLoc); searchOptionsString = searchName.substring(breakLoc).trim(); searchOptions = Utils.splitOptions(searchOptionsString); } } else { try { searchClassName = new String("weka.attributeSelection.Ranker"); searchMethod = (ASSearch)Class. forName(searchClassName).newInstance(); } catch (Exception e) { throw new Exception("Can't create Ranker object"); } } // if evaluator is a subset evaluator // create search method and set its options (if any) if (searchMethod == null) { searchMethod = ASSearch.forName(searchClassName, searchOptions); } // set the search method trainSelector.setSearch(searchMethod); } catch (Exception e) { throw new Exception('\n' + e.getMessage() + makeOptionString(ASEvaluator, searchMethod)); } try { // Set options for ASEvaluator if (ASEvaluator instanceof OptionHandler) { ((OptionHandler)ASEvaluator).setOptions(options); } /* // Set options for Search method if (searchMethod instanceof OptionHandler) { if (searchOptions != null) { ((OptionHandler)searchMethod).setOptions(searchOptions); } } Utils.checkForRemainingOptions(searchOptions); */ } catch (Exception e) { throw new Exception("\n" + e.getMessage() + makeOptionString(ASEvaluator, searchMethod)); } try { Utils.checkForRemainingOptions(options); } catch (Exception e) { throw new Exception('\n' + e.getMessage() + makeOptionString(ASEvaluator, searchMethod)); } if (helpRequested) { System.out.println(makeOptionString(ASEvaluator, searchMethod)); System.exit(0); } // set the attribute evaluator trainSelector.setEvaluator(ASEvaluator); // do the attribute selection trainSelector.SelectAttributes(train); // return the results string return trainSelector.toResultsString(); } /** * Assembles a text description of the attribute selection results. * * @return a string describing the results of attribute selection. */ private String printSelectionResults () { StringBuffer text = new StringBuffer(); text.append("\n\n=== Attribute Selection on all input data ===\n\n" + "Search Method:\n"); text.append(m_searchMethod.toString()); text.append("\nAttribute "); if (m_ASEvaluator instanceof SubsetEvaluator) { text.append("Subset Evaluator ("); } else { text.append("Evaluator ("); } if (!(m_ASEvaluator instanceof UnsupervisedSubsetEvaluator) && !(m_ASEvaluator instanceof UnsupervisedAttributeEvaluator)) { text.append("supervised, "); text.append("Class ("); if (m_trainInstances.attribute(m_trainInstances.classIndex()) .isNumeric()) { text.append("numeric): "); } else { text.append("nominal): "); } text.append((m_trainInstances.classIndex() + 1) + " " + m_trainInstances.attribute(m_trainInstances .classIndex()).name() + "):\n"); } else { text.append("unsupervised):\n"); } text.append(m_ASEvaluator.toString() + "\n"); return text.toString(); } /** * Make up the help string giving all the command line options * * @param ASEvaluator the attribute evaluator to include options for * @param searchMethod the search method to include options for * @return a string detailing the valid command line options * @throws Exception if something goes wrong */ private static String makeOptionString (ASEvaluation ASEvaluator, ASSearch searchMethod) throws Exception { StringBuffer optionsText = new StringBuffer(""); // General options optionsText.append("\n\nGeneral options:\n\n"); optionsText.append("-h\n\tdisplay this help\n"); optionsText.append("-i <name of input file>\n"); optionsText.append("\tSets training file.\n"); optionsText.append("-c <class index>\n"); optionsText.append("\tSets the class index for supervised attribute\n"); optionsText.append("\tselection. Default=last column.\n"); optionsText.append("-s <class name>\n"); optionsText.append("\tSets search method for subset evaluators.\n"); optionsText.append("-x <number of folds>\n"); optionsText.append("\tPerform a cross validation.\n"); optionsText.append("-n <random number seed>\n"); optionsText.append("\tUse in conjunction with -x.\n"); // Get attribute evaluator-specific options if (ASEvaluator instanceof OptionHandler) { optionsText.append("\nOptions specific to " + ASEvaluator.getClass().getName() + ":\n\n"); Enumeration enu = ((OptionHandler)ASEvaluator).listOptions(); while (enu.hasMoreElements()) { Option option = (Option)enu.nextElement(); optionsText.append(option.synopsis() + '\n'); optionsText.append(option.description() + "\n"); } } if (searchMethod != null) { if (searchMethod instanceof OptionHandler) { optionsText.append("\nOptions specific to " + searchMethod.getClass().getName() + ":\n\n"); Enumeration enu = ((OptionHandler)searchMethod).listOptions(); while (enu.hasMoreElements()) { Option option = (Option)enu.nextElement(); optionsText.append(option.synopsis() + '\n'); optionsText.append(option.description() + "\n"); } } } else { if (ASEvaluator instanceof SubsetEvaluator) { System.out.println("No search method given."); } } return optionsText.toString(); } /** * Main method for testing this class. * * @param args the options */ public static void main (String[] args) { try { if (args.length == 0) { throw new Exception("The first argument must be the name of an " + "attribute/subset evaluator"); } String EvaluatorName = args[0]; args[0] = ""; ASEvaluation newEval = ASEvaluation.forName(EvaluatorName, null); System.out.println(SelectAttributes(newEval, args)); } catch (Exception e) { System.out.println(e.getMessage()); } } /** * Returns the revision string. * * @return the revision */ public String getRevision() { return RevisionUtils.extract("$Revision: 8034 $"); } }