CSVLoader.java
Upload User: rhdiban
Upload Date: 2013-08-09
Package Size: 15085k
Code Size: 15k
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.  *    CsvToArff.java
  18.  *    Copyright (C) 2000 Mark Hall
  19.  *
  20.  */
  21. package weka.core.converters;
  22. import java.io.BufferedReader;
  23. import java.io.File;
  24. import java.io.FileNotFoundException;
  25. import java.io.FileReader;
  26. import java.io.IOException;
  27. import java.io.Reader;
  28. import java.util.Hashtable;
  29. import java.util.Enumeration;
  30. import weka.core.FastVector;
  31. import weka.core.Instances;
  32. import weka.core.Instance;
  33. import weka.core.Attribute;
  34. import java.io.StreamTokenizer;
  35. /**
  36.  * Reads a text file that is comma or tab delimited..
  37.  *
  38.  * @author Mark Hall (mhall@cs.waikato.ac.nz)
  39.  * @version $Revision: 1.2 $
  40.  * @see Loader
  41.  */
  42. public class CSVLoader extends AbstractLoader {
  43.   /**
  44.    * Holds the determined structure (header) of the data set.
  45.    */
  46.   //@ protected depends: model_structureDetermined -> m_structure;
  47.   //@ protected represents: model_structureDetermined <- (m_structure != null);
  48.   protected Instances m_structure = null;
  49.   /**
  50.    * Holds the source of the data set.
  51.    */
  52.   //@ protected depends: model_sourceSupplied -> m_sourceFile;
  53.   //@ protected represents: model_sourceSupplied <- (m_sourceFile != null);
  54.   protected File m_sourceFile = null;
  55.   /**
  56.    * Describe variable <code>m_tokenizer</code> here.
  57.    */
  58.   //  private StreamTokenizer m_tokenizer = null;
  59.   /**
  60.    * A list of hash tables for accumulating nominal values during parsing.
  61.    */
  62.   private FastVector m_cumulativeStructure;
  63.   /**
  64.    * Holds instances accumulated so far
  65.    */
  66.   private FastVector m_cumulativeInstances;
  67.   /**
  68.    * Returns a string describing this attribute evaluator
  69.    * @return a description of the evaluator suitable for
  70.    * displaying in the explorer/experimenter gui
  71.    */
  72.   public String globalInfo() {
  73.     return "Reads a source that is in comma separated or tab separated format. "
  74.       +"Assumes that the first row in the file determines the number of "
  75.       +"and names of the attributes.";
  76.   }
  77.   
  78.   /**
  79.    * Resets the loader ready to read a new data set
  80.    */
  81.   public void reset() {
  82.     m_structure = null;
  83.   }
  84.   /**
  85.    * Resets the Loader object and sets the source of the data set to be 
  86.    * the supplied File object.
  87.    *
  88.    * @param file the source file.
  89.    * @exception IOException if an error occurs
  90.    */
  91.   public void setSource(File file) throws IOException {
  92.     reset();
  93.     if (file == null) {
  94.       throw new IOException("Source file object is null!");
  95.     }
  96.     m_sourceFile = file;
  97.     try {
  98.       BufferedReader br = new BufferedReader(new FileReader(file));
  99.       br.close();
  100.     } catch (FileNotFoundException ex) {
  101.       throw new IOException("File not found");
  102.     }
  103.   }
  104.   /**
  105.    * Determines and returns (if possible) the structure (internally the 
  106.    * header) of the data set as an empty set of instances.
  107.    *
  108.    * @return the structure of the data set as an empty set of Instances
  109.    * @exception IOException if an error occurs
  110.    */
  111.   public Instances getStructure() throws IOException {
  112.     if (m_sourceFile == null) {
  113.       throw new IOException("No source has been specified");
  114.     }
  115.     if (m_structure == null) {
  116.       try {
  117. BufferedReader br = new BufferedReader(new FileReader(m_sourceFile));
  118.      
  119. // assumes that the first line of the file is the header
  120. /*m_tokenizer = new StreamTokenizer(br);
  121. initTokenizer(m_tokenizer);
  122. readHeader(m_tokenizer); */
  123. StreamTokenizer st = new StreamTokenizer(br);
  124. initTokenizer(st);
  125. readStructure(st);
  126.       } catch (FileNotFoundException ex) {
  127.       }
  128.     }
  129.     
  130.     return m_structure;
  131.   }
  132.   private void readStructure(StreamTokenizer st) throws IOException {
  133.     readHeader(st);
  134.   }
  135.   /**
  136.    * Return the full data set. If the structure hasn't yet been determined
  137.    * by a call to getStructure then method should do so before processing
  138.    * the rest of the data set.
  139.    *
  140.    * @return the structure of the data set as an empty set of Instances
  141.    * @exception IOException if there is no source or parsing fails
  142.    */
  143.   public Instances getDataSet() throws IOException {
  144.     if (m_sourceFile == null) {
  145.       throw new IOException("No source has been specified");
  146.     }
  147.     //    m_sourceReader.close();
  148.     setSource(m_sourceFile);
  149.     BufferedReader br = new BufferedReader(new FileReader(m_sourceFile));
  150.     //    getStructure();
  151.     StreamTokenizer st = new StreamTokenizer(br);
  152.     initTokenizer(st);
  153.     readStructure(st);
  154.     
  155.     st.ordinaryChar(',');
  156.     st.ordinaryChar('t');
  157.     
  158.     m_cumulativeStructure = new FastVector(m_structure.numAttributes());
  159.     for (int i = 0; i < m_structure.numAttributes(); i++) {
  160.       m_cumulativeStructure.addElement(new Hashtable());
  161.     }
  162.     
  163.     // Instances result = new Instances(m_structure);
  164.     m_cumulativeInstances = new FastVector();
  165.     FastVector current;
  166.     while ((current = getInstance(st)) != null) {
  167.       m_cumulativeInstances.addElement(current);
  168.     }
  169.     br.close();
  170.     // now determine the true structure of the data set
  171.     FastVector atts = new FastVector(m_structure.numAttributes());
  172.     for (int i = 0; i < m_structure.numAttributes(); i++) {
  173.       String attname = m_structure.attribute(i).name();
  174.       Hashtable tempHash = ((Hashtable)m_cumulativeStructure.elementAt(i));
  175.       if (tempHash.size() == 0) {
  176. atts.addElement(new Attribute(attname));
  177.       } else {
  178. FastVector values = new FastVector(tempHash.size());
  179. // add dummy objects in order to make the FastVector's size == capacity
  180. for (int z = 0; z < tempHash.size(); z++) {
  181.   values.addElement("dummy");
  182. }
  183. Enumeration e = tempHash.keys();
  184. while (e.hasMoreElements()) {
  185.   Object ob = e.nextElement();
  186.   //   if (ob instanceof Double) {
  187.   int index = ((Integer)tempHash.get(ob)).intValue();
  188.   values.setElementAt(new String(ob.toString()), index);
  189.   //   }
  190. }
  191. atts.addElement(new Attribute(attname, values));
  192.       }
  193.     }
  194.     // make the instances
  195.     Instances dataSet = new Instances(m_sourceFile.getName(), 
  196.       atts, 
  197.       m_cumulativeInstances.size());
  198.     for (int i = 0; i < m_cumulativeInstances.size(); i++) {
  199.       current = ((FastVector)m_cumulativeInstances.elementAt(i));
  200.       double [] vals = new double[dataSet.numAttributes()];
  201.       for (int j = 0; j < current.size(); j++) {
  202. Object cval = current.elementAt(j);
  203. if (cval instanceof String) {
  204.   if (((String)cval).compareTo("?") == 0) {
  205.     vals[j] = Instance.missingValue();
  206.   } else {
  207.     if (!dataSet.attribute(j).isNominal()) {
  208.       System.err.println("Wrong attribute type!!!");
  209.       System.exit(1);
  210.     }
  211.     // find correct index
  212.     Hashtable lookup = (Hashtable)m_cumulativeStructure.elementAt(j);
  213.     int index = ((Integer)lookup.get(cval)).intValue();
  214.     vals[j] = (double)index;
  215.   }
  216. } else if (dataSet.attribute(j).isNominal()) {
  217.   // find correct index
  218.   Hashtable lookup = (Hashtable)m_cumulativeStructure.elementAt(j);
  219.   int index = ((Integer)lookup.get(cval)).intValue();
  220.   vals[j] = (double)index;
  221. } else {
  222.   vals[j] = ((Double)cval).doubleValue();
  223. }
  224.       }
  225.       dataSet.add(new Instance(1.0, vals));
  226.     }
  227.     m_structure = new Instances(dataSet, 0);
  228.     return dataSet;
  229.   }
  230.   /**
  231.    * CSVLoader is unable to process a data set incrementally.
  232.    *
  233.    * @return never returns without throwing an exception
  234.    * @exception IOException always. CSVLoader is unable to process a data
  235.    * set incrementally.
  236.    */
  237.   public Instance getNextInstance() throws IOException {
  238.     throw new IOException("CSVLoader can't read data sets incrementally.");
  239.   }
  240.   /**
  241.    * Attempts to parse a line of the data set.
  242.    *
  243.    * @param tokenizer the tokenizer
  244.    * @return a FastVector containg String and Double objects representing
  245.    * the values of the instance.
  246.    * @exception IOException if an error occurs
  247.    *
  248.    * <pre><jml>
  249.    *    private_normal_behavior
  250.    *      requires: tokenizer != null;
  251.    *      ensures: result  != null;
  252.    *  also
  253.    *    private_exceptional_behavior
  254.    *      requires: tokenizer == null
  255.    *                || (* unsucessful parse *);
  256.    *      signals: (IOException);
  257.    * </jml></pre>
  258.    */
  259.   private FastVector getInstance(StreamTokenizer tokenizer) 
  260.     throws IOException {
  261.     FastVector current = new FastVector();
  262.     // Check if end of file reached.
  263.     ConverterUtils.getFirstToken(tokenizer);
  264.     if (tokenizer.ttype == StreamTokenizer.TT_EOF) {
  265.       return null;
  266.     }
  267.     boolean first = true;
  268.     boolean wasSep;
  269.     while (tokenizer.ttype != StreamTokenizer.TT_EOL &&
  270.    tokenizer.ttype != StreamTokenizer.TT_EOF) {
  271.       
  272.       // Get next token
  273.       if (!first) {
  274. ConverterUtils.getToken(tokenizer);
  275.       }
  276.       if (tokenizer.ttype == ',' || tokenizer.ttype == 't' || 
  277.   tokenizer.ttype == StreamTokenizer.TT_EOL) {
  278. current.addElement("?");
  279. wasSep = true;
  280.       } else {
  281. wasSep = false;
  282. /* // Check if token is valid.
  283. if (tokenizer.ttype != StreamTokenizer.TT_WORD) {
  284.   errms(tokenizer,"not a valid value");
  285.   }*/
  286. // try to parse as a number
  287. try {
  288.   double val = Double.valueOf(tokenizer.sval).doubleValue();
  289.   current.addElement(new Double(val));
  290. } catch (NumberFormatException e) {
  291.   // otherwise assume its an enumerated value
  292.   current.addElement(new String(tokenizer.sval.replace(' ','_')));
  293. }
  294.       }
  295.       
  296.       if (!wasSep) {
  297. ConverterUtils.getToken(tokenizer);
  298.       }
  299.       first = false;
  300.     }
  301.     
  302.     // check number of values read
  303.     if (current.size() != m_structure.numAttributes()) {
  304.       ConverterUtils.errms(tokenizer, 
  305.    "wrong number of values. Read "+current.size()
  306.    +", expected "+m_structure.numAttributes());
  307.     }
  308.     // check for structure update
  309.     try {
  310.       checkStructure(current);
  311.     } catch (Exception ex) {
  312.       ex.printStackTrace();
  313.     }
  314.     return current;
  315.   }
  316.   /**
  317.    * Checks the current instance against what is known about the structure
  318.    * of the data set so far. If there is a nominal value for an attribute
  319.    * that was beleived to be numeric then all previously seen values for this
  320.    * attribute are stored in a Hashtable.
  321.    *
  322.    * @param current a <code>FastVector</code> value
  323.    * @exception Exception if an error occurs
  324.    *
  325.    * <pre><jml>
  326.    *    private_normal_behavior
  327.    *      requires: current != null;
  328.    *  also
  329.    *    private_exceptional_behavior
  330.    *      requires: current == null
  331.    *                || (* unrecognized object type in current *);
  332.    *      signals: (Exception);
  333.    * </jml></pre>
  334.    */
  335.   private void checkStructure(FastVector current) throws Exception {
  336.     if (current == null) {
  337.       throw new Exception("current shouldn't be null in checkStructure");
  338.     }
  339.     for (int i = 0; i < current.size(); i++) {
  340.       Object ob = current.elementAt(i);
  341.       if (ob instanceof String) {
  342. if (((String)ob).compareTo("?") == 0) {
  343. } else {
  344.   Hashtable tempHash = (Hashtable)m_cumulativeStructure.elementAt(i);
  345.   if (!tempHash.containsKey(ob)) {
  346.     // may have found a nominal value in what was previously thought to
  347.     // be a numeric variable.
  348.     if (tempHash.size() == 0) {
  349.       for (int j = 0; j < m_cumulativeInstances.size(); j++) {
  350. FastVector tempUpdate = 
  351.   ((FastVector)m_cumulativeInstances.elementAt(j));
  352. Object tempO = tempUpdate.elementAt(i);
  353. if (tempO instanceof String) {
  354.   // must have been a missing value
  355. } else {
  356.   if (!tempHash.containsKey(tempO)) {
  357.     tempHash.put(new Double(((Double)tempO).doubleValue()), 
  358.  new Integer(tempHash.size()));
  359.   }
  360. }
  361.       }
  362.     }
  363.     int newIndex = tempHash.size();
  364.     tempHash.put(ob, new Integer(newIndex));
  365.   }
  366. }
  367.       } else if (ob instanceof Double) {
  368. Hashtable tempHash = (Hashtable)m_cumulativeStructure.elementAt(i);
  369. if (tempHash.size() != 0) {
  370.   if (!tempHash.containsKey(ob)) {
  371.     int newIndex = tempHash.size();
  372.     tempHash.put(new Double(((Double)ob).doubleValue()), 
  373.     new Integer(newIndex));
  374.   }
  375. }
  376.       } else {
  377. throw new Exception("Wrong object type in checkStructure!");
  378.       }
  379.     }
  380.   }
  381.   /**
  382.    * Assumes the first line of the file contains the attribute names.
  383.    * Assumes all attributes are real (Reading the full data set with
  384.    * getDataSet will establish the true structure).
  385.    *
  386.    * @param tokenizer a <code>StreamTokenizer</code> value
  387.    * @exception IOException if an error occurs
  388.    *
  389.    * <pre><jml>
  390.    *    private_normal_behavior
  391.    *      requires: tokenizer != null;
  392.    *      modifiable: m_structure;
  393.    *      ensures: m_structure != null;
  394.    *  also
  395.    *    private_exceptional_behavior
  396.    *      requires: tokenizer == null
  397.    *                || (* unsucessful parse *);
  398.    *      signals: (IOException);
  399.    * </jml></pre>
  400.    */
  401.   private void readHeader(StreamTokenizer tokenizer) throws IOException {
  402.    
  403.     FastVector attribNames = new FastVector();
  404.     ConverterUtils.getFirstToken(tokenizer);
  405.     if (tokenizer.ttype == StreamTokenizer.TT_EOF) {
  406.       ConverterUtils.errms(tokenizer,"premature end of file");
  407.     }
  408.     while (tokenizer.ttype != StreamTokenizer.TT_EOL) {
  409.       attribNames.addElement(new Attribute(tokenizer.sval));
  410.       ConverterUtils.getToken(tokenizer);
  411.     }
  412.     
  413.     m_structure = new Instances(m_sourceFile.getName(), attribNames, 0);
  414.   }
  415.   /**
  416.    * Initializes the stream tokenizer
  417.    *
  418.    * @param tokenizer the tokenizer to initialize
  419.    */
  420.   private void initTokenizer(StreamTokenizer tokenizer) {
  421.     tokenizer.resetSyntax();         
  422.     tokenizer.whitespaceChars(0, (' '-1));    
  423.     tokenizer.wordChars(' ','u00FF');
  424.     tokenizer.whitespaceChars(',',',');
  425.     tokenizer.whitespaceChars('t','t');
  426.     //    tokenizer.ordinaryChar(',');
  427.     tokenizer.commentChar('%');
  428.     tokenizer.quoteChar('"');
  429.     tokenizer.quoteChar(''');
  430.     //    tokenizer.ordinaryChar('{');
  431.     //    tokenizer.ordinaryChar('}');
  432.     tokenizer.eolIsSignificant(true);
  433.   }
  434.   /**
  435.    * Main method.
  436.    *
  437.    * @param args should contain the name of an input file.
  438.    */
  439.   public static void main(String [] args) {
  440.     if (args.length > 0) {
  441.       File inputfile;
  442.       inputfile = new File(args[0]);
  443.       try {
  444. CSVLoader atf = new CSVLoader();
  445. atf.setSource(inputfile);
  446. System.out.println(atf.getDataSet());
  447.       } catch (Exception ex) {
  448. ex.printStackTrace();
  449. }
  450.     } else {
  451.       System.err.println("Usage:ntCSVLoader <file.csv>n");
  452.     }
  453.   }
  454. }