DecisionStump.java
Upload User: rhdiban
Upload Date: 2013-08-09
Package Size: 15085k
Code Size: 20k
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.  *    DecisionStump.java
  18.  *    Copyright (C) 1999 Eibe Frank
  19.  *
  20.  */
  21. package weka.classifiers.trees;
  22. import weka.classifiers.meta.LogitBoost;
  23. import weka.classifiers.Classifier;
  24. import weka.classifiers.DistributionClassifier;
  25. import weka.classifiers.Evaluation;
  26. import weka.classifiers.meta.LogitBoost;
  27. import weka.classifiers.Sourcable;
  28. import java.io.*;
  29. import java.util.*;
  30. import weka.core.*;
  31. /**
  32.  * Class for building and using a decision stump. Usually used in conjunction
  33.  * with a boosting algorithm.
  34.  *
  35.  * Typical usage: <p>
  36.  * <code>java weka.classifiers.trees.LogitBoost -I 100 -W weka.classifiers.trees.DecisionStump 
  37.  * -t training_data </code><p>
  38.  * 
  39.  * @author Eibe Frank (eibe@cs.waikato.ac.nz)
  40.  * @version $Revision: 1.14 $
  41.  */
  42. public class DecisionStump extends DistributionClassifier 
  43.   implements WeightedInstancesHandler, Sourcable {
  44.   /** The attribute used for classification. */
  45.   private int m_AttIndex;
  46.   /** The split point (index respectively). */
  47.   private double m_SplitPoint;
  48.   /** The distribution of class values or the means in each subset. */
  49.   private double[][] m_Distribution;
  50.   /** The instances used for training. */
  51.   private Instances m_Instances;
  52.   /**
  53.    * Generates the classifier.
  54.    *
  55.    * @param instances set of instances serving as training data 
  56.    * @exception Exception if the classifier has not been generated successfully
  57.    */
  58.   public void buildClassifier(Instances instances) throws Exception {
  59.     
  60.     double bestVal = Double.MAX_VALUE, currVal;
  61.     double bestPoint = -Double.MAX_VALUE, sum;
  62.     int bestAtt = -1, numClasses;
  63.     if (instances.checkForStringAttributes()) {
  64.       throw new UnsupportedAttributeTypeException("Can't handle string attributes!");
  65.     }
  66.     double[][] bestDist = new double[3][instances.numClasses()];
  67.     m_Instances = new Instances(instances);
  68.     m_Instances.deleteWithMissingClass();
  69.     if (m_Instances.classAttribute().isNominal()) {
  70.       numClasses = m_Instances.numClasses();
  71.     } else {
  72.       numClasses = 1;
  73.     }
  74.     // For each attribute
  75.     boolean first = true;
  76.     for (int i = 0; i < m_Instances.numAttributes(); i++) {
  77.       if (i != m_Instances.classIndex()) {
  78. // Reserve space for distribution.
  79. m_Distribution = new double[3][numClasses];
  80. // Compute value of criterion for best split on attribute
  81. if (m_Instances.attribute(i).isNominal()) {
  82.   currVal = findSplitNominal(i);
  83. } else {
  84.   currVal = findSplitNumeric(i);
  85. }
  86. if ((first) || (Utils.sm(currVal, bestVal))) {
  87.   bestVal = currVal;
  88.   bestAtt = i;
  89.   bestPoint = m_SplitPoint;
  90.   for (int j = 0; j < 3; j++) {
  91.     System.arraycopy(m_Distribution[j], 0, bestDist[j], 0, 
  92.      numClasses);
  93.   }
  94. }
  95. // First attribute has been investigated
  96. first = false;
  97.       }
  98.     }
  99.     
  100.     // Set attribute, split point and distribution.
  101.     m_AttIndex = bestAtt;
  102.     m_SplitPoint = bestPoint;
  103.     m_Distribution = bestDist;
  104.     if (m_Instances.classAttribute().isNominal()) {
  105.       for (int i = 0; i < m_Distribution.length; i++) {
  106. Utils.normalize(m_Distribution[i]);
  107.       }
  108.     }
  109.     
  110.     // Save memory
  111.     m_Instances = new Instances(m_Instances, 0);
  112.   }
  113.   /**
  114.    * Calculates the class membership probabilities for the given test instance.
  115.    *
  116.    * @param instance the instance to be classified
  117.    * @return predicted class probability distribution
  118.    * @exception Exception if distribution can't be computed
  119.    */
  120.   public double[] distributionForInstance(Instance instance) throws Exception {
  121.     return m_Distribution[whichSubset(instance)];
  122.   }
  123.   /**
  124.    * Returns the decision tree as Java source code.
  125.    *
  126.    * @return the tree as Java source code
  127.    * @exception Exception if something goes wrong
  128.    */
  129.   public String toSource(String className) throws Exception {
  130.     StringBuffer text = new StringBuffer("class ");
  131.     Attribute c = m_Instances.classAttribute();
  132.     text.append(className)
  133.       .append(" {n"
  134.       +"  public static double classify(Object [] i) {n");
  135.     text.append("    /* " + m_Instances.attribute(m_AttIndex).name() + " */n");
  136.     text.append("    if (i[").append(m_AttIndex);
  137.     text.append("] == null) { return ");
  138.     text.append(sourceClass(c, m_Distribution[2])).append(";");
  139.     if (m_Instances.attribute(m_AttIndex).isNominal()) {
  140.       text.append(" } else if (((String)i[").append(m_AttIndex);
  141.       text.append("]).equals("");
  142.       text.append(m_Instances.attribute(m_AttIndex).value((int)m_SplitPoint));
  143.       text.append("")");
  144.     } else {
  145.       text.append(" } else if (((Double)i[").append(m_AttIndex);
  146.       text.append("]).doubleValue() <= ").append(m_SplitPoint);
  147.     }
  148.     text.append(") { return ");
  149.     text.append(sourceClass(c, m_Distribution[0])).append(";");
  150.     text.append(" } else { return ");
  151.     text.append(sourceClass(c, m_Distribution[1])).append(";");
  152.     text.append(" }n  }n}n");
  153.     return text.toString();
  154.   }
  155.   private String sourceClass(Attribute c, double []dist) {
  156.     if (c.isNominal()) {
  157.       return Integer.toString(Utils.maxIndex(dist));
  158.     } else {
  159.       return Double.toString(dist[0]);
  160.     }
  161.   }
  162.   /**
  163.    * Returns a description of the classifier.
  164.    *
  165.    * @return a description of the classifier as a string.
  166.    */
  167.   public String toString(){
  168.     if (m_Instances == null) {
  169.       return "Decision Stump: No model built yet.";
  170.     }
  171.     try {
  172.       StringBuffer text = new StringBuffer();
  173.       
  174.       text.append("Decision Stumpnn");
  175.       text.append("Classificationsnn");
  176.       Attribute att = m_Instances.attribute(m_AttIndex);
  177.       if (att.isNominal()) {
  178. text.append(att.name() + " = " + att.value((int)m_SplitPoint) + 
  179.     " : ");
  180. text.append(printClass(m_Distribution[0]));
  181. text.append(att.name() + " != " + att.value((int)m_SplitPoint) + 
  182.     " : ");
  183. text.append(printClass(m_Distribution[1]));
  184.       } else {
  185. text.append(att.name() + " <= " + m_SplitPoint + " : ");
  186. text.append(printClass(m_Distribution[0]));
  187. text.append(att.name() + " > " + m_SplitPoint + " : ");
  188. text.append(printClass(m_Distribution[1]));
  189.       }
  190.       text.append(att.name() + " is missing : ");
  191.       text.append(printClass(m_Distribution[2]));
  192.       if (m_Instances.classAttribute().isNominal()) {
  193. text.append("nClass distributionsnn");
  194. if (att.isNominal()) {
  195.   text.append(att.name() + " = " + att.value((int)m_SplitPoint) + 
  196.       "n");
  197.   text.append(printDist(m_Distribution[0]));
  198.   text.append(att.name() + " != " + att.value((int)m_SplitPoint) + 
  199.       "n");
  200.   text.append(printDist(m_Distribution[1]));
  201. } else {
  202.   text.append(att.name() + " <= " + m_SplitPoint + "n");
  203.   text.append(printDist(m_Distribution[0]));
  204.   text.append(att.name() + " > " + m_SplitPoint + "n");
  205.   text.append(printDist(m_Distribution[1]));
  206. }
  207. text.append(att.name() + " is missingn");
  208. text.append(printDist(m_Distribution[2]));
  209.       }
  210.       return text.toString();
  211.     } catch (Exception e) {
  212.       return "Can't print decision stump classifier!";
  213.     }
  214.   }
  215.   /** 
  216.    * Prints a class distribution.
  217.    *
  218.    * @param dist the class distribution to print
  219.    * @return the distribution as a string
  220.    * @exception Exception if distribution can't be printed
  221.    */
  222.   private String printDist(double[] dist) throws Exception {
  223.     StringBuffer text = new StringBuffer();
  224.     
  225.     if (m_Instances.classAttribute().isNominal()) {
  226.       for (int i = 0; i < m_Instances.numClasses(); i++) {
  227. text.append(m_Instances.classAttribute().value(i) + "t");
  228.       }
  229.       text.append("n");
  230.       for (int i = 0; i < m_Instances.numClasses(); i++) {
  231. text.append(dist[i] + "t");
  232.       }
  233.       text.append("n");
  234.     }
  235.     
  236.     return text.toString();
  237.   }
  238.   /** 
  239.    * Prints a classification.
  240.    *
  241.    * @param dist the class distribution
  242.    * @return the classificationn as a string
  243.    * @exception Exception if the classification can't be printed
  244.    */
  245.   private String printClass(double[] dist) throws Exception {
  246.     StringBuffer text = new StringBuffer();
  247.     
  248.     if (m_Instances.classAttribute().isNominal()) {
  249.       text.append(m_Instances.classAttribute().value(Utils.maxIndex(dist)));
  250.     } else {
  251.       text.append(dist[0]);
  252.     }
  253.     
  254.     return text.toString() + "n";
  255.   }
  256.   /**
  257.    * Finds best split for nominal attribute and returns value.
  258.    *
  259.    * @param index attribute index
  260.    * @return value of criterion for the best split
  261.    * @exception Exception if something goes wrong
  262.    */
  263.   private double findSplitNominal(int index) throws Exception {
  264.     if (m_Instances.classAttribute().isNominal()) {
  265.       return findSplitNominalNominal(index);
  266.     } else {
  267.       return findSplitNominalNumeric(index);
  268.     }
  269.   }
  270.   /**
  271.    * Finds best split for nominal attribute and nominal class
  272.    * and returns value.
  273.    *
  274.    * @param index attribute index
  275.    * @return value of criterion for the best split
  276.    * @exception Exception if something goes wrong
  277.    */
  278.   private double findSplitNominalNominal(int index) throws Exception {
  279.     double bestVal = Double.MAX_VALUE, currVal;
  280.     double[][] counts = new double[m_Instances.attribute(index).numValues() 
  281.   + 1][m_Instances.numClasses()];
  282.     double[] sumCounts = new double[m_Instances.numClasses()];
  283.     double[][] bestDist = new double[3][m_Instances.numClasses()];
  284.     int numMissing = 0;
  285.     // Compute counts for all the values
  286.     for (int i = 0; i < m_Instances.numInstances(); i++) {
  287.       Instance inst = m_Instances.instance(i);
  288.       if (inst.isMissing(index)) {
  289. numMissing++;
  290. counts[m_Instances.attribute(index).numValues()]
  291.   [(int)inst.classValue()] += inst.weight();
  292.       } else {
  293. counts[(int)inst.value(index)][(int)inst.classValue()] += inst
  294.   .weight();
  295.       }
  296.     }
  297.     // Compute sum of counts
  298.     for (int i = 0; i < m_Instances.attribute(index).numValues(); i++) {
  299.       for (int j = 0; j < m_Instances.numClasses(); j++) {
  300. sumCounts[j] += counts[i][j];
  301.       }
  302.     }
  303.     
  304.     // Make split counts for each possible split and evaluate
  305.     System.arraycopy(counts[m_Instances.attribute(index).numValues()], 0,
  306.      m_Distribution[2], 0, m_Instances.numClasses());
  307.     for (int i = 0; i < m_Instances.attribute(index).numValues(); i++) {
  308.       for (int j = 0; j < m_Instances.numClasses(); j++) {
  309. m_Distribution[0][j] = counts[i][j];
  310. m_Distribution[1][j] = sumCounts[j] - counts[i][j];
  311.       }
  312.       currVal = ContingencyTables.entropyConditionedOnRows(m_Distribution);
  313.       if (Utils.sm(currVal, bestVal)) {
  314. bestVal = currVal;
  315. m_SplitPoint = (double)i;
  316. for (int j = 0; j < 3; j++) {
  317.   System.arraycopy(m_Distribution[j], 0, bestDist[j], 0, 
  318.    m_Instances.numClasses());
  319. }
  320.       }
  321.     }
  322.     // No missing values in training data.
  323.     if (numMissing == 0) {
  324.       System.arraycopy(sumCounts, 0, bestDist[2], 0, 
  325.        m_Instances.numClasses());
  326.     }
  327.    
  328.     m_Distribution = bestDist;
  329.     return bestVal;
  330.   }
  331.   /**
  332.    * Finds best split for nominal attribute and numeric class
  333.    * and returns value.
  334.    *
  335.    * @param index attribute index
  336.    * @return value of criterion for the best split
  337.    * @exception Exception if something goes wrong
  338.    */
  339.   private double findSplitNominalNumeric(int index) throws Exception {
  340.     double bestVal = Double.MAX_VALUE, currVal;
  341.     double[] sumsSquaresPerValue = 
  342.       new double[m_Instances.attribute(index).numValues()], 
  343.       sumsPerValue = new double[m_Instances.attribute(index).numValues()], 
  344.       weightsPerValue = new double[m_Instances.attribute(index).numValues()];
  345.     double totalSumSquaresW = 0, totalSumW = 0, totalSumOfWeightsW = 0,
  346.       totalSumOfWeights = 0, totalSum = 0;
  347.     double[] sumsSquares = new double[3], sumOfWeights = new double[3];
  348.     double[][] bestDist = new double[3][1];
  349.     // Compute counts for all the values
  350.     for (int i = 0; i < m_Instances.numInstances(); i++) {
  351.       Instance inst = m_Instances.instance(i);
  352.       if (inst.isMissing(index)) {
  353. m_Distribution[2][0] += inst.classValue() * inst.weight();
  354. sumsSquares[2] += inst.classValue() * inst.classValue() 
  355.   * inst.weight();
  356. sumOfWeights[2] += inst.weight();
  357.       } else {
  358. weightsPerValue[(int)inst.value(index)] += inst.weight();
  359. sumsPerValue[(int)inst.value(index)] += inst.classValue() 
  360.   * inst.weight();
  361. sumsSquaresPerValue[(int)inst.value(index)] += 
  362.   inst.classValue() * inst.classValue() * inst.weight();
  363.       }
  364.       totalSumOfWeights += inst.weight();
  365.       totalSum += inst.classValue() * inst.weight();
  366.     }
  367.     // Check if the total weight is zero
  368.     if (Utils.eq(totalSumOfWeights, 0)) {
  369.       return bestVal;
  370.     }
  371.     // Compute sum of counts without missing ones
  372.     for (int i = 0; i < m_Instances.attribute(index).numValues(); i++) {
  373.       totalSumOfWeightsW += weightsPerValue[i];
  374.       totalSumSquaresW += sumsSquaresPerValue[i];
  375.       totalSumW += sumsPerValue[i];
  376.     }
  377.     
  378.     // Make split counts for each possible split and evaluate
  379.     for (int i = 0; i < m_Instances.attribute(index).numValues(); i++) {
  380.       
  381.       m_Distribution[0][0] = sumsPerValue[i];
  382.       sumsSquares[0] = sumsSquaresPerValue[i];
  383.       sumOfWeights[0] = weightsPerValue[i];
  384.       m_Distribution[1][0] = totalSumW - sumsPerValue[i];
  385.       sumsSquares[1] = totalSumSquaresW - sumsSquaresPerValue[i];
  386.       sumOfWeights[1] = totalSumOfWeightsW - weightsPerValue[i];
  387.       currVal = variance(m_Distribution, sumsSquares, sumOfWeights);
  388.       
  389.       if (Utils.sm(currVal, bestVal)) {
  390. bestVal = currVal;
  391. m_SplitPoint = (double)i;
  392. for (int j = 0; j < 3; j++) {
  393.   if (!Utils.eq(sumOfWeights[j], 0)) {
  394.     bestDist[j][0] = m_Distribution[j][0] / sumOfWeights[j];
  395.   } else {
  396.     bestDist[j][0] = totalSum / totalSumOfWeights;
  397.   }
  398. }
  399.       }
  400.     }
  401.     m_Distribution = bestDist;
  402.     return bestVal;
  403.   }
  404.   /**
  405.    * Finds best split for numeric attribute and returns value.
  406.    *
  407.    * @param index attribute index
  408.    * @return value of criterion for the best split
  409.    * @exception Exception if something goes wrong
  410.    */
  411.   private double findSplitNumeric(int index) throws Exception {
  412.     if (m_Instances.classAttribute().isNominal()) {
  413.       return findSplitNumericNominal(index);
  414.     } else {
  415.       return findSplitNumericNumeric(index);
  416.     }
  417.   }
  418.   /**
  419.    * Finds best split for numeric attribute and nominal class
  420.    * and returns value.
  421.    *
  422.    * @param index attribute index
  423.    * @return value of criterion for the best split
  424.    * @exception Exception if something goes wrong
  425.    */
  426.   private double findSplitNumericNominal(int index) throws Exception {
  427.     double bestVal = Double.MAX_VALUE, currVal, currCutPoint;
  428.     int numMissing = 0;
  429.     double[] sum = new double[m_Instances.numClasses()];
  430.     double[][] bestDist = new double[3][m_Instances.numClasses()];
  431.     // Compute counts for all the values
  432.     for (int i = 0; i < m_Instances.numInstances(); i++) {
  433.       Instance inst = m_Instances.instance(i);
  434.       if (!inst.isMissing(index)) {
  435. m_Distribution[1][(int)inst.classValue()] += inst.weight();
  436.       } else {
  437. m_Distribution[2][(int)inst.classValue()] += inst.weight();
  438. numMissing++;
  439.       }
  440.     }
  441.     System.arraycopy(m_Distribution[1], 0, sum, 0, m_Instances.numClasses());
  442.     // Sort instances
  443.     m_Instances.sort(index);
  444.     
  445.     // Make split counts for each possible split and evaluate
  446.     for (int i = 0; i < m_Instances.numInstances() - (numMissing + 1); i++) {
  447.       Instance inst = m_Instances.instance(i);
  448.       Instance instPlusOne = m_Instances.instance(i + 1);
  449.       m_Distribution[0][(int)inst.classValue()] += inst.weight();
  450.       m_Distribution[1][(int)inst.classValue()] -= inst.weight();
  451.       if (Utils.sm(inst.value(index), instPlusOne.value(index))) {
  452. currCutPoint = (inst.value(index) + instPlusOne.value(index)) / 2.0;
  453. currVal = ContingencyTables.entropyConditionedOnRows(m_Distribution);
  454. if (Utils.sm(currVal, bestVal)) {
  455.   m_SplitPoint = currCutPoint;
  456.   bestVal = currVal;
  457.   for (int j = 0; j < 3; j++) {
  458.     System.arraycopy(m_Distribution[j], 0, bestDist[j], 0, 
  459.      m_Instances.numClasses());
  460.   }
  461. }
  462.       }
  463.     }
  464.     // No missing values in training data.
  465.     if (numMissing == 0) {
  466.       System.arraycopy(sum, 0, bestDist[2], 0, m_Instances.numClasses());
  467.     }
  468.  
  469.     m_Distribution = bestDist;
  470.     return bestVal;
  471.   }
  472.   /**
  473.    * Finds best split for numeric attribute and numeric class
  474.    * and returns value.
  475.    *
  476.    * @param index attribute index
  477.    * @return value of criterion for the best split
  478.    * @exception Exception if something goes wrong
  479.    */
  480.   private double findSplitNumericNumeric(int index) throws Exception {
  481.     double bestVal = Double.MAX_VALUE, currVal, currCutPoint;
  482.     int numMissing = 0;
  483.     double[] sumsSquares = new double[3], sumOfWeights = new double[3];
  484.     double[][] bestDist = new double[3][1];
  485.     double totalSum = 0, totalSumOfWeights = 0;
  486.     // Compute counts for all the values
  487.     for (int i = 0; i < m_Instances.numInstances(); i++) {
  488.       Instance inst = m_Instances.instance(i);
  489.       if (!inst.isMissing(index)) {
  490. m_Distribution[1][0] += inst.classValue() * inst.weight();
  491. sumsSquares[1] += inst.classValue() * inst.classValue() 
  492.   * inst.weight();
  493. sumOfWeights[1] += inst.weight();
  494.       } else {
  495. m_Distribution[2][0] += inst.classValue() * inst.weight();
  496. sumsSquares[2] += inst.classValue() * inst.classValue() 
  497.   * inst.weight();
  498. sumOfWeights[2] += inst.weight();
  499. numMissing++;
  500.       }
  501.       totalSumOfWeights += inst.weight();
  502.       totalSum += inst.classValue() * inst.weight();
  503.     }
  504.     // Check if the total weight is zero
  505.     if (Utils.eq(totalSumOfWeights, 0)) {
  506.       return bestVal;
  507.     }
  508.     // Sort instances
  509.     m_Instances.sort(index);
  510.     
  511.     // Make split counts for each possible split and evaluate
  512.     for (int i = 0; i < m_Instances.numInstances() - (numMissing + 1); i++) {
  513.       Instance inst = m_Instances.instance(i);
  514.       Instance instPlusOne = m_Instances.instance(i + 1);
  515.       m_Distribution[0][0] += inst.classValue() * inst.weight();
  516.       sumsSquares[0] += inst.classValue() * inst.classValue() * inst.weight();
  517.       sumOfWeights[0] += inst.weight();
  518.       m_Distribution[1][0] -= inst.classValue() * inst.weight();
  519.       sumsSquares[1] -= inst.classValue() * inst.classValue() * inst.weight();
  520.       sumOfWeights[1] -= inst.weight();
  521.       if (Utils.sm(inst.value(index), instPlusOne.value(index))) {
  522. currCutPoint = (inst.value(index) + instPlusOne.value(index)) / 2.0;
  523. currVal = variance(m_Distribution, sumsSquares, sumOfWeights);
  524. if (Utils.sm(currVal, bestVal)) {
  525.   m_SplitPoint = currCutPoint;
  526.   bestVal = currVal;
  527.   for (int j = 0; j < 3; j++) {
  528.     if (!Utils.eq(sumOfWeights[j], 0)) {
  529.       bestDist[j][0] = m_Distribution[j][0] / sumOfWeights[j];
  530.     } else {
  531.       bestDist[j][0] = totalSum / totalSumOfWeights;
  532.     }
  533.   }
  534. }
  535.       }
  536.     }
  537.     m_Distribution = bestDist;
  538.     return bestVal;
  539.   }
  540.   /**
  541.    * Computes variance for subsets.
  542.    */
  543.   private double variance(double[][] s,double[] sS,double[] sumOfWeights) {
  544.     double var = 0;
  545.     for (int i = 0; i < s.length; i++) {
  546.       if (Utils.gr(sumOfWeights[i], 0)) {
  547. var += sS[i] - ((s[i][0] * s[i][0]) / (double) sumOfWeights[i]);
  548.       }
  549.     }
  550.     
  551.     return var;
  552.   }
  553.   /**
  554.    * Returns the subset an instance falls into.
  555.    */
  556.   private int whichSubset(Instance instance) throws Exception {
  557.     if (instance.isMissing(m_AttIndex)) {
  558.       return 2;
  559.     } else if (instance.attribute(m_AttIndex).isNominal()) {
  560.       if ((int)instance.value(m_AttIndex) == m_SplitPoint) {
  561. return 0;
  562.       } else {
  563. return 1;
  564.       }
  565.     } else {
  566.       if (Utils.smOrEq(instance.value(m_AttIndex), m_SplitPoint)) {
  567. return 0;
  568.       } else {
  569. return 1;
  570.       }
  571.     }
  572.   }
  573.  
  574.   /**
  575.    * Main method for testing this class.
  576.    *
  577.    * @param argv the options
  578.    */
  579.   public static void main(String [] argv) {
  580.     Classifier scheme;
  581.     try {
  582.       scheme = new DecisionStump();
  583.       System.out.println(Evaluation.evaluateModel(scheme, argv));
  584.     } catch (Exception e) {
  585.       System.err.println(e.getMessage());
  586.     }
  587.   }
  588. }