source: branches/MetisMQI/src/main/java/weka/filters/unsupervised/attribute/AddExpression.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.7 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 *    AddExpression.java
19 *    Copyright (C) 2000 University of Waikato, Hamilton, New Zealand
20 *
21 */
22
23package weka.filters.unsupervised.attribute;
24
25import weka.core.Attribute;
26import weka.core.AttributeExpression;
27import weka.core.Capabilities;
28import weka.core.Instance; 
29import weka.core.DenseInstance;
30import weka.core.Instances;
31import weka.core.Option;
32import weka.core.OptionHandler;
33import weka.core.RevisionUtils;
34import weka.core.SparseInstance;
35import weka.core.Utils;
36import weka.core.Capabilities.Capability;
37import weka.filters.Filter;
38import weka.filters.StreamableFilter;
39import weka.filters.UnsupervisedFilter;
40
41import java.util.Enumeration;
42import java.util.Vector;
43
44/**
45 <!-- globalinfo-start -->
46 * An instance filter that creates a new attribute by applying a mathematical expression to existing attributes. The expression can contain attribute references and numeric constants. Supported operators are :<br/>
47 * +, -, *, /, ^, log, abs, cos, exp, sqrt, floor, ceil, rint, tan, sin, (, )<br/>
48 * Attributes are specified by prefixing with 'a', eg. a7 is attribute number 7 (starting from 1).<br/>
49 * Example expression : a1^2*a5/log(a7*4.0).
50 * <p/>
51 <!-- globalinfo-end -->
52 *
53 <!-- options-start -->
54 * Valid options are: <p/>
55 *
56 * <pre> -E &lt;expression&gt;
57 *  Specify the expression to apply. Eg a1^2*a5/log(a7*4.0).
58 *  Supported opperators: ,+, -, *, /, ^, log, abs, cos,
59 *  exp, sqrt, floor, ceil, rint, tan, sin, (, )
60 *  (default: a1^2)</pre>
61 *
62 * <pre> -N &lt;name&gt;
63 *  Specify the name for the new attribute. (default is the expression provided with -E)</pre>
64 *
65 * <pre> -D
66 *  Debug. Names attribute with the postfix parse of the expression.</pre>
67 *
68 <!-- options-end -->
69 *
70 * @author Mark Hall (mhall@cs.waikato.ac.nz)
71 * @version $Revision: 5987 $
72 */
73public class AddExpression 
74  extends Filter
75  implements UnsupervisedFilter, StreamableFilter, OptionHandler {
76
77  /** for serialization */
78  static final long serialVersionUID = 402130384261736245L;
79 
80  /** The infix expression */
81  private String m_infixExpression = "a1^2";
82
83  /** Name of the new attribute. "expression"  length string will use the
84      provided expression as the new attribute name */
85  private String m_attributeName="expression";
86
87  /** If true, makes the attribute name equal to the postfix parse of the
88      expression */
89  private boolean m_Debug = false;
90
91  private AttributeExpression m_attributeExpression = null;
92
93  /**
94   * Returns a string describing this filter
95   *
96   * @return            a description of the filter suitable for
97   *                    displaying in the explorer/experimenter gui
98   */
99  public String globalInfo() {
100    return 
101        "An instance filter that creates a new attribute by applying a "
102      + "mathematical expression to existing attributes. The expression "
103      + "can contain attribute references and numeric constants. Supported "
104      + "operators are :\n"
105      + "+, -, *, /, ^, log, abs, cos, exp, sqrt, floor, ceil, rint, tan, "
106      + "sin, (, )\n"
107      + "Attributes are specified by prefixing with 'a', eg. a7 is "
108      + "attribute number 7 (starting from 1).\n"
109      + "Example expression : a1^2*a5/log(a7*4.0).";
110  }
111 
112  /**
113   * Returns an enumeration describing the available options.
114   *
115   * @return an enumeration of all the available options.
116   */
117  public Enumeration listOptions() {
118
119    Vector newVector = new Vector(3); 
120
121    newVector.addElement(new Option(
122             "\tSpecify the expression to apply. Eg a1^2*a5/log(a7*4.0)."
123             +"\n\tSupported opperators: ,+, -, *, /, ^, log, abs, cos, "
124             +"\n\texp, sqrt, floor, ceil, rint, tan, sin, (, )"
125             +"\n\t(default: a1^2)",
126             "E",1,"-E <expression>"));
127
128    newVector.addElement(new Option(
129             "\tSpecify the name for the new attribute. (default is the "
130             +"expression provided with -E)",
131             "N",1,"-N <name>"));
132
133    newVector.addElement(new Option(
134             "\tDebug. Names attribute with the postfix parse of the "
135             +"expression.","D",0,"-D"));
136
137    return newVector.elements();
138  }
139
140  /**
141   * Parses a given list of options. <p/>
142   *
143   <!-- options-start -->
144   * Valid options are: <p/>
145   *
146   * <pre> -E &lt;expression&gt;
147   *  Specify the expression to apply. Eg a1^2*a5/log(a7*4.0).
148   *  Supported opperators: ,+, -, *, /, ^, log, abs, cos,
149   *  exp, sqrt, floor, ceil, rint, tan, sin, (, )
150   *  (default: a1^2)</pre>
151   *
152   * <pre> -N &lt;name&gt;
153   *  Specify the name for the new attribute. (default is the expression provided with -E)</pre>
154   *
155   * <pre> -D
156   *  Debug. Names attribute with the postfix parse of the expression.</pre>
157   *
158   <!-- options-end -->
159   *
160   * @param options the list of options as an array of strings
161   * @throws Exception if an option is not supported
162   */
163  public void setOptions(String[] options) throws Exception {
164    String expString = Utils.getOption('E', options);
165    if (expString.length() != 0) {
166      setExpression(expString);
167    } else {
168      setExpression("a1^2");
169    }
170
171    String name = Utils.getOption('N',options);
172    if (name.length() != 0) {
173      setName(name);
174    }
175
176    setDebug(Utils.getFlag('D', options));
177  }
178 
179  /**
180   * Gets the current settings of the filter.
181   *
182   * @return an array of strings suitable for passing to setOptions
183   */
184  public String [] getOptions() {
185
186    String [] options = new String [5];
187    int current = 0;
188   
189    options[current++] = "-E"; options[current++] = getExpression();
190    options[current++] = "-N"; options[current++] = getName();
191
192    if (getDebug()) {
193      options[current++] = "-D";
194    }
195   
196    while (current < options.length) {
197      options[current++] = "";
198    }
199    return options;
200  }
201
202  /**
203   * Returns the tip text for this property
204   *
205   * @return tip text for this property suitable for
206   * displaying in the explorer/experimenter gui
207   */
208  public String nameTipText() {
209    return "Set the name of the new attribute.";
210  }
211
212  /**
213   * Set the name for the new attribute. The string "expression" can
214   * be used to make the name of the new attribute equal to the expression
215   * provided.
216   * @param name the name of the new attribute
217   */
218  public void setName(String name) {
219    m_attributeName = name;
220  }
221
222  /**
223   * Returns the name of the new attribute
224   * @return the name of the new attribute
225   */
226  public String getName() {
227    return m_attributeName;
228  }
229
230  /**
231   * Returns the tip text for this property
232   *
233   * @return tip text for this property suitable for
234   * displaying in the explorer/experimenter gui
235   */
236  public String debugTipText() {
237    return "Set debug mode. If true then the new attribute will be named with "
238      +"the postfix parse of the supplied expression.";
239  }
240 
241  /**
242   * Set debug mode. Causes the new attribute to be named with the postfix
243   * parse of the expression
244   * @param d true if debug mode is to be used
245   */
246  public void setDebug(boolean d) {
247    m_Debug = d;
248  }
249
250  /**
251   * Gets whether debug is set
252   * @return true if debug is set
253   */
254  public boolean getDebug() {
255    return m_Debug;
256  }
257
258  /**
259   * Returns the tip text for this property
260   *
261   * @return tip text for this property suitable for
262   * displaying in the explorer/experimenter gui
263   */
264  public String expressionTipText() {
265    return "Set the math expression to apply. Eg. a1^2*a5/log(a7*4.0)";
266  }
267
268  /**
269   * Set the expression to apply
270   * @param expr a mathematical expression to apply
271   */
272  public void setExpression(String expr) {
273    m_infixExpression = expr;
274  }
275
276  /**
277   * Get the expression
278   * @return the expression
279   */
280  public String getExpression() {
281    return m_infixExpression;
282  }
283
284  /**
285   * Returns the Capabilities of this filter.
286   *
287   * @return            the capabilities of this object
288   * @see               Capabilities
289   */
290  public Capabilities getCapabilities() {
291    Capabilities result = super.getCapabilities();
292    result.disableAll();
293
294    // attributes
295    result.enableAllAttributes();
296    result.enable(Capability.MISSING_VALUES);
297   
298    // class
299    result.enableAllClasses();
300    result.enable(Capability.MISSING_CLASS_VALUES);
301    result.enable(Capability.NO_CLASS);
302   
303    return result;
304  }
305
306  /**
307   * Sets the format of the input instances.
308   *
309   * @param instanceInfo an Instances object containing the input instance
310   * structure (any instances contained in the object are ignored - only the
311   * structure is required).
312   * @return true if the outputFormat may be collected immediately
313   * @throws Exception if the format couldn't be set successfully
314   */
315  public boolean setInputFormat(Instances instanceInfo) throws Exception {
316
317    m_attributeExpression = new AttributeExpression();
318    m_attributeExpression.
319      convertInfixToPostfix(new String(m_infixExpression));
320
321    super.setInputFormat(instanceInfo);
322
323    Instances outputFormat = new Instances(instanceInfo, 0);
324    Attribute newAttribute;
325    if (m_Debug) {
326      newAttribute = 
327        new Attribute(m_attributeExpression.getPostFixExpression());
328    } else if (m_attributeName.compareTo("expression") != 0) {
329      newAttribute = new Attribute(m_attributeName);
330    } else {
331      newAttribute = new Attribute(m_infixExpression);
332    }
333    outputFormat.insertAttributeAt(newAttribute, 
334                                   instanceInfo.numAttributes());
335    setOutputFormat(outputFormat);
336    return true;
337  }
338
339  /**
340   * Input an instance for filtering. Ordinarily the instance is processed
341   * and made available for output immediately. Some filters require all
342   * instances be read before producing output.
343   *
344   * @param instance the input instance
345   * @return true if the filtered instance may now be
346   * collected with output().
347   * @throws IllegalStateException if no input format has been defined.
348   * @throws Exception if there was a problem during the filtering.
349   */
350  public boolean input(Instance instance) throws Exception {
351
352    if (getInputFormat() == null) {
353      throw new IllegalStateException("No input instance format defined");
354    }
355    if (m_NewBatch) {
356      resetQueue();
357      m_NewBatch = false;
358    }
359
360    double[] vals = new double[instance.numAttributes()+1];
361    for(int i = 0; i < instance.numAttributes(); i++) {
362      if (instance.isMissing(i)) {
363        vals[i] = Utils.missingValue();
364      } else {
365        vals[i] = instance.value(i);
366      }
367    }
368
369    m_attributeExpression.evaluateExpression(vals);
370
371    Instance inst = null;
372    if (instance instanceof SparseInstance) {
373      inst = new SparseInstance(instance.weight(), vals);
374    } else {
375      inst = new DenseInstance(instance.weight(), vals);
376    }
377
378    inst.setDataset(getOutputFormat());
379    copyValues(inst, false, instance.dataset(), getOutputFormat());
380    inst.setDataset(getOutputFormat());
381    push(inst);
382    return true;
383  }
384 
385  /**
386   * Returns the revision string.
387   *
388   * @return            the revision
389   */
390  public String getRevision() {
391    return RevisionUtils.extract("$Revision: 5987 $");
392  }
393 
394  /**
395   * Main method for testing this class.
396   *
397   * @param args should contain arguments to the filter: use -h for help
398   */
399  public static void main(String [] args) {
400    runFilter(new AddExpression(), args);
401  }
402}
Note: See TracBrowser for help on using the repository browser.