ConsistencySubsetEval.java
Upload User: rhdiban
Upload Date: 2013-08-09
Package Size: 15085k
Code Size: 11k
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.  *    ConsistencySubsetEval.java
  18.  *    Copyright (C) 1999 Mark Hall
  19.  *
  20.  */
  21. package  weka.attributeSelection;
  22. import  java.io.*;
  23. import  java.util.*;
  24. import  weka.core.*;
  25. import  weka.filters.supervised.attribute.Discretize;
  26. import  weka.filters.Filter;
  27. /** 
  28.  * Consistency attribute subset evaluator. <p>
  29.  *
  30.  * For more information see: <br>
  31.  * Liu, H., and Setiono, R., (1996). A probabilistic approach to feature 
  32.  * selection - A filter solution. In 13th International Conference on 
  33.  * Machine Learning (ICML'96), July 1996, pp. 319-327. Bari, Italy. 
  34.  *
  35.  * @author Mark Hall (mhall@cs.waikato.ac.nz)
  36.  * @version $Revision: 1.9 $
  37.  */
  38. public class ConsistencySubsetEval extends SubsetEvaluator {
  39.   
  40.   /** training instances */
  41.   private Instances m_trainInstances;
  42.   /** class index */
  43.   private int m_classIndex;
  44.   /** number of attributes in the training data */
  45.   private int m_numAttribs;
  46.   /** number of instances in the training data */
  47.   private int m_numInstances;
  48.   /** Discretise numeric attributes */
  49.   private Discretize m_disTransform;
  50.   /** Hash table for evaluating feature subsets */
  51.   private Hashtable m_table;
  52.   /**
  53.    * Class providing keys to the hash table.
  54.    */
  55.   public class hashKey {
  56.     
  57.     /** Array of attribute values for an instance */
  58.     private double [] attributes;
  59.     
  60.     /** True for an index if the corresponding attribute value is missing. */
  61.     private boolean [] missing;
  62.     /** The values */
  63.     private String [] values;
  64.     /** The key */
  65.     private int key;
  66.     /**
  67.      * Constructor for a hashKey
  68.      *
  69.      * @param t an instance from which to generate a key
  70.      * @param numAtts the number of attributes
  71.      */
  72.     public hashKey(Instance t, int numAtts) throws Exception {
  73.       int i;
  74.       int cindex = t.classIndex();
  75.       key = -999;
  76.       attributes = new double [numAtts];
  77.       missing = new boolean [numAtts];
  78.       for (i=0;i<numAtts;i++) {
  79. if (i == cindex) {
  80.   missing[i] = true;
  81. } else {
  82.   if ((missing[i] = t.isMissing(i)) == false) {
  83.     attributes[i] = t.value(i);
  84.   }
  85. }
  86.       }
  87.     }
  88.     /**
  89.      * Convert a hash entry to a string
  90.      *
  91.      * @param t the set of instances
  92.      * @param maxColWidth width to make the fields
  93.      */
  94.     public String toString(Instances t, int maxColWidth) {
  95.       int i;
  96.       int cindex = t.classIndex();
  97.       StringBuffer text = new StringBuffer();
  98.       
  99.       for (i=0;i<attributes.length;i++) {
  100. if (i != cindex) {
  101.   if (missing[i]) {
  102.     text.append("?");
  103.     for (int j=0;j<maxColWidth;j++) {
  104.       text.append(" ");
  105.     }
  106.   } else {
  107.     String ss = t.attribute(i).value((int)attributes[i]);
  108.     StringBuffer sb = new StringBuffer(ss);
  109.     
  110.     for (int j=0;j < (maxColWidth-ss.length()+1); j++) {
  111. sb.append(" ");
  112.     }
  113.     text.append(sb);
  114.   }
  115. }
  116.       }
  117.       return text.toString();
  118.     }
  119.     /**
  120.      * Constructor for a hashKey
  121.      *
  122.      * @param t an array of feature values
  123.      */
  124.     public hashKey(double [] t) {
  125.       int i;
  126.       int l = t.length;
  127.       key = -999;
  128.       attributes = new double [l];
  129.       missing = new boolean [l];
  130.       for (i=0;i<l;i++) {
  131. if (t[i] == Double.MAX_VALUE) {
  132.   missing[i] = true;
  133. } else {
  134.   missing[i] = false;
  135.   attributes[i] = t[i];
  136. }
  137.       }
  138.     }
  139.     
  140.     /**
  141.      * Calculates a hash code
  142.      *
  143.      * @return the hash code as an integer
  144.      */
  145.     public int hashCode() {
  146.       int hv = 0;
  147.       
  148.       if (key != -999)
  149. return key;
  150.       for (int i=0;i<attributes.length;i++) {
  151. if (missing[i]) {
  152.   hv += (i*13);
  153. } else {
  154.   hv += (i * 5 * (attributes[i]+1));
  155. }
  156.       }
  157.       if (key == -999) {
  158. key = hv;
  159.       }
  160.       return hv;
  161.     }
  162.     /**
  163.      * Tests if two instances are equal
  164.      *
  165.      * @param b a key to compare with
  166.      */
  167.     public boolean equals(Object b) {
  168.       
  169.       if ((b == null) || !(b.getClass().equals(this.getClass()))) {
  170.         return false;
  171.       }
  172.       boolean ok = true;
  173.       boolean l;
  174.       if (b instanceof hashKey) {
  175. hashKey n = (hashKey)b;
  176. for (int i=0;i<attributes.length;i++) {
  177.   l = n.missing[i];
  178.   if (missing[i] || l) {
  179.     if ((missing[i] && !l) || (!missing[i] && l)) {
  180.       ok = false;
  181.       break;
  182.     }
  183.   } else {
  184.     if (attributes[i] != n.attributes[i]) {
  185.       ok = false;
  186.       break;
  187.     }
  188.   }
  189. }
  190.       } else {
  191. return false;
  192.       }
  193.       return ok;
  194.     }
  195.     
  196.     /**
  197.      * Prints the hash code
  198.      */
  199.     public void print_hash_code() {
  200.       
  201.       System.out.println("Hash val: "+hashCode());
  202.     }
  203.   }
  204.   /**
  205.    * Returns a string describing this search method
  206.    * @return a description of the search suitable for
  207.    * displaying in the explorer/experimenter gui
  208.    */
  209.   public String globalInfo() {
  210.     return "ConsistencySubsetEval :nnEvaluates the worth of a subset of "
  211.       +"attributes by the level of consistency in the class values when the "
  212.       +"training instances are projected onto the subset of attributes. "
  213.       +"nnConsistency of any subset can never be lower than that of the "
  214.       +"full set of attributes, hence the usual practice is to use this "
  215.       +"subset evaluator in conjunction with a Random or Exhaustive search "
  216.       +"which looks for the smallest subset with consistency equal to that "
  217.       +"of the full set of attributes.n";
  218.   }
  219.   /**
  220.    * Constructor. Calls restOptions to set default options
  221.    **/
  222.   public ConsistencySubsetEval () {
  223.     resetOptions();
  224.   }
  225.   /**
  226.    * reset to defaults
  227.    */
  228.   private void resetOptions () {
  229.     m_trainInstances = null;
  230.   }
  231.   /**
  232.    * Generates a attribute evaluator. Has to initialize all fields of the 
  233.    * evaluator that are not being set via options.
  234.    *
  235.    * @param data set of instances serving as training data 
  236.    * @exception Exception if the evaluator has not been 
  237.    * generated successfully
  238.    */
  239.   public void buildEvaluator (Instances data) throws Exception {
  240.     if (data.checkForStringAttributes()) {
  241.       throw  new UnsupportedAttributeTypeException("Can't handle string attributes!");
  242.     }
  243.     m_trainInstances = data;
  244.     m_trainInstances.deleteWithMissingClass();
  245.     m_classIndex = m_trainInstances.classIndex();
  246.     if (m_classIndex < 0) {
  247.       throw new Exception("Consistency subset evaluator requires a class "
  248.   + "attribute!");
  249.     }
  250.     if (m_trainInstances.classAttribute().isNumeric()) {
  251.       throw new Exception("Consistency subset evaluator can't handle a "
  252.   +"numeric class attribute!");
  253.     }
  254.     m_numAttribs = m_trainInstances.numAttributes();
  255.     m_numInstances = m_trainInstances.numInstances();
  256.     m_disTransform = new Discretize();
  257.     m_disTransform.setUseBetterEncoding(true);
  258.     m_disTransform.setInputFormat(m_trainInstances);
  259.     m_trainInstances = Filter.useFilter(m_trainInstances, m_disTransform);
  260.   }
  261.   /**
  262.    * Evaluates a subset of attributes
  263.    *
  264.    * @param subset a bitset representing the attribute subset to be 
  265.    * evaluated 
  266.    * @exception Exception if the subset could not be evaluated
  267.    */
  268.   public double evaluateSubset (BitSet subset) throws Exception {
  269.     int [] fs;
  270.     int i;
  271.     int count = 0;
  272.     for (i=0;i<m_numAttribs;i++) {
  273.       if (subset.get(i)) {
  274. count++;
  275.       }
  276.     }
  277.     double [] instArray = new double[count];
  278.     int index = 0;
  279.     fs = new int[count];
  280.     for (i=0;i<m_numAttribs;i++) {
  281.       if (subset.get(i)) {
  282. fs[index++] = i;
  283.       }
  284.     }
  285.     
  286.     // create new hash table
  287.     m_table = new Hashtable((int)(m_numInstances * 1.5));
  288.     
  289.     for (i=0;i<m_numInstances;i++) {
  290.       Instance inst = m_trainInstances.instance(i);
  291.       for (int j=0;j<fs.length;j++) {
  292. if (fs[j] == m_classIndex) {
  293.   throw new Exception("A subset should not contain the class!");
  294. }
  295. if (inst.isMissing(fs[j])) {
  296.   instArray[j] = Double.MAX_VALUE;
  297. } else {
  298.   instArray[j] = inst.value(fs[j]);
  299. }
  300.       }
  301.       insertIntoTable(inst, instArray);
  302.     }
  303.     return consistencyCount();
  304.   }
  305.   /**
  306.    * calculates the level of consistency in a dataset using a subset of
  307.    * features. The consistency of a hash table entry is the total number
  308.    * of instances hashed to that location minus the number of instances in
  309.    * the largest class hashed to that location. The total consistency is
  310.    * 1.0 minus the sum of the individual consistencies divided by the
  311.    * total number of instances.
  312.    * @return the consistency of the hash table as a value between 0 and 1.
  313.    */
  314.   private double consistencyCount() {
  315.     Enumeration e = m_table.keys();
  316.     double [] classDist;
  317.     double count = 0.0;
  318.     
  319.     while (e.hasMoreElements()) {
  320.       hashKey tt = (hashKey)e.nextElement();
  321.       classDist = (double []) m_table.get(tt);
  322.       count += Utils.sum(classDist);
  323.       int max = Utils.maxIndex(classDist);
  324.       count -= classDist[max];
  325.     }
  326.     count /= (double)m_numInstances;
  327.     return (1.0 - count);
  328.   }
  329.   /**
  330.    * Inserts an instance into the hash table
  331.    *
  332.    * @param inst instance to be inserted
  333.    * @param instA the instance to be inserted as an array of attribute
  334.    * values.
  335.    * @exception Exception if the instance can't be inserted
  336.    */
  337.   private void insertIntoTable(Instance inst, double [] instA)
  338.        throws Exception {
  339.     double [] tempClassDist2;
  340.     double [] newDist;
  341.     hashKey thekey;
  342.     thekey = new hashKey(instA);
  343.     // see if this one is already in the table
  344.     tempClassDist2 = (double []) m_table.get(thekey);
  345.     if (tempClassDist2 == null) {
  346.       newDist = new double [m_trainInstances.classAttribute().numValues()];
  347.       newDist[(int)inst.classValue()] = inst.weight();
  348.       
  349.       // add to the table
  350.       m_table.put(thekey, newDist);
  351.     } else { 
  352.       // update the distribution for this instance
  353.       tempClassDist2[(int)inst.classValue()]+=inst.weight();
  354.       
  355.       // update the table
  356.       m_table.put(thekey, tempClassDist2);
  357.     }
  358.   }
  359.   /**
  360.    * returns a description of the evaluator
  361.    * @return a description of the evaluator as a String.
  362.    */
  363.   public String toString() {
  364.     StringBuffer text = new StringBuffer();
  365.     if (m_trainInstances == null) {
  366.       text.append("tConsistency subset evaluator has not been built yetn");
  367.     }
  368.     else {
  369.       text.append("tConsistency Subset Evaluatorn");
  370.     }
  371.     return text.toString();
  372.   }
  373.   /**
  374.    * Main method for testing this class.
  375.    *
  376.    * @param args the options
  377.    */
  378.   public static void main (String[] args) {
  379.     try {
  380.       System.out.println(AttributeSelection.
  381.  SelectAttributes(new ConsistencySubsetEval(), args));
  382.     }
  383.     catch (Exception e) {
  384.       e.printStackTrace();
  385.       System.out.println(e.getMessage());
  386.     }
  387.   }
  388. }