C45PruneableClassifierTree.java
Upload User: rhdiban
Upload Date: 2013-08-09
Package Size: 15085k
Code Size: 8k
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.  *    C45PruneableClassifierTree.java
  18.  *    Copyright (C) 1999 Eibe Frank
  19.  *
  20.  */
  21. package weka.classifiers.j48;
  22. import weka.core.*;
  23. /**
  24.  * Class for handling a tree structure that can
  25.  * be pruned using C4.5 procedures.
  26.  *
  27.  * @author Eibe Frank (eibe@cs.waikato.ac.nz)
  28.  * @version $Revision: 1.7 $
  29.  */
  30. public class C45PruneableClassifierTree extends ClassifierTree{
  31.   /** True if the tree is to be pruned. */
  32.   boolean m_pruneTheTree = false;
  33.   /** The confidence factor for pruning. */
  34.   float m_CF = 0.25f;
  35.   /** Is subtree raising to be performed? */
  36.   boolean m_subtreeRaising = true;
  37.   /** Cleanup after the tree has been built. */
  38.   boolean m_cleanup = true;
  39.   /**
  40.    * Constructor for pruneable tree structure. Stores reference
  41.    * to associated training data at each node.
  42.    *
  43.    * @param toSelectLocModel selection method for local splitting model
  44.    * @param pruneTree true if the tree is to be pruned
  45.    * @param cf the confidence factor for pruning
  46.    * @exception Exception if something goes wrong
  47.    */
  48.   public C45PruneableClassifierTree(ModelSelection toSelectLocModel,
  49.     boolean pruneTree,float cf,
  50.     boolean raiseTree,
  51.     boolean cleanup)
  52.        throws Exception{
  53.     super(toSelectLocModel);
  54.     m_pruneTheTree = pruneTree;
  55.     m_CF = cf;
  56.     m_subtreeRaising = raiseTree;
  57.     m_cleanup = cleanup;
  58.   }
  59.   /**
  60.    * Method for building a pruneable classifier tree.
  61.    *
  62.    * @exception Exception if something goes wrong
  63.    */
  64.   public void buildClassifier(Instances data) throws Exception{
  65.    if (data.classAttribute().isNumeric())
  66.      throw new UnsupportedClassTypeException("Class is numeric!");
  67.    if (data.checkForStringAttributes()) {
  68.      throw new UnsupportedAttributeTypeException("Can't handle string attributes!");
  69.    }
  70.    data = new Instances(data);
  71.    data.deleteWithMissingClass();
  72.    buildTree(data, m_subtreeRaising);
  73.    collapse();
  74.    if (m_pruneTheTree) {
  75.      prune();
  76.    }
  77.    if (m_cleanup) {
  78.      cleanup(new Instances(data, 0));
  79.    }
  80.   }
  81.   /**
  82.    * Collapses a tree to a node if training error doesn't increase.
  83.    */
  84.   public final void collapse(){
  85.     double errorsOfSubtree;
  86.     double errorsOfTree;
  87.     int i;
  88.     if (!m_isLeaf){
  89.       errorsOfSubtree = getTrainingErrors();
  90.       errorsOfTree = localModel().distribution().numIncorrect();
  91.       if (errorsOfSubtree >= errorsOfTree-1E-3){
  92. // Free adjacent trees
  93. m_sons = null;
  94. m_isLeaf = true;
  95. // Get NoSplit Model for tree.
  96. m_localModel = new NoSplit(localModel().distribution());
  97.       }else
  98. for (i=0;i<m_sons.length;i++)
  99.   son(i).collapse();
  100.     }
  101.   }
  102.   /**
  103.    * Prunes a tree using C4.5's pruning procedure.
  104.    *
  105.    * @exception Exception if something goes wrong
  106.    */
  107.   public void prune() throws Exception {
  108.     double errorsLargestBranch;
  109.     double errorsLeaf;
  110.     double errorsTree;
  111.     int indexOfLargestBranch;
  112.     C45PruneableClassifierTree largestBranch;
  113.     int i;
  114.     if (!m_isLeaf){
  115.       // Prune all subtrees.
  116.       for (i=0;i<m_sons.length;i++)
  117. son(i).prune();
  118.       // Compute error for largest branch
  119.       indexOfLargestBranch = localModel().distribution().maxBag();
  120.       if (m_subtreeRaising) {
  121. errorsLargestBranch = son(indexOfLargestBranch).
  122.   getEstimatedErrorsForBranch((Instances)m_train);
  123.       } else {
  124. errorsLargestBranch = Double.MAX_VALUE;
  125.       }
  126.       // Compute error if this Tree would be leaf
  127.       errorsLeaf = 
  128. getEstimatedErrorsForDistribution(localModel().distribution());
  129.       // Compute error for the whole subtree
  130.       errorsTree = getEstimatedErrors();
  131.       // Decide if leaf is best choice.
  132.       if (Utils.smOrEq(errorsLeaf,errorsTree+0.1) &&
  133.   Utils.smOrEq(errorsLeaf,errorsLargestBranch+0.1)){
  134. // Free son Trees
  135. m_sons = null;
  136. m_isLeaf = true;
  137. // Get NoSplit Model for node.
  138. m_localModel = new NoSplit(localModel().distribution());
  139. return;
  140.       }
  141.       // Decide if largest branch is better choice
  142.       // than whole subtree.
  143.       if (Utils.smOrEq(errorsLargestBranch,errorsTree+0.1)){
  144. largestBranch = son(indexOfLargestBranch);
  145. m_sons = largestBranch.m_sons;
  146. m_localModel = largestBranch.localModel();
  147. m_isLeaf = largestBranch.m_isLeaf;
  148. newDistribution(m_train);
  149. prune();
  150.       }
  151.     }
  152.   }
  153.   /**
  154.    * Returns a newly created tree.
  155.    *
  156.    * @exception Exception if something goes wrong
  157.    */
  158.   protected ClassifierTree getNewTree(Instances data) throws Exception{
  159.     
  160.     C45PruneableClassifierTree newTree = 
  161.       new C45PruneableClassifierTree(m_toSelectModel, m_pruneTheTree, m_CF,
  162.      m_subtreeRaising, m_cleanup);
  163.     newTree.buildTree((Instances)data, m_subtreeRaising);
  164.     return newTree;
  165.   }
  166.   /**
  167.    * Computes estimated errors for tree.
  168.    */
  169.   private double getEstimatedErrors(){
  170.     double errors = 0;
  171.     int i;
  172.     if (m_isLeaf)
  173.       return getEstimatedErrorsForDistribution(localModel().distribution());
  174.     else{
  175.       for (i=0;i<m_sons.length;i++)
  176. errors = errors+son(i).getEstimatedErrors();
  177.       return errors;
  178.     }
  179.   }
  180.   
  181.   /**
  182.    * Computes estimated errors for one branch.
  183.    *
  184.    * @exception Exception if something goes wrong
  185.    */
  186.   private double getEstimatedErrorsForBranch(Instances data) 
  187.        throws Exception {
  188.     Instances [] localInstances;
  189.     double errors = 0;
  190.     int i;
  191.     if (m_isLeaf)
  192.       return getEstimatedErrorsForDistribution(new Distribution(data));
  193.     else{
  194.       Distribution savedDist = localModel().m_distribution;
  195.       localModel().resetDistribution(data);
  196.       localInstances = (Instances[])localModel().split(data);
  197.       localModel().m_distribution = savedDist;
  198.       for (i=0;i<m_sons.length;i++)
  199. errors = errors+
  200.   son(i).getEstimatedErrorsForBranch(localInstances[i]);
  201.       return errors;
  202.     }
  203.   }
  204.   /**
  205.    * Computes estimated errors for leaf.
  206.    */
  207.   private double getEstimatedErrorsForDistribution(Distribution 
  208.    theDistribution){
  209.     if (Utils.eq(theDistribution.total(),0))
  210.       return 0;
  211.     else
  212.       return theDistribution.numIncorrect()+
  213. Stats.addErrs(theDistribution.total(),
  214.       theDistribution.numIncorrect(),m_CF);
  215.   }
  216.   /**
  217.    * Computes errors of tree on training data.
  218.    */
  219.   private double getTrainingErrors(){
  220.     double errors = 0;
  221.     int i;
  222.     if (m_isLeaf)
  223.       return localModel().distribution().numIncorrect();
  224.     else{
  225.       for (i=0;i<m_sons.length;i++)
  226. errors = errors+son(i).getTrainingErrors();
  227.       return errors;
  228.     }
  229.   }
  230.   /**
  231.    * Method just exists to make program easier to read.
  232.    */
  233.   private ClassifierSplitModel localModel(){
  234.     
  235.     return (ClassifierSplitModel)m_localModel;
  236.   }
  237.   /**
  238.    * Computes new distributions of instances for nodes
  239.    * in tree.
  240.    *
  241.    * @exception Exception if something goes wrong
  242.    */
  243.   private void newDistribution(Instances data) throws Exception {
  244.     Instances [] localInstances;
  245.     localModel().resetDistribution(data);
  246.     m_train = data;
  247.     if (!m_isLeaf){
  248.       localInstances = 
  249. (Instances [])localModel().split(data);
  250.       for (int i = 0; i < m_sons.length; i++)
  251. son(i).newDistribution(localInstances[i]);
  252.     }
  253.   }
  254.   /**
  255.    * Method just exists to make program easier to read.
  256.    */
  257.   private C45PruneableClassifierTree son(int index){
  258.     return (C45PruneableClassifierTree)m_sons[index];
  259.   }
  260. }