/* * 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 2 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, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * PART.java * Copyright (C) 1999 Eibe Frank * */ package weka.classifiers.rules.part; import weka.classifiers.trees.j48.BinC45ModelSelection; import weka.classifiers.trees.j48.C45ModelSelection; import weka.classifiers.trees.j48.Distribution; import weka.classifiers.trees.j48.ModelSelection; import java.util.*; import weka.core.*; import weka.classifiers.*; /** * Class for generating a PART decision list. For more information, see<p> * * Eibe Frank and Ian H. Witten (1998). <a * href="http://www.cs.waikato.ac.nz/~eibe/pubs/ML98-57.ps.gz">Generating * Accurate Rule Sets Without Global Optimization.</a> In Shavlik, J., * ed., <i>Machine Learning: Proceedings of the Fifteenth * International Conference</i>, Morgan Kaufmann Publishers, San * Francisco, CA. <p> * * Valid options are: <p> * * -C confidence <br> * Set confidence threshold for pruning. (Default: 0.25) <p> * * -M number <br> * Set minimum number of instances per leaf. (Default: 2) <p> * * -R <br> * Use reduced error pruning. <p> * * -N number <br> * Set number of folds for reduced error pruning. One fold is * used as the pruning set. (Default: 3) <p> * * -B <br> * Use binary splits for nominal attributes. <p> * * -U <br> * Generate unpruned decision list. <p> * * @author Eibe Frank (eibe@cs.waikato.ac.nz) * @version $Revision: 1.1.1.1 $ */ public class PART extends DistributionClassifier implements OptionHandler, WeightedInstancesHandler, Summarizable, AdditionalMeasureProducer { /** The decision list */ private MakeDecList m_root; /** Confidence level */ private float m_CF = 0.25f; /** Minimum number of objects */ private int m_minNumObj = 2; /** Use reduced error pruning? */ private boolean m_reducedErrorPruning = false; /** Number of folds for reduced error pruning. */ private int m_numFolds = 3; /** Binary splits on nominal attributes? */ private boolean m_binarySplits = false; /** Generate unpruned list? */ private boolean m_unpruned = false; /** * Generates the classifier. * * @exception Exception if classifier can't be built successfully */ public void buildClassifier(Instances instances) throws Exception { ModelSelection modSelection; if (m_binarySplits) modSelection = new BinC45ModelSelection(m_minNumObj, instances); else modSelection = new C45ModelSelection(m_minNumObj, instances); if (m_unpruned) m_root = new MakeDecList(modSelection, m_minNumObj); else if (m_reducedErrorPruning) m_root = new MakeDecList(modSelection, m_numFolds, m_minNumObj); else m_root = new MakeDecList(modSelection, m_CF, m_minNumObj); m_root.buildClassifier(instances); if (m_binarySplits) { ((BinC45ModelSelection)modSelection).cleanup(); } else { ((C45ModelSelection)modSelection).cleanup(); } } /** * Classifies an instance. * * @exception Exception if instance can't be classified successfully */ public double classifyInstance(Instance instance) throws Exception { return m_root.classifyInstance(instance); } /** * Returns class probabilities for an instance. * * @exception Exception if the distribution can't be computed successfully */ public final double [] distributionForInstance(Instance instance) throws Exception { return m_root.distributionForInstance(instance); } /** * Returns an enumeration describing the available options. * * Valid options are: <p> * * -C confidence <br> * Set confidence threshold for pruning. (Default: 0.25) <p> * * -M number <br> * Set minimum number of instances per leaf. (Default: 2) <p> * * -R <br> * Use reduced error pruning. <p> * * -N number <br> * Set number of folds for reduced error pruning. One fold is * used as the pruning set. (Default: 3) <p> * * -B <br> * Use binary splits for nominal attributes. <p> * * -U <br> * Generate unpruned decision list. <p> * * @return an enumeration of all the available options. */ public Enumeration listOptions() { Vector newVector = new Vector(6); newVector. addElement(new Option("\tSet confidence threshold for pruning.\n" + "\t(default 0.25)", "C", 1, "-C <pruning confidence>")); newVector. addElement(new Option("\tSet minimum number of objects per leaf.\n" + "\t(default 2)", "M", 1, "-M <minimum number of objects>")); newVector. addElement(new Option("\tUse reduced error pruning.", "R", 0, "-R")); newVector. addElement(new Option("\tSet number of folds for reduced error\n" + "\tpruning. One fold is used as pruning set.\n" + "\t(default 3)", "N", 1, "-N <number of folds>")); newVector. addElement(new Option("\tUse binary splits only.", "B", 0, "-B")); newVector. addElement(new Option("\tGenerate unpruned decision list.", "U", 0, "-U")); return newVector.elements(); } /** * Parses a given list of options. * * @param options the list of options as an array of strings * @exception Exception if an option is not supported */ public void setOptions(String[] options) throws Exception { // Pruning options m_unpruned = Utils.getFlag('U', options); m_reducedErrorPruning = Utils.getFlag('R', options); m_binarySplits = Utils.getFlag('B', options); String confidenceString = Utils.getOption('C', options); if (confidenceString.length() != 0) { if (m_reducedErrorPruning) { throw new Exception("Setting CF doesn't make sense " + "for reduced error pruning."); } else { m_CF = (new Float(confidenceString)).floatValue(); if ((m_CF <= 0) || (m_CF >= 1)) { throw new Exception("CF has to be greater than zero and smaller than one!"); } } } else { m_CF = 0.25f; } String numFoldsString = Utils.getOption('N', options); if (numFoldsString.length() != 0) { if (!m_reducedErrorPruning) { throw new Exception("Setting the number of folds" + " does only make sense for" + " reduced error pruning."); } else { m_numFolds = Integer.parseInt(numFoldsString); } } else { m_numFolds = 3; } // Other options String minNumString = Utils.getOption('M', options); if (minNumString.length() != 0) { m_minNumObj = Integer.parseInt(minNumString); } else { m_minNumObj = 2; } } /** * Gets the current settings of the Classifier. * * @return an array of strings suitable for passing to setOptions */ public String [] getOptions() { String [] options = new String [9]; int current = 0; if (m_unpruned) { options[current++] = "-U"; } if (m_reducedErrorPruning) { options[current++] = "-R"; } if (m_binarySplits) { options[current++] = "-B"; } options[current++] = "-M"; options[current++] = "" + m_minNumObj; options[current++] = "-C"; options[current++] = "" + m_CF; options[current++] = "-N"; options[current++] = "" + m_numFolds; while (current < options.length) { options[current++] = ""; } return options; } /** * Returns a description of the classifier */ public String toString() { if (m_root == null) { return "No classifier built"; } return "PART decision list\n------------------\n\n" + m_root.toString(); } /** * Returns a superconcise version of the model */ public String toSummaryString() { return "Number of rules: " + m_root.numRules() + "\n"; } /** * Return the number of rules. * @return the number of rules */ public double measureNumRules() { return m_root.numRules(); } /** * Returns an enumeration of the additional measure names * @return an enumeration of the measure names */ public Enumeration enumerateMeasures() { Vector newVector = new Vector(1); newVector.addElement("measureNumRules"); return newVector.elements(); } /** * Returns the value of the named measure * @param measureName the name of the measure to query for its value * @return the value of the named measure * @exception IllegalArgumentException if the named measure is not supported */ public double getMeasure(String additionalMeasureName) { if (additionalMeasureName.compareTo("measureNumRules") == 0) { return measureNumRules(); } else { throw new IllegalArgumentException(additionalMeasureName + " not supported (PART)"); } } /** * Get the value of CF. * * @return Value of CF. */ public float getConfidenceFactor() { return m_CF; } /** * Set the value of CF. * * @param v Value to assign to CF. */ public void setConfidenceFactor(float v) { m_CF = v; } /** * Get the value of minNumObj. * * @return Value of minNumObj. */ public int getMinNumObj() { return m_minNumObj; } /** * Set the value of minNumObj. * * @param v Value to assign to minNumObj. */ public void setMinNumObj(int v) { m_minNumObj = v; } /** * Get the value of reducedErrorPruning. * * @return Value of reducedErrorPruning. */ public boolean getReducedErrorPruning() { return m_reducedErrorPruning; } /** * Set the value of reducedErrorPruning. * * @param v Value to assign to reducedErrorPruning. */ public void setReducedErrorPruning(boolean v) { m_reducedErrorPruning = v; } /** * Get the value of unpruned. * * @return Value of unpruned. */ public boolean getUnpruned() { return m_unpruned; } /** * Set the value of unpruned. * * @param newunpruned Value to assign to unpruned. */ public void setUnpruned(boolean newunpruned) { m_unpruned = newunpruned; } /** * Get the value of numFolds. * * @return Value of numFolds. */ public int getNumFolds() { return m_numFolds; } /** * Set the value of numFolds. * * @param v Value to assign to numFolds. */ public void setNumFolds(int v) { m_numFolds = v; } /** * Get the value of binarySplits. * * @return Value of binarySplits. */ public boolean getBinarySplits() { return m_binarySplits; } /** * Set the value of binarySplits. * * @param v Value to assign to binarySplits. */ public void setBinarySplits(boolean v) { m_binarySplits = v; } /** * Main method for testing this class. * * @param String options */ public static void main(String [] argv){ try { System.out.println(Evaluation.evaluateModel(new PART(), argv)); } catch (Exception e) { System.out.println(e.getMessage()); } } }