~ubuntu-branches/ubuntu/precise/weka/precise

« back to all changes in this revision

Viewing changes to weka/filters/unsupervised/attribute/PropositionalToMultiInstance.java

  • Committer: Bazaar Package Importer
  • Author(s): Soeren Sonnenburg
  • Date: 2008-02-24 09:18:45 UTC
  • Revision ID: james.westby@ubuntu.com-20080224091845-1l8zy6fm6xipbzsr
Tags: upstream-3.5.7+tut1
ImportĀ upstreamĀ versionĀ 3.5.7+tut1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 * PropositionalToMultiInstance.java
 
19
 * Copyright (C) 2005 University of Waikato, Hamilton, New Zealand
 
20
 *
 
21
 */
 
22
 
 
23
package weka.filters.unsupervised.attribute;
 
24
 
 
25
import weka.core.Attribute;
 
26
import weka.core.Capabilities;
 
27
import weka.core.FastVector;
 
28
import weka.core.Instance;
 
29
import weka.core.Instances;
 
30
import weka.core.Option;
 
31
import weka.core.OptionHandler;
 
32
import weka.core.RelationalLocator;
 
33
import weka.core.StringLocator;
 
34
import weka.core.Utils;
 
35
import weka.core.Capabilities.Capability;
 
36
import weka.filters.Filter;
 
37
import weka.filters.UnsupervisedFilter;
 
38
 
 
39
import java.util.Enumeration;
 
40
import java.util.Random;
 
41
import java.util.Vector;
 
42
 
 
43
/** 
 
44
 <!-- globalinfo-start -->
 
45
 * Converts the propositional instance dataset into multi-instance dataset (with relational attribute). When normalize or standardize a multi-instance dataset, a MIToSingleInstance filter can be applied first to convert the multi-instance dataset into propositional instance dataset. After normalization or standardization, may use this PropositionalToMultiInstance filter to convert the data back to multi-instance format.<br/>
 
46
 * <br/>
 
47
 * Note: the first attribute of the original propositional instance dataset must be a nominal attribute which is expected to be bagId attribute.
 
48
 * <p/>
 
49
 <!-- globalinfo-end -->
 
50
 * 
 
51
 <!-- options-start -->
 
52
 * Valid options are: <p/>
 
53
 * 
 
54
 * <pre> -S &lt;num&gt;
 
55
 *  The seed for the randomization of the order of bags. (default 1)</pre>
 
56
 * 
 
57
 * <pre> -R
 
58
 *  Randomizes the order of the produced bags after the generation. (default off)</pre>
 
59
 * 
 
60
 <!-- options-end -->
 
61
 *
 
62
 * @author Lin Dong (ld21@cs.waikato.ac.nz) 
 
63
 * @version $Revision: 1.6 $
 
64
 * @see MultiInstanceToPropositional
 
65
 */
 
66
public class PropositionalToMultiInstance 
 
67
  extends Filter
 
68
  implements OptionHandler, UnsupervisedFilter {
 
69
 
 
70
  /** for serialization */
 
71
  private static final long serialVersionUID = 5825873573912102482L;
 
72
 
 
73
  /** the seed for randomizing, default is 1 */
 
74
  protected int m_Seed = 1;
 
75
  
 
76
  /** whether to randomize the output data */
 
77
  protected boolean m_Randomize = false;
 
78
 
 
79
  /** Indices of string attributes in the bag */
 
80
  protected StringLocator m_BagStringAtts = null;
 
81
 
 
82
  /** Indices of relational attributes in the bag */
 
83
  protected RelationalLocator m_BagRelAtts = null;
 
84
  
 
85
  /**
 
86
   * Returns a string describing this filter
 
87
   *
 
88
   * @return a description of the filter suitable for
 
89
   * displaying in the explorer/experimenter gui
 
90
   */
 
91
  public String globalInfo() {
 
92
    return  
 
93
        "Converts the propositional instance dataset into multi-instance "
 
94
      + "dataset (with relational attribute). When normalize or standardize a "
 
95
      + "multi-instance dataset, a MIToSingleInstance filter can be applied "
 
96
      + "first to convert the multi-instance dataset into propositional "
 
97
      + "instance dataset. After normalization or standardization, may use "
 
98
      + "this PropositionalToMultiInstance filter to convert the data back to "
 
99
      + "multi-instance format.\n\n"
 
100
      + "Note: the first attribute of the original propositional instance "
 
101
      + "dataset must be a nominal attribute which is expected to be bagId "
 
102
      + "attribute.";
 
103
 
 
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
    Vector result = new Vector();
 
113
  
 
114
    result.addElement(new Option(
 
115
        "\tThe seed for the randomization of the order of bags."
 
116
        + "\t(default 1)",
 
117
        "S", 1, "-S <num>"));
 
118
  
 
119
    result.addElement(new Option(
 
120
        "\tRandomizes the order of the produced bags after the generation."
 
121
        + "\t(default off)",
 
122
        "R", 0, "-R"));
 
123
  
 
124
    return result.elements();
 
125
  }
 
126
 
 
127
 
 
128
  /**
 
129
   * Parses a given list of options. <p/>
 
130
   * 
 
131
   <!-- options-start -->
 
132
   * Valid options are: <p/>
 
133
   * 
 
134
   * <pre> -S &lt;num&gt;
 
135
   *  The seed for the randomization of the order of bags. (default 1)</pre>
 
136
   * 
 
137
   * <pre> -R
 
138
   *  Randomizes the order of the produced bags after the generation. (default off)</pre>
 
139
   * 
 
140
   <!-- options-end -->
 
141
   *
 
142
   * @param options the list of options as an array of strings
 
143
   * @throws Exception if an option is not supported
 
144
   */
 
145
  public void setOptions(String[] options) throws Exception {
 
146
    String        tmpStr;
 
147
    
 
148
    setRandomize(Utils.getFlag('R', options));
 
149
    
 
150
    tmpStr = Utils.getOption('S', options);
 
151
    if (tmpStr.length() != 0)
 
152
      setSeed(Integer.parseInt(tmpStr));
 
153
    else
 
154
      setSeed(1);
 
155
  }
 
156
 
 
157
  /**
 
158
   * Gets the current settings of the classifier.
 
159
   *
 
160
   * @return an array of strings suitable for passing to setOptions
 
161
   */
 
162
  public String [] getOptions() {
 
163
    Vector        result;
 
164
    
 
165
    result = new Vector();
 
166
    
 
167
    result.add("-S");
 
168
    result.add("" + getSeed());
 
169
    
 
170
    if (m_Randomize)
 
171
      result.add("-R");
 
172
 
 
173
    return (String[]) result.toArray(new String[result.size()]);
 
174
  }
 
175
 
 
176
  /**
 
177
   * Returns the tip text for this property
 
178
   *
 
179
   * @return            tip text for this property suitable for
 
180
   *                    displaying in the explorer/experimenter gui
 
181
   */
 
182
  public String seedTipText() {
 
183
    return "The random seed used by the random number generator";
 
184
  }
 
185
 
 
186
  /**
 
187
   * Sets the new seed for randomizing the order of the generated data
 
188
   * 
 
189
   * @param value     the new seed value
 
190
   */
 
191
  public void setSeed(int value) {
 
192
    m_Seed = value;
 
193
  }
 
194
  
 
195
  /**
 
196
   * Returns the current seed value for randomizing the order of the generated
 
197
   * data
 
198
   * 
 
199
   * @return          the current seed value
 
200
   */
 
201
  public int getSeed() {
 
202
    return m_Seed;
 
203
  }
 
204
  
 
205
  /**
 
206
   * Sets whether the order of the generated data is randomized
 
207
   * 
 
208
   * @param value     whether to randomize or not
 
209
   */
 
210
  public void setRandomize(boolean value) {
 
211
    m_Randomize = value;
 
212
  }
 
213
  
 
214
  /**
 
215
   * Gets whether the order of the generated is randomized
 
216
   * 
 
217
   * @return      true if the order is randomized
 
218
   */
 
219
  public boolean getRandomize() {
 
220
    return m_Randomize;
 
221
  }
 
222
 
 
223
  /**
 
224
   * Returns the tip text for this property
 
225
   *
 
226
   * @return tip text for this property suitable for
 
227
   * displaying in the explorer/experimenter gui
 
228
   */
 
229
  public String randomizeTipText() {
 
230
    return "Whether the order of the generated data is randomized.";
 
231
  }
 
232
 
 
233
  /** 
 
234
   * Returns the Capabilities of this filter.
 
235
   *
 
236
   * @return            the capabilities of this object
 
237
   * @see               Capabilities
 
238
   */
 
239
  public Capabilities getCapabilities() {
 
240
    Capabilities result = super.getCapabilities();
 
241
 
 
242
    // attributes
 
243
    result.enable(Capability.NOMINAL_ATTRIBUTES);
 
244
    result.enable(Capability.NUMERIC_ATTRIBUTES);
 
245
    result.enable(Capability.DATE_ATTRIBUTES);
 
246
    result.enable(Capability.STRING_ATTRIBUTES);
 
247
    result.enable(Capability.MISSING_VALUES);
 
248
    
 
249
    // class
 
250
    result.enableAllClasses();
 
251
    result.enable(Capability.MISSING_CLASS_VALUES);
 
252
    result.enable(Capability.NO_CLASS);
 
253
    
 
254
    return result;
 
255
  }
 
256
  
 
257
  /**
 
258
   * Sets the format of the input instances.
 
259
   *
 
260
   * @param instanceInfo an Instances object containing the input 
 
261
   * instance structure (any instances contained in the object are 
 
262
   * ignored - only the structure is required).
 
263
   * @return true if the outputFormat may be collected immediately
 
264
   * @throws Exception if the input format can't be set 
 
265
   * successfully
 
266
   */
 
267
  public boolean setInputFormat(Instances instanceInfo) 
 
268
    throws Exception {
 
269
 
 
270
    if (instanceInfo.attribute(0).type()!= Attribute.NOMINAL) {
 
271
      throw new Exception("The first attribute type of the original propositional instance dataset must be Nominal!");
 
272
    }
 
273
    super.setInputFormat(instanceInfo);
 
274
 
 
275
    /* create a new output format (multi-instance format) */
 
276
    Instances newData = instanceInfo.stringFreeStructure();
 
277
    Attribute attBagIndex = (Attribute) newData.attribute(0).copy();
 
278
    Attribute attClass = (Attribute) newData.classAttribute().copy();
 
279
    // remove the bagIndex attribute
 
280
    newData.deleteAttributeAt(0);
 
281
    // remove the class attribute
 
282
    newData.setClassIndex(-1);
 
283
    newData.deleteAttributeAt(newData.numAttributes() - 1);
 
284
 
 
285
    FastVector attInfo = new FastVector(3); 
 
286
    attInfo.addElement(attBagIndex);
 
287
    attInfo.addElement(new Attribute("bag", newData)); // relation-valued attribute
 
288
    attInfo.addElement(attClass);
 
289
    Instances data = new Instances("Multi-Instance-Dataset", attInfo, 0); 
 
290
    data.setClassIndex(data.numAttributes() - 1);
 
291
 
 
292
    super.setOutputFormat(data.stringFreeStructure());
 
293
 
 
294
    m_BagStringAtts = new StringLocator(data.attribute(1).relation());
 
295
    m_BagRelAtts    = new RelationalLocator(data.attribute(1).relation());
 
296
    
 
297
    return true;
 
298
  }
 
299
 
 
300
  /**
 
301
   * adds a new bag out of the given data and adds it to the output
 
302
   * 
 
303
   * @param input       the intput dataset
 
304
   * @param output      the dataset this bag is added to
 
305
   * @param bagInsts    the instances in this bag
 
306
   * @param bagIndex    the bagIndex of this bag
 
307
   * @param classValue  the associated class value
 
308
   * @param bagWeight   the weight of the bag
 
309
   */
 
310
  protected void addBag(
 
311
      Instances input,
 
312
      Instances output,
 
313
      Instances bagInsts, 
 
314
      int bagIndex, 
 
315
      double classValue, 
 
316
      double bagWeight) {
 
317
    
 
318
    // copy strings/relational values
 
319
    for (int i = 0; i < bagInsts.numInstances(); i++) {
 
320
      RelationalLocator.copyRelationalValues(
 
321
          bagInsts.instance(i), false, 
 
322
          input, m_InputRelAtts,
 
323
          bagInsts, m_BagRelAtts);
 
324
 
 
325
      StringLocator.copyStringValues(
 
326
          bagInsts.instance(i), false, 
 
327
          input, m_InputStringAtts,
 
328
          bagInsts, m_BagStringAtts);
 
329
    }
 
330
    
 
331
    int value = output.attribute(1).addRelation(bagInsts);
 
332
    Instance newBag = new Instance(output.numAttributes());        
 
333
    newBag.setValue(0, bagIndex);
 
334
    newBag.setValue(2, classValue);
 
335
    newBag.setValue(1, value);
 
336
    newBag.setWeight(bagWeight);
 
337
    newBag.setDataset(output);
 
338
    output.add(newBag);
 
339
  }
 
340
 
 
341
  /**
 
342
   * Adds an output instance to the queue. The derived class should use this
 
343
   * method for each output instance it makes available. 
 
344
   *
 
345
   * @param instance the instance to be added to the queue.
 
346
   */
 
347
  protected void push(Instance instance) {
 
348
    if (instance != null) {
 
349
      super.push(instance);
 
350
      // set correct references
 
351
    }
 
352
  }
 
353
  
 
354
  /**
 
355
   * Signify that this batch of input to the filter is finished. 
 
356
   * If the filter requires all instances prior to filtering,
 
357
   * output() may now be called to retrieve the filtered instances.
 
358
   *
 
359
   * @return true if there are instances pending output
 
360
   * @throws IllegalStateException if no input structure has been defined
 
361
   */
 
362
  public boolean batchFinished() {
 
363
 
 
364
    if (getInputFormat() == null) {
 
365
      throw new IllegalStateException("No input instance format defined");
 
366
    }
 
367
 
 
368
    Instances input = getInputFormat();
 
369
    input.sort(0);   // make sure that bagID is sorted
 
370
    Instances output = getOutputFormat();
 
371
    Instances bagInsts = output.attribute(1).relation();
 
372
    Instance inst = new Instance(bagInsts.numAttributes());
 
373
    inst.setDataset(bagInsts);
 
374
 
 
375
    double bagIndex   = input.instance(0).value(0);
 
376
    double classValue = input.instance(0).classValue(); 
 
377
    double bagWeight  = 0.0;
 
378
 
 
379
    // Convert pending input instances
 
380
    for(int i = 0; i < input.numInstances(); i++) {
 
381
      double currentBagIndex = input.instance(i).value(0);
 
382
 
 
383
      // copy the propositional instance value, except the bagIndex and the class value
 
384
      for (int j = 0; j < input.numAttributes() - 2; j++) 
 
385
        inst.setValue(j, input.instance(i).value(j + 1));
 
386
      inst.setWeight(input.instance(i).weight());
 
387
 
 
388
      if (currentBagIndex == bagIndex){
 
389
        bagInsts.add(inst);
 
390
        bagWeight += inst.weight();
 
391
      }
 
392
      else{
 
393
        addBag(input, output, bagInsts, (int) bagIndex, classValue, bagWeight);
 
394
 
 
395
        bagInsts   = bagInsts.stringFreeStructure();  
 
396
        bagInsts.add(inst);
 
397
        bagIndex   = currentBagIndex;
 
398
        classValue = input.instance(i).classValue();
 
399
        bagWeight  = inst.weight();
 
400
      }
 
401
    }
 
402
 
 
403
    // reach the last instance, create and add the last bag
 
404
    addBag(input, output, bagInsts, (int) bagIndex, classValue, bagWeight);
 
405
 
 
406
    if (getRandomize())
 
407
      output.randomize(new Random(getSeed()));
 
408
    
 
409
    for (int i = 0; i < output.numInstances(); i++)
 
410
      push(output.instance(i));
 
411
    
 
412
    // Free memory
 
413
    flushInput();
 
414
 
 
415
    m_NewBatch = true;
 
416
    m_FirstBatchDone = true;
 
417
    
 
418
    return (numPendingOutput() != 0);
 
419
  }
 
420
 
 
421
  /**
 
422
   * Main method for running this filter.
 
423
   *
 
424
   * @param args should contain arguments to the filter: 
 
425
   * use -h for help
 
426
   */
 
427
  public static void main(String[] args) {
 
428
    runFilter(new PropositionalToMultiInstance(), args);
 
429
  }
 
430
}