source: branches/MetisMQI/src/main/java/weka/filters/unsupervised/attribute/NumericTransform.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: 12.9 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 *    NumericTransform.java
19 *    Copyright (C) 1999 University of Waikato, Hamilton, New Zealand
20 *
21 */
22
23package weka.filters.unsupervised.attribute;
24
25import weka.core.Capabilities;
26import weka.core.Instance; 
27import weka.core.DenseInstance;
28import weka.core.Instances;
29import weka.core.Option;
30import weka.core.OptionHandler;
31import weka.core.Range;
32import weka.core.RevisionUtils;
33import weka.core.SparseInstance;
34import weka.core.Utils;
35import weka.core.Capabilities.Capability;
36import weka.filters.Filter;
37import weka.filters.StreamableFilter;
38import weka.filters.UnsupervisedFilter;
39
40import java.lang.reflect.InvocationTargetException;
41import java.lang.reflect.Method;
42import java.util.Enumeration;
43import java.util.Vector;
44
45/**
46 <!-- globalinfo-start -->
47 * Transforms numeric attributes using a given transformation method.
48 * <p/>
49 <!-- globalinfo-end -->
50 *
51 <!-- options-start -->
52 * Valid options are: <p/>
53 *
54 * <pre> -R &lt;index1,index2-index4,...&gt;
55 *  Specify list of columns to transform. First and last are
56 *  valid indexes (default none). Non-numeric columns are
57 *  skipped.</pre>
58 *
59 * <pre> -V
60 *  Invert matching sense.</pre>
61 *
62 * <pre> -C &lt;string&gt;
63 *  Sets the class containing transformation method.
64 *  (default java.lang.Math)</pre>
65 *
66 * <pre> -M &lt;string&gt;
67 *  Sets the method. (default abs)</pre>
68 *
69 <!-- options-end -->
70 *
71 * @author Eibe Frank (eibe@cs.waikato.ac.nz)
72 * @version $Revision: 5987 $
73 */
74public class NumericTransform 
75  extends Filter
76  implements UnsupervisedFilter, StreamableFilter, OptionHandler {
77 
78  /** for serialization */
79  static final long serialVersionUID = -8561413333351366934L;
80
81  /** Stores which columns to transform. */
82  private Range m_Cols = new Range();
83
84  /** Class containing transformation method. */
85  private String m_Class;
86
87  /** Transformation method. */
88  private String m_Method;
89
90  /**
91   * Returns a string describing this filter
92   *
93   * @return a description of the filter suitable for
94   * displaying in the explorer/experimenter gui
95   */
96  public String globalInfo() {
97
98    return "Transforms numeric attributes using a given transformation method.";
99  }
100
101  /**
102   * Default constructor -- sets the default transform method
103   * to java.lang.Math.abs().
104   */
105  public NumericTransform() {
106
107    m_Class = "java.lang.Math";
108    m_Method = "abs";
109  }
110
111  /**
112   * Returns the Capabilities of this filter.
113   *
114   * @return            the capabilities of this object
115   * @see               Capabilities
116   */
117  public Capabilities getCapabilities() {
118    Capabilities result = super.getCapabilities();
119    result.disableAll();
120
121    // attributes
122    result.enableAllAttributes();
123    result.enable(Capability.MISSING_VALUES);
124   
125    // class
126    result.enableAllClasses();
127    result.enable(Capability.MISSING_CLASS_VALUES);
128    result.enable(Capability.NO_CLASS);
129   
130    return result;
131  }
132
133  /**
134   * Sets the format of the input instances.
135   *
136   * @param instanceInfo an Instances object containing the input
137   * instance structure (any instances contained in the object are
138   * ignored - only the structure is required).
139   * @return true if the outputFormat may be collected immediately
140   * @throws Exception if the input format can't be set
141   * successfully
142   */
143  public boolean setInputFormat(Instances instanceInfo) 
144       throws Exception {
145
146    if (m_Class == null) {
147      throw new IllegalStateException("No class has been set.");
148    }
149    if (m_Method == null) {
150      throw new IllegalStateException("No method has been set.");
151    }
152    super.setInputFormat(instanceInfo);
153    m_Cols.setUpper(instanceInfo.numAttributes() - 1);
154    setOutputFormat(instanceInfo);
155    return true;
156  }
157
158  /**
159   * Input an instance for filtering. The instance is processed
160   * and made available for output immediately.
161   *
162   * @param instance the input instance
163   * @return true if the filtered instance may now be
164   * collected with output().
165   * @throws IllegalStateException if no input format has been set.
166   * @throws InvocationTargetException if there is a problem applying
167   * the configured transform method.
168   */
169  public boolean input(Instance instance) throws Exception {
170
171    if (getInputFormat() == null) {
172      throw new IllegalStateException("No input instance format defined");
173    }
174    if (m_NewBatch) {
175      resetQueue();
176      m_NewBatch = false;
177    }
178
179    Method m = (Class.forName(m_Class)).getMethod(m_Method, new Class[] {Double.TYPE});
180
181    double []vals = new double[instance.numAttributes()];
182    Double []params = new Double[1];
183    Double newVal;
184    for(int i = 0; i < instance.numAttributes(); i++) {
185      if (instance.isMissing(i)) {
186        vals[i] = Utils.missingValue();
187      } else {
188        if (m_Cols.isInRange(i) &&
189            instance.attribute(i).isNumeric()) {
190          params[0] = new Double(instance.value(i));
191          newVal = (Double) m.invoke(null, (Object[])params);
192          if (newVal.isNaN() || newVal.isInfinite()) {
193            vals[i] = Utils.missingValue();
194          } else {
195            vals[i] = newVal.doubleValue(); 
196          }
197        } else {
198          vals[i] = instance.value(i);
199        }
200      }
201    }
202    Instance inst = null;
203    if (instance instanceof SparseInstance) {
204      inst = new SparseInstance(instance.weight(), vals);
205    } else {
206      inst = new DenseInstance(instance.weight(), vals);
207    }
208    inst.setDataset(instance.dataset());
209    push(inst);
210    return true;
211  }
212
213  /**
214   * Returns an enumeration describing the available options.
215   *
216   * @return an enumeration of all the available options.
217   */
218  public Enumeration listOptions() {
219
220    Vector newVector = new Vector(4);
221
222    newVector.addElement(new Option(
223              "\tSpecify list of columns to transform. First and last are\n"
224              + "\tvalid indexes (default none). Non-numeric columns are \n"
225              + "\tskipped.",
226              "R", 1, "-R <index1,index2-index4,...>"));
227
228    newVector.addElement(new Option(
229              "\tInvert matching sense.",
230              "V", 0, "-V"));
231
232    newVector.addElement(new Option(
233              "\tSets the class containing transformation method.\n"+
234              "\t(default java.lang.Math)",
235              "C", 1, "-C <string>"));
236
237    newVector.addElement(new Option(
238              "\tSets the method. (default abs)",
239              "M", 1, "-M <string>"));
240
241    return newVector.elements();
242  }
243
244
245  /**
246   * Parses a given list of options. <p/>
247   *
248   <!-- options-start -->
249   * Valid options are: <p/>
250   *
251   * <pre> -R &lt;index1,index2-index4,...&gt;
252   *  Specify list of columns to transform. First and last are
253   *  valid indexes (default none). Non-numeric columns are
254   *  skipped.</pre>
255   *
256   * <pre> -V
257   *  Invert matching sense.</pre>
258   *
259   * <pre> -C &lt;string&gt;
260   *  Sets the class containing transformation method.
261   *  (default java.lang.Math)</pre>
262   *
263   * <pre> -M &lt;string&gt;
264   *  Sets the method. (default abs)</pre>
265   *
266   <!-- options-end -->
267   *
268   * @param options the list of options as an array of strings
269   * @throws Exception if an option is not supported
270   */
271  public void setOptions(String[] options) throws Exception {
272   
273    setAttributeIndices(Utils.getOption('R', options));
274    setInvertSelection(Utils.getFlag('V', options));
275    String classString = Utils.getOption('C', options);
276    if (classString.length() != 0) {
277      setClassName(classString);
278    }
279    String methodString = Utils.getOption('M', options);
280    if (methodString.length() != 0) {
281      setMethodName(methodString);
282    }
283
284    if (getInputFormat() != null) {
285      setInputFormat(getInputFormat());
286    }
287  }
288
289  /**
290   * Gets the current settings of the filter.
291   *
292   * @return an array of strings suitable for passing to setOptions
293   */
294  public String [] getOptions() {
295
296    String [] options = new String [7];
297    int current = 0;
298
299    if (getInvertSelection()) {
300      options[current++] = "-V";
301    }
302    if (!getAttributeIndices().equals("")) {
303      options[current++] = "-R"; options[current++] = getAttributeIndices();
304    }
305    if (m_Class != null) {
306      options[current++] = "-C"; options[current++] = getClassName();
307    }
308    if (m_Method != null) {
309      options[current++] = "-M"; options[current++] = getMethodName();
310    }
311
312    while (current < options.length) {
313      options[current++] = "";
314    }
315    return options;
316  }
317
318  /**
319   * Returns the tip text for this property
320   *
321   * @return tip text for this property suitable for
322   * displaying in the explorer/experimenter gui
323   */
324  public String classNameTipText() {
325    return "Name of the class containing the method used for the transformation.";
326  }
327
328  /**
329   * Get the class containing the transformation method.
330   *
331   * @return string describing the class
332   */
333  public String getClassName() {
334
335    return m_Class;
336  }
337 
338  /**
339   * Sets the class containing the transformation method.
340   *
341   * @param name the name of the class
342   * @throws ClassNotFoundException if class can't be found
343   */
344  public void setClassName(String name) throws ClassNotFoundException {
345 
346    m_Class = name;
347  }
348
349  /**
350   * Returns the tip text for this property
351   *
352   * @return tip text for this property suitable for
353   * displaying in the explorer/experimenter gui
354   */
355  public String methodNameTipText() {
356    return "Name of the method used for the transformation.";
357  }
358 
359  /**
360   * Get the transformation method.
361   *
362   * @return string describing the transformation method.
363   */
364  public String getMethodName() {
365
366    return m_Method;
367  }
368
369  /**
370   * Set the transformation method.
371   *
372   * @param name the name of the method
373   * @throws NoSuchMethodException if method can't be found in class
374   */
375  public void setMethodName(String name) throws NoSuchMethodException {
376
377    m_Method = name;
378  }
379
380  /**
381   * Returns the tip text for this property
382   *
383   * @return tip text for this property suitable for
384   * displaying in the explorer/experimenter gui
385   */
386  public String invertSelectionTipText() {
387    return "Whether to process the inverse of the given attribute ranges.";
388  }
389
390  /**
391   * Get whether the supplied columns are to be transformed or not
392   *
393   * @return true if the supplied columns will be kept
394   */
395  public boolean getInvertSelection() {
396
397    return m_Cols.getInvert();
398  }
399
400  /**
401   * Set whether selected columns should be transformed or not.
402   *
403   * @param invert the new invert setting
404   */
405  public void setInvertSelection(boolean invert) {
406
407    m_Cols.setInvert(invert);
408  }
409
410  /**
411   * Returns the tip text for this property
412   *
413   * @return tip text for this property suitable for
414   * displaying in the explorer/experimenter gui
415   */
416  public String attributeIndicesTipText() {
417    return "Specify range of attributes to act on."
418      + " This is a comma separated list of attribute indices, with"
419      + " \"first\" and \"last\" valid values. Specify an inclusive"
420      + " range with \"-\". E.g: \"first-3,5,6-10,last\".";
421  }
422
423  /**
424   * Get the current range selection
425   *
426   * @return a string containing a comma separated list of ranges
427   */
428  public String getAttributeIndices() {
429
430    return m_Cols.getRanges();
431  }
432
433  /**
434   * Set which attributes are to be transformed (or kept if invert is true).
435   *
436   * @param rangeList a string representing the list of attributes. Since
437   * the string will typically come from a user, attributes are indexed from
438   * 1. <br> eg:
439   * first-3,5,6-last
440   * @throws InvalidArgumentException if an invalid range list is supplied
441   */
442
443  public void setAttributeIndices(String rangeList) {
444
445    m_Cols.setRanges(rangeList);
446  }
447
448  /**
449   * Set which attributes are to be transformed (or kept if invert is true)
450   *
451   * @param attributes an array containing indexes of attributes to select.
452   * Since the array will typically come from a program, attributes are indexed
453   * from 0.
454   * @throws InvalidArgumentException if an invalid set of ranges is supplied
455   */
456  public void setAttributeIndicesArray(int [] attributes) {
457
458    setAttributeIndices(Range.indicesToRangeList(attributes));
459  }
460 
461  /**
462   * Returns the revision string.
463   *
464   * @return            the revision
465   */
466  public String getRevision() {
467    return RevisionUtils.extract("$Revision: 5987 $");
468  }
469
470  /**
471   * Main method for testing this class.
472   *
473   * @param argv should contain arguments to the filter: use -h for help
474   */
475  public static void main(String [] argv) {
476    runFilter(new NumericTransform(), argv);
477  }
478}
Note: See TracBrowser for help on using the repository browser.