source: branches/MetisMQI/src/main/java/weka/filters/unsupervised/attribute/FirstOrder.java

Last change on this file was 29, checked in by gnappo, 15 years ago

Taggata versione per la demo e aggiunto branch.

File size: 11.2 KB
Line 
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/*
18 *    FirstOrder.java
19 *    Copyright (C) 1999 University of Waikato, Hamilton, New Zealand
20 *
21 */
22
23
24package weka.filters.unsupervised.attribute;
25
26import weka.core.Attribute;
27import weka.core.Capabilities;
28import weka.core.FastVector;
29import weka.core.Instance; 
30import weka.core.DenseInstance;
31import weka.core.Instances;
32import weka.core.Option;
33import weka.core.OptionHandler;
34import weka.core.Range;
35import weka.core.RevisionUtils;
36import weka.core.SparseInstance;
37import weka.core.UnsupportedAttributeTypeException;
38import weka.core.Utils;
39import weka.core.Capabilities.Capability;
40import weka.filters.Filter;
41import weka.filters.StreamableFilter;
42import weka.filters.UnsupervisedFilter;
43
44import java.util.Enumeration;
45import java.util.Vector;
46
47/**
48 <!-- globalinfo-start -->
49 * This instance filter takes a range of N numeric attributes and replaces them with N-1 numeric attributes, the values of which are the difference between consecutive attribute values from the original instance. eg: <br/>
50 * <br/>
51 * Original attribute values<br/>
52 * <br/>
53 *    0.1, 0.2, 0.3, 0.1, 0.3<br/>
54 * <br/>
55 * New attribute values<br/>
56 * <br/>
57 *    0.1, 0.1, -0.2, 0.2<br/>
58 * <br/>
59 * The range of attributes used is taken in numeric order. That is, a range spec of 7-11,3-5 will use the attribute ordering 3,4,5,7,8,9,10,11 for the differences, NOT 7,8,9,10,11,3,4,5.
60 * <p/>
61 <!-- globalinfo-end -->
62 *
63 <!-- options-start -->
64 * Valid options are: <p/>
65 *
66 * <pre> -R &lt;index1,index2-index4,...&gt;
67 *  Specify list of columns to take the differences between.
68 *  First and last are valid indexes.
69 *  (default none)</pre>
70 *
71 <!-- options-end -->
72 *
73 * @author Len Trigg (trigg@cs.waikato.ac.nz)
74 * @version $Revision: 5987 $
75 */
76public class FirstOrder 
77  extends Filter
78  implements UnsupervisedFilter, StreamableFilter, OptionHandler {
79
80  /** for serialization */
81  static final long serialVersionUID = -7500464545400454179L;
82 
83  /** Stores which columns to take differences between */
84  protected Range m_DeltaCols = new Range();
85
86  /**
87   * Returns a string describing this filter
88   *
89   * @return a description of the filter suitable for
90   * displaying in the explorer/experimenter gui
91   */
92  public String globalInfo() {
93
94    return "This instance filter takes a range of N numeric attributes and replaces "
95      + "them with N-1 numeric attributes, the values of which are the difference "
96      + "between consecutive attribute values from the original instance. eg: \n\n"
97      + "Original attribute values\n\n"
98      + "   0.1, 0.2, 0.3, 0.1, 0.3\n\n"
99      + "New attribute values\n\n"
100      + "   0.1, 0.1, -0.2, 0.2\n\n"
101      + "The range of attributes used is taken in numeric order. That is, a range "
102      + "spec of 7-11,3-5 will use the attribute ordering 3,4,5,7,8,9,10,11 for the "
103      + "differences, NOT 7,8,9,10,11,3,4,5.";
104  }
105
106  /**
107   * Returns an enumeration describing the available options.
108   *
109   * @return an enumeration of all the available options.
110   */
111  public Enumeration listOptions() {
112
113    Vector newVector = new Vector(1);
114
115    newVector.addElement(new Option(
116              "\tSpecify list of columns to take the differences between.\n"
117              + "\tFirst and last are valid indexes.\n"
118              + "\t(default none)",
119              "R", 1, "-R <index1,index2-index4,...>"));
120
121    return newVector.elements();
122  }
123
124
125  /**
126   * Parses a given list of options. <p/>
127   *
128   <!-- options-start -->
129   * Valid options are: <p/>
130   *
131   * <pre> -R &lt;index1,index2-index4,...&gt;
132   *  Specify list of columns to take the differences between.
133   *  First and last are valid indexes.
134   *  (default none)</pre>
135   *
136   <!-- options-end -->
137   *
138   * @param options the list of options as an array of strings
139   * @throws Exception if an option is not supported
140   */
141  public void setOptions(String[] options) throws Exception {
142
143    String deltaList = Utils.getOption('R', options);
144    if (deltaList.length() != 0) {
145      setAttributeIndices(deltaList);
146    } else {
147      setAttributeIndices("");
148    }
149   
150    if (getInputFormat() != null)
151      setInputFormat(getInputFormat());
152  }
153
154
155  /**
156   * Gets the current settings of the filter.
157   *
158   * @return an array of strings suitable for passing to setOptions
159   */
160  public String [] getOptions() {
161
162    String [] options = new String [2];
163    int current = 0;
164
165    if (!getAttributeIndices().equals("")) {
166      options[current++] = "-R"; options[current++] = getAttributeIndices();
167    }
168
169    while (current < options.length) {
170      options[current++] = "";
171    }
172    return options;
173  }
174
175  /**
176   * Returns the Capabilities of this filter.
177   *
178   * @return            the capabilities of this object
179   * @see               Capabilities
180   */
181  public Capabilities getCapabilities() {
182    Capabilities result = super.getCapabilities();
183    result.disableAll();
184
185    // attributes
186    result.enableAllAttributes();
187    result.enable(Capability.MISSING_VALUES);
188   
189    // class
190    result.enableAllClasses();
191    result.enable(Capability.MISSING_CLASS_VALUES);
192    result.enable(Capability.NO_CLASS);
193   
194    return result;
195  }
196
197  /**
198   * Sets the format of the input instances.
199   *
200   * @param instanceInfo an Instances object containing the input instance
201   * structure (any instances contained in the object are ignored - only the
202   * structure is required).
203   * @return true if the outputFormat may be collected immediately
204   * @throws UnsupportedAttributeTypeException if any of the
205   * selected attributes are not numeric
206   * @throws Exception if only one attribute has been selected.
207   */
208  public boolean setInputFormat(Instances instanceInfo) throws Exception {
209
210    super.setInputFormat(instanceInfo);
211
212    m_DeltaCols.setUpper(getInputFormat().numAttributes() - 1);
213    int selectedCount = 0;
214    for (int i = getInputFormat().numAttributes() - 1; i >= 0; i--) {
215      if (m_DeltaCols.isInRange(i)) {
216        selectedCount++;
217        if (!getInputFormat().attribute(i).isNumeric()) {
218          throw new UnsupportedAttributeTypeException("Selected attributes must be all numeric");
219        }
220      }
221    }
222    if (selectedCount == 1) {
223      throw new Exception("Cannot select only one attribute.");
224    }
225
226    // Create the output buffer
227    FastVector newAtts = new FastVector();
228    boolean inRange = false;
229    String foName = null;
230    int clsIndex = -1;
231    for(int i = 0; i < instanceInfo.numAttributes(); i++) {
232      if (m_DeltaCols.isInRange(i) && (i != instanceInfo.classIndex())) {
233        if (inRange) {
234          Attribute newAttrib = new Attribute(foName);
235          newAtts.addElement(newAttrib);
236        }
237        foName = instanceInfo.attribute(i).name();
238        foName = "'FO " + foName.replace('\'', ' ').trim() + '\'';
239        inRange = true;
240      } else {
241        newAtts.addElement((Attribute)instanceInfo.attribute(i).copy());
242        if ((i == instanceInfo.classIndex()))
243          clsIndex = newAtts.size() - 1;
244      }     
245    }
246    Instances data = new Instances(instanceInfo.relationName(), newAtts, 0);
247    data.setClassIndex(clsIndex);
248    setOutputFormat(data);
249    return true;
250  }
251 
252
253  /**
254   * Input an instance for filtering. Ordinarily the instance is processed
255   * and made available for output immediately. Some filters require all
256   * instances be read before producing output.
257   *
258   * @param instance the input instance
259   * @return true if the filtered instance may now be
260   * collected with output().
261   * @throws IllegalStateException if no input format has been defined.
262   */
263  public boolean input(Instance instance) {
264
265    if (getInputFormat() == null) {
266      throw new IllegalStateException("No input instance format defined");
267    }
268    if (m_NewBatch) {
269      resetQueue();
270      m_NewBatch = false;
271    }
272
273    Instances outputFormat = outputFormatPeek();
274    double[] vals = new double[outputFormat.numAttributes()];
275    boolean inRange = false;
276    double lastVal = Utils.missingValue();
277    int i, j;
278    for(i = 0, j = 0; j < outputFormat.numAttributes(); i++) {
279      if (m_DeltaCols.isInRange(i) && (i != instance.classIndex())) {
280        if (inRange) {
281          if (Utils.isMissingValue(lastVal) || instance.isMissing(i)) {
282            vals[j++] = Utils.missingValue();
283          } else {
284            vals[j++] = instance.value(i) - lastVal;
285          }
286        } else {
287          inRange = true;
288        }
289        lastVal = instance.value(i);
290      } else {
291        vals[j++] = instance.value(i);
292      }
293    }
294
295    Instance inst = null;
296    if (instance instanceof SparseInstance) {
297      inst = new SparseInstance(instance.weight(), vals);
298    } else {
299      inst = new DenseInstance(instance.weight(), vals);
300    }
301    inst.setDataset(getOutputFormat());
302    copyValues(inst, false, instance.dataset(), getOutputFormat());
303    inst.setDataset(getOutputFormat());
304    push(inst);
305    return true;
306  }
307
308
309  /**
310   * Returns the tip text for this property
311   *
312   * @return tip text for this property suitable for
313   * displaying in the explorer/experimenter gui
314   */
315  public String attributeIndicesTipText() {
316    return "Specify range of attributes to act on."
317      + " This is a comma separated list of attribute indices, with"
318      + " \"first\" and \"last\" valid values. Specify an inclusive"
319      + " range with \"-\". E.g: \"first-3,5,6-10,last\".";
320  }
321
322  /**
323   * Get the current range selection
324   *
325   * @return a string containing a comma separated list of ranges
326   */
327  public String getAttributeIndices() {
328
329    return m_DeltaCols.getRanges();
330  }
331
332  /**
333   * Set which attributes are to be deleted (or kept if invert is true)
334   *
335   * @param rangeList a string representing the list of attributes. Since
336   * the string will typically come from a user, attributes are indexed from
337   * 1. <br>
338   * eg: first-3,5,6-last
339   * @throws Exception if an invalid range list is supplied
340   */
341  public void setAttributeIndices(String rangeList) throws Exception {
342
343    m_DeltaCols.setRanges(rangeList);
344  }
345
346  /**
347   * Set which attributes are to be deleted (or kept if invert is true)
348   *
349   * @param attributes an array containing indexes of attributes to select.
350   * Since the array will typically come from a program, attributes are indexed
351   * from 0.
352   * @throws Exception if an invalid set of ranges is supplied
353   */
354  public void setAttributeIndicesArray(int [] attributes) throws Exception {
355
356    setAttributeIndices(Range.indicesToRangeList(attributes));
357  }
358 
359  /**
360   * Returns the revision string.
361   *
362   * @return            the revision
363   */
364  public String getRevision() {
365    return RevisionUtils.extract("$Revision: 5987 $");
366  }
367
368  /**
369   * Main method for testing this class.
370   *
371   * @param argv should contain arguments to the filter: use -h for help
372   */
373  public static void main(String [] argv) {
374    runFilter(new FirstOrder(), argv);
375  }
376}
Note: See TracBrowser for help on using the repository browser.