~ubuntu-branches/ubuntu/oneiric/weka/oneiric

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Torsten Werner, Soeren Sonnenburg, Torsten Werner
  • Date: 2008-08-10 21:27:05 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20080810212705-tr8etpnkdx2ziktp
Tags: 3.5.8-1
[ Soeren Sonnenburg ]
* Bump Standards Version to 3.8.0.
* Remove references to non-free Java in debian/copyright.

[ Torsten Werner ]
* new upstream release
* Switch to openjdk-6.
* Move package to main.

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
import weka.core.Option;
31
31
import weka.core.OptionHandler;
32
32
import weka.core.Range;
 
33
import weka.core.RevisionHandler;
 
34
import weka.core.RevisionUtils;
33
35
import weka.core.SelectedTag;
34
36
import weka.core.SparseInstance;
35
37
import weka.core.Stopwords;
38
40
import weka.core.Capabilities.Capability;
39
41
import weka.core.stemmers.NullStemmer;
40
42
import weka.core.stemmers.Stemmer;
 
43
import weka.core.tokenizers.Tokenizer;
41
44
import weka.core.tokenizers.WordTokenizer;
42
 
import weka.core.tokenizers.Tokenizer;
43
45
import weka.filters.Filter;
44
46
import weka.filters.UnsupervisedFilter;
45
47
 
80
82
 *  Surplus words will be discarded..
81
83
 *  (default: 1000)</pre>
82
84
 * 
 
85
 * <pre> -prune-rate &lt;rate as a percentage of dataset&gt;
 
86
 *  Specify the rate (e.g., every 10% of the input dataset) at which to periodically prune the dictionary.
 
87
 *  -W prunes after creating a full dictionary. You may not have enough memory for this approach.
 
88
 *  (default: no periodic pruning)</pre>
 
89
 * 
83
90
 * <pre> -T
84
91
 *  Transform the word frequencies into log(1+fij)
85
92
 *  where fij is the frequency of word i in jth document(instance).
129
136
 * @author Stuart Inglis (stuart@reeltwo.com)
130
137
 * @author Gordon Paynter (gordon.paynter@ucr.edu)
131
138
 * @author Asrhaf M. Kibriya (amk14@cs.waikato.ac.nz)
132
 
 * @version $Revision: 1.20 $ 
 
139
 * @version $Revision: 1.25 $ 
133
140
 * @see Stopwords
134
141
 */
135
142
public class StringToWordVector 
136
143
  extends Filter
137
144
  implements UnsupervisedFilter, OptionHandler {
138
145
 
139
 
  /** for serialization */
 
146
  /** for serialization. */
140
147
  static final long serialVersionUID = 8249106275278565424L;
141
148
 
142
 
  /** Range of columns to convert to word vectors */
 
149
  /** Range of columns to convert to word vectors. */
143
150
  protected Range m_SelectedRange = new Range("first-last");
144
151
 
145
 
  /** Contains a mapping of valid words to attribute indexes */
 
152
  /** Contains a mapping of valid words to attribute indexes. */
146
153
  private TreeMap m_Dictionary = new TreeMap();
147
154
 
148
155
  /** True if output instances should contain word frequency rather than boolean 0 or 1. */
149
156
  private boolean m_OutputCounts = false;
150
157
 
151
 
  /** A String prefix for the attribute names */
 
158
  /** A String prefix for the attribute names. */
152
159
  private String m_Prefix = "";
153
 
  
 
160
 
154
161
  /** Contains the number of documents (instances) a particular word appears in.
155
 
      The counts are stored with the same indexing as given by m_Dictionary.  */
 
162
          The counts are stored with the same indexing as given by m_Dictionary.  */
156
163
  private int [] m_DocsCounts;
157
 
  
 
164
 
158
165
  /** Contains the number of documents (instances) in the input format from 
159
 
      which the dictionary is created. It is used in IDF transform. */
 
166
          which the dictionary is created. It is used in IDF transform. */
160
167
  private int m_NumInstances = -1;
161
168
 
162
169
  /**
165
172
   * documents which will be normalized to average document length.
166
173
   */
167
174
  private double m_AvgDocLength = -1;
168
 
  
 
175
 
169
176
  /**
170
177
   * The default number of words (per class if there is a class attribute
171
178
   * assigned) to attempt to keep.
172
179
   */
173
180
  private int m_WordsToKeep = 1000;
174
181
 
 
182
  /**
 
183
   * The percentage at which to periodically prune the dictionary.
 
184
   */
 
185
  private double m_PeriodicPruningRate = -1;
 
186
 
175
187
  /** True if word frequencies should be transformed into log(1+fi) 
176
 
      where fi is the frequency of word i
 
188
          where fi is the frequency of word i.
177
189
   */
178
190
  private boolean m_TFTransform;
179
191
 
180
192
  /** The normalization to apply. */
181
193
  protected int m_filterType = FILTER_NONE;
182
 
  
183
 
  /** normalization: No normalization */
 
194
 
 
195
  /** normalization: No normalization. */
184
196
  public static final int FILTER_NONE = 0;
185
 
  /** normalization: Normalize all data */
 
197
  /** normalization: Normalize all data. */
186
198
  public static final int FILTER_NORMALIZE_ALL = 1;
187
 
  /** normalization: Normalize test data only */
 
199
  /** normalization: Normalize test data only. */
188
200
  public static final int FILTER_NORMALIZE_TEST_ONLY = 2;
189
201
 
190
202
  /** Specifies whether document's (instance's) word frequencies are
197
209
  };
198
210
 
199
211
  /** True if word frequencies should be transformed into 
200
 
     fij*log(numOfDocs/numOfDocsWithWordi) */
 
212
          fij*log(numOfDocs/numOfDocsWithWordi). */
201
213
  private boolean m_IDFTransform;
202
 
  
203
 
  /** True if all tokens should be downcased */
 
214
 
 
215
  /** True if all tokens should be downcased. */
204
216
  private boolean m_lowerCaseTokens;
205
 
  
 
217
 
206
218
  /** True if tokens that are on a stoplist are to be ignored. */
207
219
  private boolean m_useStoplist;  
208
220
 
209
 
  /** the stemming algorithm */
 
221
  /** the stemming algorithm. */
210
222
  private Stemmer m_Stemmer = new NullStemmer();
211
223
 
212
 
  /** the minimum (per-class) word frequency */
 
224
  /** the minimum (per-class) word frequency. */
213
225
  private int m_minTermFreq = 1;
214
 
  
215
 
  /** whether to operate on a per-class basis */
 
226
 
 
227
  /** whether to operate on a per-class basis. */
216
228
  private boolean m_doNotOperateOnPerClassBasis = false;
217
229
 
218
230
  /** a file containing stopwords for using others than the default Rainbow 
219
 
   * ones */
 
231
   * ones. */
220
232
  private File m_Stopwords = new File(System.getProperty("user.dir"));
221
233
 
222
 
  /** the tokenizer algorithm to use */
 
234
  /** the tokenizer algorithm to use. */
223
235
  private Tokenizer m_Tokenizer = new WordTokenizer();
224
236
 
225
237
  /**
227
239
   */
228
240
  public StringToWordVector() {
229
241
  }
230
 
  
 
242
 
231
243
  /**
232
 
   * Returns an enumeration describing the available options
 
244
   * Returns an enumeration describing the available options.
233
245
   *
234
246
   * @return an enumeration of all the available options
235
247
   */
261
273
        "W", 1, "-W <number of words to keep>"));
262
274
 
263
275
    result.addElement(new Option(
 
276
        "\tSpecify the rate (e.g., every 10% of the input dataset) at which to periodically prune the dictionary.\n"
 
277
        + "\t-W prunes after creating a full dictionary. You may not have enough memory for this approach.\n"
 
278
        + "\t(default: no periodic pruning)",
 
279
        "prune-rate", 1, "-prune-rate <rate as a percentage of dataset>"));
 
280
 
 
281
    result.addElement(new Option(
264
282
        "\tTransform the word frequencies into log(1+fij)\n"+
265
283
        "\twhere fij is the frequency of word i in jth document(instance).\n",
266
284
        "T", 0, "-T"));
320
338
  /**
321
339
   * Parses a given list of options. <p/>
322
340
   * 
323
 
   <!-- options-start -->
324
 
   * Valid options are: <p/>
325
 
   * 
326
 
   * <pre> -C
327
 
   *  Output word counts rather than boolean word presence.
328
 
   * </pre>
329
 
   * 
330
 
   * <pre> -R &lt;index1,index2-index4,...&gt;
331
 
   *  Specify list of string attributes to convert to words (as weka Range).
332
 
   *  (default: select all string attributes)</pre>
333
 
   * 
334
 
   * <pre> -V
335
 
   *  Invert matching sense of column indexes.</pre>
336
 
   * 
337
 
   * <pre> -P &lt;attribute name prefix&gt;
338
 
   *  Specify a prefix for the created attribute names.
339
 
   *  (default: "")</pre>
340
 
   * 
341
 
   * <pre> -W &lt;number of words to keep&gt;
342
 
   *  Specify approximate number of word fields to create.
343
 
   *  Surplus words will be discarded..
344
 
   *  (default: 1000)</pre>
345
 
   * 
346
 
   * <pre> -T
347
 
   *  Transform the word frequencies into log(1+fij)
348
 
   *  where fij is the frequency of word i in jth document(instance).
349
 
   * </pre>
350
 
   * 
351
 
   * <pre> -I
352
 
   *  Transform each word frequency into:
353
 
   *  fij*log(num of Documents/num of documents containing word i)
354
 
   *    where fij if frequency of word i in jth document(instance)</pre>
355
 
   * 
356
 
   * <pre> -N
357
 
   *  Whether to 0=not normalize/1=normalize all data/2=normalize test data only
358
 
   *  to average length of training documents (default 0=don't normalize).</pre>
359
 
   * 
360
 
   * <pre> -L
361
 
   *  Convert all tokens to lowercase before adding to the dictionary.</pre>
362
 
   * 
363
 
   * <pre> -S
364
 
   *  Ignore words that are in the stoplist.</pre>
365
 
   * 
366
 
   * <pre> -stemmer &lt;spec&gt;
367
 
   *  The stemmering algorihtm (classname plus parameters) to use.</pre>
368
 
   * 
369
 
   * <pre> -M &lt;int&gt;
370
 
   *  The minimum term frequency (default = 1).</pre>
371
 
   * 
372
 
   * <pre> -O
373
 
   *  If this is set, the maximum number of words and the 
374
 
   *  minimum term frequency is not enforced on a per-class 
375
 
   *  basis but based on the documents in all the classes 
376
 
   *  (even if a class attribute is set).</pre>
377
 
   * 
378
 
   * <pre> -stopwords &lt;file&gt;
379
 
   *  A file containing stopwords to override the default ones.
380
 
   *  Using this option automatically sets the flag ('-S') to use the
381
 
   *  stoplist if the file exists.
382
 
   *  Format: one stopword per line, lines starting with '#'
383
 
   *  are interpreted as comments and ignored.</pre>
384
 
   * 
385
 
   * <pre> -tokenizer &lt;spec&gt;
386
 
   *  The tokenizing algorihtm (classname plus parameters) to use.
387
 
   *  (default: weka.core.tokenizers.WordTokenizer)</pre>
388
 
   * 
389
 
   <!-- options-end -->
 
341
         <!-- options-start -->
 
342
         * Valid options are: <p/>
 
343
         * 
 
344
         * <pre> -C
 
345
         *  Output word counts rather than boolean word presence.
 
346
         * </pre>
 
347
         * 
 
348
         * <pre> -R &lt;index1,index2-index4,...&gt;
 
349
         *  Specify list of string attributes to convert to words (as weka Range).
 
350
         *  (default: select all string attributes)</pre>
 
351
         * 
 
352
         * <pre> -V
 
353
         *  Invert matching sense of column indexes.</pre>
 
354
         * 
 
355
         * <pre> -P &lt;attribute name prefix&gt;
 
356
         *  Specify a prefix for the created attribute names.
 
357
         *  (default: "")</pre>
 
358
         * 
 
359
         * <pre> -W &lt;number of words to keep&gt;
 
360
         *  Specify approximate number of word fields to create.
 
361
         *  Surplus words will be discarded..
 
362
         *  (default: 1000)</pre>
 
363
         * 
 
364
         * <pre> -prune-rate &lt;rate as a percentage of dataset&gt;
 
365
         *  Specify the rate (e.g., every 10% of the input dataset) at which to periodically prune the dictionary.
 
366
         *  -W prunes after creating a full dictionary. You may not have enough memory for this approach.
 
367
         *  (default: no periodic pruning)</pre>
 
368
         * 
 
369
         * <pre> -T
 
370
         *  Transform the word frequencies into log(1+fij)
 
371
         *  where fij is the frequency of word i in jth document(instance).
 
372
         * </pre>
 
373
         * 
 
374
         * <pre> -I
 
375
         *  Transform each word frequency into:
 
376
         *  fij*log(num of Documents/num of documents containing word i)
 
377
         *    where fij if frequency of word i in jth document(instance)</pre>
 
378
         * 
 
379
         * <pre> -N
 
380
         *  Whether to 0=not normalize/1=normalize all data/2=normalize test data only
 
381
         *  to average length of training documents (default 0=don't normalize).</pre>
 
382
         * 
 
383
         * <pre> -L
 
384
         *  Convert all tokens to lowercase before adding to the dictionary.</pre>
 
385
         * 
 
386
         * <pre> -S
 
387
         *  Ignore words that are in the stoplist.</pre>
 
388
         * 
 
389
         * <pre> -stemmer &lt;spec&gt;
 
390
         *  The stemmering algorihtm (classname plus parameters) to use.</pre>
 
391
         * 
 
392
         * <pre> -M &lt;int&gt;
 
393
         *  The minimum term frequency (default = 1).</pre>
 
394
         * 
 
395
         * <pre> -O
 
396
         *  If this is set, the maximum number of words and the 
 
397
         *  minimum term frequency is not enforced on a per-class 
 
398
         *  basis but based on the documents in all the classes 
 
399
         *  (even if a class attribute is set).</pre>
 
400
         * 
 
401
         * <pre> -stopwords &lt;file&gt;
 
402
         *  A file containing stopwords to override the default ones.
 
403
         *  Using this option automatically sets the flag ('-S') to use the
 
404
         *  stoplist if the file exists.
 
405
         *  Format: one stopword per line, lines starting with '#'
 
406
         *  are interpreted as comments and ignored.</pre>
 
407
         * 
 
408
         * <pre> -tokenizer &lt;spec&gt;
 
409
         *  The tokenizing algorihtm (classname plus parameters) to use.
 
410
         *  (default: weka.core.tokenizers.WordTokenizer)</pre>
 
411
         * 
 
412
         <!-- options-end -->
390
413
   *
391
414
   * @param options the list of options as an array of strings
392
415
   * @throws Exception if an option is not supported
393
416
   */
394
417
  public void setOptions(String[] options) throws Exception {
395
418
    String      value;
396
 
    
 
419
 
397
420
    value = Utils.getOption('R', options);
398
421
    if (value.length() != 0)
399
422
      setSelectedRange(value);
414
437
    else
415
438
      setWordsToKeep(1000);
416
439
 
 
440
    value = Utils.getOption("prune-rate", options);
 
441
    if (value.length() > 0)
 
442
      setPeriodicPruning(Double.parseDouble(value));
 
443
    else
 
444
      setPeriodicPruning(-1);
 
445
 
417
446
    value = Utils.getOption('M', options);
418
447
    if (value.length() != 0)
419
448
      setMinTermFreq(Integer.valueOf(value).intValue());
420
449
    else
421
450
      setMinTermFreq(1);
422
 
    
 
451
 
423
452
    setOutputWordCounts(Utils.getFlag('C', options));
424
453
 
425
454
    setTFTransform(Utils.getFlag('T',  options));
426
455
 
427
456
    setIDFTransform(Utils.getFlag('I',  options));
428
 
    
 
457
 
429
458
    setDoNotOperateOnPerClassBasis(Utils.getFlag('O', options));
430
459
 
431
460
    String nString = Utils.getOption('N', options);
433
462
      setNormalizeDocLength(new SelectedTag(Integer.parseInt(nString), TAGS_FILTER));
434
463
    else
435
464
      setNormalizeDocLength(new SelectedTag(FILTER_NONE, TAGS_FILTER));
436
 
    
 
465
 
437
466
    setLowerCaseTokens(Utils.getFlag('L', options));
438
 
    
 
467
 
439
468
    setUseStoplist(Utils.getFlag('S', options));
440
 
    
 
469
 
441
470
    String stemmerString = Utils.getOption("stemmer", options);
442
471
    if (stemmerString.length() == 0) {
443
472
      setStemmer(null);
445
474
    else {
446
475
      String[] stemmerSpec = Utils.splitOptions(stemmerString);
447
476
      if (stemmerSpec.length == 0)
448
 
        throw new Exception("Invalid stemmer specification string");
 
477
        throw new Exception("Invalid stemmer specification string");
449
478
      String stemmerName = stemmerSpec[0];
450
479
      stemmerSpec[0] = "";
451
480
      Stemmer stemmer = (Stemmer) Class.forName(stemmerName).newInstance();
452
481
      if (stemmer instanceof OptionHandler)
453
 
        ((OptionHandler) stemmer).setOptions(stemmerSpec);
 
482
        ((OptionHandler) stemmer).setOptions(stemmerSpec);
454
483
      setStemmer(stemmer);
455
484
    }
456
485
 
467
496
    else {
468
497
      String[] tokenizerSpec = Utils.splitOptions(tokenizerString);
469
498
      if (tokenizerSpec.length == 0)
470
 
        throw new Exception("Invalid tokenizer specification string");
 
499
        throw new Exception("Invalid tokenizer specification string");
471
500
      String tokenizerName = tokenizerSpec[0];
472
501
      tokenizerSpec[0] = "";
473
502
      Tokenizer tokenizer = (Tokenizer) Class.forName(tokenizerName).newInstance();
474
503
      if (tokenizer instanceof OptionHandler)
475
 
        ((OptionHandler) tokenizer).setOptions(tokenizerSpec);
 
504
        ((OptionHandler) tokenizer).setOptions(tokenizerSpec);
476
505
      setTokenizer(tokenizer);
477
506
    }
478
507
  }
501
530
    result.add("-W"); 
502
531
    result.add(String.valueOf(getWordsToKeep()));
503
532
 
 
533
    result.add("-prune-rate"); 
 
534
    result.add(String.valueOf(getPeriodicPruning()));
 
535
 
504
536
    if (getOutputWordCounts())
505
537
      result.add("-C");
506
538
 
559
591
  public StringToWordVector(int wordsToKeep) {
560
592
    m_WordsToKeep = wordsToKeep;
561
593
  }
562
 
  
 
594
 
563
595
  /** 
564
596
   * Used to store word counts for dictionary selection based on 
565
597
   * a threshold.
566
598
   */
567
599
  private class Count 
568
 
    implements Serializable {
 
600
  implements Serializable, RevisionHandler {
569
601
 
570
 
    /** for serialization */
 
602
    /** for serialization. */
571
603
    static final long serialVersionUID = 2157223818584474321L;
572
 
    
573
 
    /** the counts */
 
604
 
 
605
    /** the counts. */
574
606
    public int count, docCount;
575
 
    
 
607
 
576
608
    /**
577
 
     * the constructor
 
609
     * the constructor.
578
610
     * 
579
611
     * @param c the count
580
612
     */
581
613
    public Count(int c) { 
582
614
      count = c; 
583
615
    }
 
616
    
 
617
    /**
 
618
     * Returns the revision string.
 
619
     * 
 
620
     * @return          the revision
 
621
     */
 
622
    public String getRevision() {
 
623
      return RevisionUtils.extract("$Revision: 1.25 $");
 
624
    }
584
625
  }
585
626
 
586
627
  /** 
595
636
    // attributes
596
637
    result.enableAllAttributes();
597
638
    result.enable(Capability.MISSING_VALUES);
598
 
    
 
639
 
599
640
    // class
600
641
    result.enableAllClasses();
601
642
    result.enable(Capability.MISSING_CLASS_VALUES);
602
643
    result.enable(Capability.NO_CLASS);
603
 
    
 
644
 
604
645
    return result;
605
646
  }
606
647
 
615
656
   * successfully
616
657
   */
617
658
  public boolean setInputFormat(Instances instanceInfo) 
618
 
    throws Exception {
 
659
  throws Exception {
619
660
 
620
661
    super.setInputFormat(instanceInfo);
621
662
    m_SelectedRange.setUpper(instanceInfo.numAttributes() - 1);
685
726
      for(int i=0; i < m_NumInstances; i++) {
686
727
        firstCopy = convertInstancewoDocNorm(getInputFormat().instance(i), fv);
687
728
      }
688
 
      
 
729
 
689
730
      // Need to compute average document length if necessary
690
731
      if (m_filterType != FILTER_NONE) {
691
732
        m_AvgDocLength = 0;
724
765
  }
725
766
 
726
767
  /**
727
 
   * Returns a string describing this filter
 
768
   * Returns a string describing this filter.
 
769
   * 
728
770
   * @return a description of the filter suitable for
729
771
   * displaying in the explorer/experimenter gui
730
772
   */  
731
773
  public String globalInfo() {
732
774
    return 
733
 
        "Converts String attributes into a set of attributes representing "
734
 
      + "word occurrence (depending on the tokenizer) information from the "
735
 
      + "text contained in the strings. The set of words (attributes) is "
736
 
      + "determined by the first batch filtered (typically training data).";
 
775
    "Converts String attributes into a set of attributes representing "
 
776
    + "word occurrence (depending on the tokenizer) information from the "
 
777
    + "text contained in the strings. The set of words (attributes) is "
 
778
    + "determined by the first batch filtered (typically training data).";
737
779
  }  
738
 
  
 
780
 
739
781
  /**
740
782
   * Gets whether output instances contain 0 or 1 indicating word
741
783
   * presence, or word counts.
757
799
  }
758
800
 
759
801
  /**
760
 
   * Returns the tip text for this property
 
802
   * Returns the tip text for this property.
 
803
   * 
761
804
   * @return tip text for this property suitable for
762
805
   * displaying in the explorer/experimenter gui
763
806
   */
764
807
  public String outputWordCountsTipText() {
765
 
      return "Output word counts rather than boolean 0 or 1"+
766
 
             "(indicating presence or absence of a word).";
 
808
    return "Output word counts rather than boolean 0 or 1"+
 
809
    "(indicating presence or absence of a word).";
767
810
  }
768
811
 
769
812
  /**
774
817
  public Range getSelectedRange() {
775
818
    return m_SelectedRange;
776
819
  }
777
 
    
 
820
 
778
821
  /**
779
822
   * Set the value of m_SelectedRange.
780
823
   *
785
828
  }
786
829
 
787
830
  /**
788
 
   * Returns the tip text for this property
 
831
   * Returns the tip text for this property.
789
832
   *
790
833
   * @return tip text for this property suitable for
791
834
   * displaying in the explorer/experimenter gui
792
835
   */
793
836
  public String attributeIndicesTipText() {
794
837
    return "Specify range of attributes to act on."
795
 
      + " This is a comma separated list of attribute indices, with"
796
 
      + " \"first\" and \"last\" valid values. Specify an inclusive"
797
 
      + " range with \"-\". E.g: \"first-3,5,6-10,last\".";
 
838
    + " This is a comma separated list of attribute indices, with"
 
839
    + " \"first\" and \"last\" valid values. Specify an inclusive"
 
840
    + " range with \"-\". E.g: \"first-3,5,6-10,last\".";
798
841
  }
799
842
 
800
843
  /**
801
 
   * Gets the current range selection
 
844
   * Gets the current range selection.
802
845
   *
803
846
   * @return a string containing a comma separated list of ranges
804
847
   */
833
876
  }
834
877
 
835
878
  /**
836
 
   * Returns the tip text for this property
 
879
   * Returns the tip text for this property.
837
880
   *
838
881
   * @return tip text for this property suitable for
839
882
   * displaying in the explorer/experimenter gui
840
883
   */
841
884
  public String invertSelectionTipText() {
842
885
    return "Set attribute selection mode. If false, only selected"
843
 
      + " attributes in the range will be worked on; if"
844
 
      + " true, only non-selected attributes will be processed.";
 
886
    + " attributes in the range will be worked on; if"
 
887
    + " true, only non-selected attributes will be processed.";
845
888
  }
846
889
 
847
890
  /**
848
 
   * Gets whether the supplied columns are to be processed or skipped
 
891
   * Gets whether the supplied columns are to be processed or skipped.
849
892
   *
850
893
   * @return true if the supplied columns will be kept
851
894
   */
870
913
  public String getAttributeNamePrefix() {
871
914
    return m_Prefix;
872
915
  }
873
 
    
 
916
 
874
917
  /**
875
918
   * Set the attribute name prefix.
876
919
   *
881
924
  }
882
925
 
883
926
  /**
884
 
   * Returns the tip text for this property
 
927
   * Returns the tip text for this property.
 
928
   * 
885
929
   * @return tip text for this property suitable for
886
930
   * displaying in the explorer/experimenter gui
887
931
   */
888
932
  public String attributeNamePrefixTipText() {
889
 
      return "Prefix for the created attribute names. "+
890
 
             "(default: \"\")";
 
933
    return "Prefix for the created attribute names. "+
 
934
    "(default: \"\")";
891
935
  }
892
936
 
893
937
  /**
900
944
  public int getWordsToKeep() {
901
945
    return m_WordsToKeep;
902
946
  }
903
 
  
 
947
 
904
948
  /**
905
949
   * Sets the number of words (per class if there is a class attribute
906
950
   * assigned) to attempt to keep.
911
955
  public void setWordsToKeep(int newWordsToKeep) {
912
956
    m_WordsToKeep = newWordsToKeep;
913
957
  }
914
 
  
 
958
 
915
959
  /**
916
 
   * Returns the tip text for this property
 
960
   * Returns the tip text for this property.
 
961
   * 
917
962
   * @return tip text for this property suitable for
918
963
   * displaying in the explorer/experimenter gui
919
964
   */
920
965
  public String wordsToKeepTipText() {
921
 
      return "The number of words (per class if there is a class attribute "+
922
 
             "assigned) to attempt to keep.";
 
966
    return "The number of words (per class if there is a class attribute "+
 
967
    "assigned) to attempt to keep.";
 
968
  }
 
969
 
 
970
  /**
 
971
   * Gets the rate at which the dictionary is periodically pruned, as a 
 
972
   * percentage of the dataset size.
 
973
   *
 
974
   * @return the rate at which the dictionary is periodically pruned
 
975
   */
 
976
  public double getPeriodicPruning() {
 
977
    return m_PeriodicPruningRate;
 
978
  }
 
979
 
 
980
  /**
 
981
   * Sets the rate at which the dictionary is periodically pruned, as a 
 
982
   * percentage of the dataset size.
 
983
   *
 
984
   * @param newPeriodicPruning the rate at which the dictionary is periodically pruned
 
985
   */
 
986
  public void setPeriodicPruning(double newPeriodicPruning) {
 
987
    m_PeriodicPruningRate = newPeriodicPruning;
 
988
  }
 
989
 
 
990
  /**
 
991
   * Returns the tip text for this property.
 
992
   * 
 
993
   * @return tip text for this property suitable for
 
994
   * displaying in the explorer/experimenter gui
 
995
   */
 
996
  public String periodicPruningTipText() {
 
997
    return "Specify the rate (x% of the input dataset) at which to periodically prune the dictionary. "
 
998
    + "wordsToKeep prunes after creating a full dictionary. You may not have enough "
 
999
    + "memory for this approach.";
923
1000
  }
924
1001
 
925
1002
  /** Gets whether if the word frequencies should be transformed into
928
1005
   * @return true if word frequencies are to be transformed.
929
1006
   */
930
1007
  public boolean getTFTransform() {
931
 
      return this.m_TFTransform;
 
1008
    return this.m_TFTransform;
932
1009
  }
933
 
  
 
1010
 
934
1011
  /** Sets whether if the word frequencies should be transformed into
935
1012
   *  log(1+fij) where fij is the frequency of word i in document(instance) j.
936
1013
   *
937
1014
   * @param TFTransform true if word frequencies are to be transformed.
938
1015
   */
939
1016
  public void setTFTransform(boolean TFTransform) {
940
 
      this.m_TFTransform = TFTransform;
 
1017
    this.m_TFTransform = TFTransform;
941
1018
  }
942
 
  
 
1019
 
943
1020
  /**
944
 
   * Returns the tip text for this property
 
1021
   * Returns the tip text for this property.
 
1022
   * 
945
1023
   * @return tip text for this property suitable for
946
1024
   * displaying in the explorer/experimenter gui
947
1025
   */
948
1026
  public String TFTransformTipText() {
949
 
      return "Sets whether if the word frequencies should be transformed into:\n "+
950
 
             "   log(1+fij) \n"+
951
 
             "       where fij is the frequency of word i in document (instance) j.";
 
1027
    return "Sets whether if the word frequencies should be transformed into:\n "+
 
1028
    "   log(1+fij) \n"+
 
1029
    "       where fij is the frequency of word i in document (instance) j.";
952
1030
  }
953
 
  
 
1031
 
954
1032
  /** Sets whether if the word frequencies in a document should be transformed
955
1033
   * into: <br>
956
1034
   * fij*log(num of Docs/num of Docs with word i) <br>
959
1037
   * @return true if the word frequencies are to be transformed.
960
1038
   */
961
1039
  public boolean getIDFTransform() {
962
 
      return this.m_IDFTransform;
 
1040
    return this.m_IDFTransform;
963
1041
  }
964
 
  
 
1042
 
965
1043
  /** Sets whether if the word frequencies in a document should be transformed
966
1044
   * into: <br>
967
1045
   * fij*log(num of Docs/num of Docs with word i) <br>
970
1048
   * @param IDFTransform true if the word frequecies are to be transformed
971
1049
   */
972
1050
  public void setIDFTransform(boolean IDFTransform) {
973
 
      this.m_IDFTransform = IDFTransform;
 
1051
    this.m_IDFTransform = IDFTransform;
974
1052
  }
975
 
  
 
1053
 
976
1054
  /**
977
 
   * Returns the tip text for this property
 
1055
   * Returns the tip text for this property.
 
1056
   * 
978
1057
   * @return tip text for this property suitable for
979
1058
   * displaying in the explorer/experimenter gui
980
1059
   */
981
1060
  public String IDFTransformTipText() {
982
 
      return "Sets whether if the word frequencies in a document should be "+
983
 
             "transformed into: \n"+
984
 
             "   fij*log(num of Docs/num of Docs with word i) \n"+
985
 
             "      where fij is the frequency of word i in document (instance) j.";
 
1061
    return "Sets whether if the word frequencies in a document should be "+
 
1062
    "transformed into: \n"+
 
1063
    "   fij*log(num of Docs/num of Docs with word i) \n"+
 
1064
    "      where fij is the frequency of word i in document (instance) j.";
986
1065
  }
987
1066
 
988
 
  
 
1067
 
989
1068
  /** Gets whether if the word frequencies for a document (instance) should
990
1069
   *  be normalized or not.
991
1070
   *
995
1074
 
996
1075
    return new SelectedTag(m_filterType, TAGS_FILTER);
997
1076
  }
998
 
  
 
1077
 
999
1078
  /** Sets whether if the word frequencies for a document (instance) should
1000
1079
   *  be normalized or not.
1001
1080
   *
1002
1081
   * @param newType the new type.
1003
1082
   */
1004
1083
  public void setNormalizeDocLength(SelectedTag newType) {
1005
 
    
 
1084
 
1006
1085
    if (newType.getTags() == TAGS_FILTER) {
1007
1086
      m_filterType = newType.getSelectedTag().getID();
1008
1087
    }
1009
1088
  }
1010
1089
 
1011
1090
  /**
1012
 
   * Returns the tip text for this property
 
1091
   * Returns the tip text for this property.
1013
1092
   *
1014
1093
   * @return tip text for this property suitable for
1015
1094
   * displaying in the explorer/experimenter gui
1016
1095
   */
1017
1096
  public String normalizeDocLengthTipText() {
1018
 
      return "Sets whether if the word frequencies for a document (instance) "+
1019
 
             "should be normalized or not.";
 
1097
    return "Sets whether if the word frequencies for a document (instance) "+
 
1098
    "should be normalized or not.";
1020
1099
  }
1021
 
  
 
1100
 
1022
1101
  /** Gets whether if the tokens are to be downcased or not.
1023
1102
   *
1024
1103
   * @return true if the tokens are to be downcased.
1025
1104
   */
1026
1105
  public boolean getLowerCaseTokens() {
1027
 
      return this.m_lowerCaseTokens;
 
1106
    return this.m_lowerCaseTokens;
1028
1107
  }
1029
 
  
 
1108
 
1030
1109
  /** Sets whether if the tokens are to be downcased or not. (Doesn't affect
1031
1110
   * non-alphabetic characters in tokens).
1032
1111
   *
1034
1113
   * to be formed.
1035
1114
   */
1036
1115
  public void setLowerCaseTokens(boolean downCaseTokens) {
1037
 
      this.m_lowerCaseTokens = downCaseTokens;
 
1116
    this.m_lowerCaseTokens = downCaseTokens;
1038
1117
  }
1039
1118
 
1040
1119
  /**
1044
1123
   * displaying in the explorer/experimenter gui
1045
1124
   */
1046
1125
  public String doNotOperateOnPerClassBasisTipText() {
1047
 
      return "If this is set, the maximum number of words and the "
1048
 
        + "minimum term frequency is not enforced on a per-class "
1049
 
        + "basis but based on the documents in all the classes "
1050
 
        +  "(even if a class attribute is set).";
 
1126
    return "If this is set, the maximum number of words and the "
 
1127
    + "minimum term frequency is not enforced on a per-class "
 
1128
    + "basis but based on the documents in all the classes "
 
1129
    +  "(even if a class attribute is set).";
1051
1130
  }
1052
1131
 
1053
1132
  /**
1073
1152
   * displaying in the explorer/experimenter gui
1074
1153
   */
1075
1154
  public String minTermFreqTipText() {
1076
 
      return "Sets the minimum term frequency. This is enforced "
1077
 
        + "on a per-class basis.";
 
1155
    return "Sets the minimum term frequency. This is enforced "
 
1156
    + "on a per-class basis.";
1078
1157
  }
1079
1158
 
1080
1159
  /**
1092
1171
  public void setMinTermFreq(int newMinTermFreq) {
1093
1172
    this.m_minTermFreq = newMinTermFreq;
1094
1173
  }
1095
 
  
 
1174
 
1096
1175
  /**
1097
1176
   * Returns the tip text for this property.
1098
1177
   *
1100
1179
   * displaying in the explorer/experimenter gui
1101
1180
   */
1102
1181
  public String lowerCaseTokensTipText() {
1103
 
      return "If set then all the word tokens are converted to lower case "+
1104
 
             "before being added to the dictionary.";
 
1182
    return "If set then all the word tokens are converted to lower case "+
 
1183
    "before being added to the dictionary.";
1105
1184
  }
1106
1185
 
1107
1186
  /** Gets whether if the words on the stoplist are to be ignored (The stoplist
1110
1189
   * @return true if the words on the stoplist are to be ignored.
1111
1190
   */
1112
1191
  public boolean getUseStoplist() {
1113
 
      return m_useStoplist;
 
1192
    return m_useStoplist;
1114
1193
  }  
1115
 
  
 
1194
 
1116
1195
  /** Sets whether if the words that are on a stoplist are to be ignored (The
1117
1196
   * stop list is in weka.core.StopWords).
1118
1197
   *
1120
1199
   * ignored.
1121
1200
   */
1122
1201
  public void setUseStoplist(boolean useStoplist) {
1123
 
      m_useStoplist = useStoplist;
 
1202
    m_useStoplist = useStoplist;
1124
1203
  }  
1125
 
  
 
1204
 
1126
1205
  /**
1127
1206
   * Returns the tip text for this property.
1128
1207
   *
1130
1209
   * displaying in the explorer/experimenter gui
1131
1210
   */
1132
1211
  public String useStoplistTipText() {
1133
 
      return "Ignores all the words that are on the stoplist, if set to true.";
 
1212
    return "Ignores all the words that are on the stoplist, if set to true.";
1134
1213
  } 
1135
1214
 
1136
1215
  /**
1137
1216
   * the stemming algorithm to use, null means no stemming at all (i.e., the
1138
 
   * NullStemmer is used)
 
1217
   * NullStemmer is used).
1139
1218
   *
1140
1219
   * @param value     the configured stemming algorithm, or null
1141
1220
   * @see             NullStemmer
1201
1280
  public String stopwordsTipText() {
1202
1281
    return "The file containing the stopwords (if this is a directory then the default ones are used).";
1203
1282
  }
1204
 
  
 
1283
 
1205
1284
  /**
1206
 
   * the tokenizer algorithm to use
 
1285
   * the tokenizer algorithm to use.
1207
1286
   *
1208
1287
   * @param value     the configured tokenizing algorithm
1209
1288
   */
1231
1310
  }
1232
1311
 
1233
1312
  /**
1234
 
   * sorts an array
 
1313
   * sorts an array.
1235
1314
   * 
1236
1315
   * @param array the array to sort
1237
1316
   */
1238
1317
  private static void sortArray(int [] array) {
1239
 
      
 
1318
 
1240
1319
    int i, j, h, N = array.length - 1;
1241
 
        
 
1320
 
1242
1321
    for (h = 1; h <= N / 9; h = 3 * h + 1); 
1243
 
        
 
1322
 
1244
1323
    for (; h > 0; h /= 3) {
1245
1324
      for (i = h + 1; i <= N; i++) { 
1246
 
        int v = array[i]; 
1247
 
        j = i; 
1248
 
        while (j > h && array[j - h] > v ) { 
1249
 
          array[j] = array[j - h]; 
1250
 
          j -= h; 
1251
 
        } 
1252
 
        array[j] = v; 
 
1325
        int v = array[i]; 
 
1326
        j = i; 
 
1327
        while (j > h && array[j - h] > v ) { 
 
1328
          array[j] = array[j - h]; 
 
1329
          j -= h; 
 
1330
        } 
 
1331
        array[j] = v; 
1253
1332
      } 
1254
1333
    }
1255
1334
  }
1256
1335
 
1257
1336
  /**
1258
 
   * determines the selected range
 
1337
   * determines the selected range.
1259
1338
   */
1260
1339
  private void determineSelectedRange() {
1261
 
    
 
1340
 
1262
1341
    Instances inputFormat = getInputFormat();
1263
 
    
 
1342
 
1264
1343
    // Calculate the default set of fields to convert
1265
1344
    if (m_SelectedRange == null) {
1266
1345
      StringBuffer fields = new StringBuffer();
1271
1350
      m_SelectedRange = new Range(fields.toString());
1272
1351
    }
1273
1352
    m_SelectedRange.setUpper(inputFormat.numAttributes() - 1);
1274
 
    
 
1353
 
1275
1354
    // Prevent the user from converting non-string fields
1276
1355
    StringBuffer fields = new StringBuffer();
1277
1356
    for (int j = 0; j < inputFormat.numAttributes(); j++) { 
1284
1363
 
1285
1364
    // System.err.println("Selected Range: " + getSelectedRange().getRanges()); 
1286
1365
  }
1287
 
  
 
1366
 
1288
1367
  /**
1289
 
   * determines the dictionary
 
1368
   * determines the dictionary.
1290
1369
   */
1291
1370
  private void determineDictionary() {
1292
1371
    // initialize stopwords
1318
1397
    determineSelectedRange();
1319
1398
 
1320
1399
    // Tokenize all training text into an orderedMap of "words".
 
1400
    long pruneRate = 
 
1401
      Math.round((m_PeriodicPruningRate/100.0)*getInputFormat().numInstances());
1321
1402
    for (int i = 0; i < getInputFormat().numInstances(); i++) {
1322
1403
      Instance instance = getInputFormat().instance(i);
1323
1404
      int vInd = 0;
1328
1409
      // Iterate through all relevant string attributes of the current instance
1329
1410
      Hashtable h = new Hashtable();
1330
1411
      for (int j = 0; j < instance.numAttributes(); j++) { 
1331
 
        if (m_SelectedRange.isInRange(j) && (instance.isMissing(j) == false)) {
 
1412
        if (m_SelectedRange.isInRange(j) && (instance.isMissing(j) == false)) {
1332
1413
 
1333
1414
          // Get tokenizer
1334
 
          m_Tokenizer.tokenize(instance.stringValue(j));
1335
 
          
 
1415
          m_Tokenizer.tokenize(instance.stringValue(j));
 
1416
 
1336
1417
          // Iterate through tokens, perform stemming, and remove stopwords
1337
1418
          // (if required)
1338
 
          while (m_Tokenizer.hasMoreElements()) {
1339
 
            String word = ((String)m_Tokenizer.nextElement()).intern();
1340
 
            
1341
 
            if(this.m_lowerCaseTokens==true)
1342
 
                word = word.toLowerCase();
1343
 
            
1344
 
            word = m_Stemmer.stem(word);
1345
 
            
1346
 
            if(this.m_useStoplist==true)
1347
 
                if(stopwords.is(word))
1348
 
                    continue;
1349
 
            
1350
 
            if(!(h.contains(word)))
1351
 
                h.put(word, new Integer(0));
1352
 
 
1353
 
            Count count = (Count)dictionaryArr[vInd].get(word);
1354
 
            if (count == null) {
1355
 
              dictionaryArr[vInd].put(word, new Count(1));
1356
 
            } else {
1357
 
              count.count ++;                
1358
 
            }
1359
 
          }          
1360
 
        }
 
1419
          while (m_Tokenizer.hasMoreElements()) {
 
1420
            String word = ((String)m_Tokenizer.nextElement()).intern();
 
1421
 
 
1422
            if(this.m_lowerCaseTokens==true)
 
1423
              word = word.toLowerCase();
 
1424
 
 
1425
            word = m_Stemmer.stem(word);
 
1426
 
 
1427
            if(this.m_useStoplist==true)
 
1428
              if(stopwords.is(word))
 
1429
                continue;
 
1430
 
 
1431
            if(!(h.contains(word)))
 
1432
              h.put(word, new Integer(0));
 
1433
 
 
1434
            Count count = (Count)dictionaryArr[vInd].get(word);
 
1435
            if (count == null) {
 
1436
              dictionaryArr[vInd].put(word, new Count(1));
 
1437
            } else {
 
1438
              count.count++;                
 
1439
            }
 
1440
          }          
 
1441
        }
1361
1442
      }
1362
1443
 
1363
1444
      //updating the docCount for the words that have occurred in this
1370
1451
          c.docCount++;
1371
1452
        } else 
1372
1453
          System.err.println("Warning: A word should definitely be in the "+
1373
 
                             "dictionary.Please check the code");
 
1454
              "dictionary.Please check the code");
 
1455
      }
 
1456
 
 
1457
 
 
1458
      if (pruneRate > 0) {
 
1459
        if (i % pruneRate == 0 && i > 0) {
 
1460
          for (int z = 0; z < values; z++) {
 
1461
            Vector d = new Vector(1000);
 
1462
            Iterator it = dictionaryArr[z].keySet().iterator();
 
1463
            while (it.hasNext()) {
 
1464
              String word = (String)it.next();
 
1465
              Count count = (Count)dictionaryArr[z].get(word);
 
1466
              if (count.count <= 1) { d.add(word); }
 
1467
            }
 
1468
            Iterator iter = d.iterator();
 
1469
            while(iter.hasNext()) {
 
1470
              String word = (String)iter.next();
 
1471
              dictionaryArr[z].remove(word);
 
1472
            }
 
1473
          }
 
1474
        }
1374
1475
      }
1375
1476
    }
1376
1477
 
1384
1485
      int pos = 0;
1385
1486
      Iterator it = dictionaryArr[z].keySet().iterator();
1386
1487
      while (it.hasNext()) {
1387
 
        String word = (String)it.next();
1388
 
        Count count = (Count)dictionaryArr[z].get(word);
1389
 
        array[pos] = count.count;
1390
 
        pos++;
 
1488
        String word = (String)it.next();
 
1489
        Count count = (Count)dictionaryArr[z].get(word);
 
1490
        array[pos] = count.count;
 
1491
        pos++;
1391
1492
      }
1392
1493
 
1393
1494
      // sort the array
1394
1495
      sortArray(array);
1395
1496
      if (array.length < m_WordsToKeep) {
1396
 
        // if there aren't enough words, set the threshold to
 
1497
        // if there aren't enough words, set the threshold to
1397
1498
        // minFreq
1398
 
        prune[z] = m_minTermFreq;
 
1499
        prune[z] = m_minTermFreq;
1399
1500
      } else {
1400
 
        // otherwise set it to be at least minFreq
1401
 
        prune[z] = Math.max(m_minTermFreq, 
1402
 
                            array[array.length - m_WordsToKeep]);
 
1501
        // otherwise set it to be at least minFreq
 
1502
        prune[z] = Math.max(m_minTermFreq, 
 
1503
            array[array.length - m_WordsToKeep]);
1403
1504
      }
1404
1505
    }
1405
1506
 
1406
1507
    // Convert the dictionary into an attribute index
1407
1508
    // and create one attribute per word
1408
1509
    FastVector attributes = new FastVector(totalsize +
1409
 
                                           getInputFormat().numAttributes());
 
1510
        getInputFormat().numAttributes());
1410
1511
 
1411
1512
    // Add the non-converted attributes 
1412
1513
    int classIndex = -1;
1413
1514
    for (int i = 0; i < getInputFormat().numAttributes(); i++) {
1414
1515
      if (!m_SelectedRange.isInRange(i)) { 
1415
 
        if (getInputFormat().classIndex() == i) {
1416
 
          classIndex = attributes.size();
1417
 
        }
 
1516
        if (getInputFormat().classIndex() == i) {
 
1517
          classIndex = attributes.size();
 
1518
        }
1418
1519
        attributes.addElement(getInputFormat().attribute(i).copy());
1419
1520
      }     
1420
1521
    }
1421
 
    
 
1522
 
1422
1523
    // Add the word vector attributes (eliminating duplicates
1423
 
    // that occur in multiple classes)
 
1524
        // that occur in multiple classes)
1424
1525
    TreeMap newDictionary = new TreeMap();
1425
1526
    int index = attributes.size();
1426
1527
    for(int z = 0; z < values; z++) {
1427
1528
      Iterator it = dictionaryArr[z].keySet().iterator();
1428
1529
      while (it.hasNext()) {
1429
 
        String word = (String)it.next();
1430
 
        Count count = (Count)dictionaryArr[z].get(word);
1431
 
        if (count.count >= prune[z]) {
1432
 
          if(newDictionary.get(word) == null) {
1433
 
            newDictionary.put(word, new Integer(index++));
1434
 
            attributes.addElement(new Attribute(m_Prefix + word));
1435
 
          }
1436
 
        }
 
1530
        String word = (String)it.next();
 
1531
        Count count = (Count)dictionaryArr[z].get(word);
 
1532
        if (count.count >= prune[z]) {
 
1533
          if(newDictionary.get(word) == null) {
 
1534
            newDictionary.put(word, new Integer(index++));
 
1535
            attributes.addElement(new Attribute(m_Prefix + word));
 
1536
          }
 
1537
        }
1437
1538
      }
1438
1539
    }
1439
 
    
 
1540
 
1440
1541
    // Compute document frequencies
1441
1542
    m_DocsCounts = new int[attributes.size()];
1442
1543
    Iterator it = newDictionary.keySet().iterator();
1456
1557
    attributes.trimToSize();
1457
1558
    m_Dictionary = newDictionary;
1458
1559
    m_NumInstances = getInputFormat().numInstances();
1459
 
    
 
1560
 
1460
1561
    // Set the filter's output format
1461
1562
    Instances outputFormat = new Instances(getInputFormat().relationName(), 
1462
 
                                           attributes, 0);
 
1563
        attributes, 0);
1463
1564
    outputFormat.setClassIndex(classIndex);
1464
1565
    setOutputFormat(outputFormat);
1465
1566
  }
1475
1576
 
1476
1577
    // Convert the instance into a sorted set of indexes
1477
1578
    TreeMap contained = new TreeMap();
1478
 
    
 
1579
 
1479
1580
    // Copy all non-converted attributes from input to output
1480
1581
    int firstCopy = 0;
1481
1582
    for (int i = 0; i < getInputFormat().numAttributes(); i++) {
1484
1585
          // Add simple nominal and numeric attributes directly
1485
1586
          if (instance.value(i) != 0.0) {
1486
1587
            contained.put(new Integer(firstCopy), 
1487
 
                          new Double(instance.value(i)));
 
1588
                new Double(instance.value(i)));
1488
1589
          } 
1489
1590
        } else {
1490
1591
          if (instance.isMissing(i)) {
1491
1592
            contained.put(new Integer(firstCopy),
1492
 
                          new Double(Instance.missingValue()));
 
1593
                new Double(Instance.missingValue()));
1493
1594
          } else {
1494
 
            
 
1595
 
1495
1596
            // If this is a string attribute, we have to first add
1496
1597
            // this value to the range of possible values, then add
1497
1598
            // its new internal index.
1499
1600
              // Note that the first string value in a
1500
1601
              // SparseInstance doesn't get printed.
1501
1602
              outputFormatPeek().attribute(firstCopy)
1502
 
                .addStringValue("Hack to defeat SparseInstance bug");
 
1603
              .addStringValue("Hack to defeat SparseInstance bug");
1503
1604
            }
1504
1605
            int newIndex = outputFormatPeek().attribute(firstCopy)
1505
 
              .addStringValue(instance.stringValue(i));
 
1606
            .addStringValue(instance.stringValue(i));
1506
1607
            contained.put(new Integer(firstCopy), 
1507
 
                          new Double(newIndex));
 
1608
                new Double(newIndex));
1508
1609
          }
1509
1610
        }
1510
1611
        firstCopy++;
1511
1612
      }     
1512
1613
    }
1513
 
    
 
1614
 
1514
1615
    for (int j = 0; j < instance.numAttributes(); j++) { 
1515
1616
      //if ((getInputFormat().attribute(j).type() == Attribute.STRING) 
1516
1617
      if (m_SelectedRange.isInRange(j)
1517
1618
          && (instance.isMissing(j) == false)) {          
1518
 
        
1519
 
        m_Tokenizer.tokenize(instance.stringValue(j));
1520
 
        
1521
 
        while (m_Tokenizer.hasMoreElements()) {
1522
 
          String word = (String)m_Tokenizer.nextElement(); 
1523
 
          if(this.m_lowerCaseTokens==true)
 
1619
 
 
1620
        m_Tokenizer.tokenize(instance.stringValue(j));
 
1621
 
 
1622
        while (m_Tokenizer.hasMoreElements()) {
 
1623
          String word = (String)m_Tokenizer.nextElement(); 
 
1624
          if(this.m_lowerCaseTokens==true)
1524
1625
            word = word.toLowerCase();
1525
 
          word = m_Stemmer.stem(word);
1526
 
          Integer index = (Integer) m_Dictionary.get(word);
1527
 
          if (index != null) {
1528
 
            if (m_OutputCounts) { // Separate if here rather than two lines down to avoid hashtable lookup
1529
 
              Double count = (Double)contained.get(index);
1530
 
              if (count != null) {
1531
 
                contained.put(index, new Double(count.doubleValue() + 1.0));
1532
 
              } else {
1533
 
                contained.put(index, new Double(1));
1534
 
              }
1535
 
            } else {
1536
 
              contained.put(index, new Double(1));
1537
 
            }                
1538
 
          }
1539
 
        }
 
1626
          word = m_Stemmer.stem(word);
 
1627
          Integer index = (Integer) m_Dictionary.get(word);
 
1628
          if (index != null) {
 
1629
            if (m_OutputCounts) { // Separate if here rather than two lines down to avoid hashtable lookup
 
1630
              Double count = (Double)contained.get(index);
 
1631
            if (count != null) {
 
1632
              contained.put(index, new Double(count.doubleValue() + 1.0));
 
1633
            } else {
 
1634
              contained.put(index, new Double(1));
 
1635
            }
 
1636
            } else {
 
1637
              contained.put(index, new Double(1));
 
1638
            }                
 
1639
          }
 
1640
        }
1540
1641
      }
1541
1642
    }
1542
 
    
 
1643
 
1543
1644
    //Doing TFTransform
1544
1645
    if(m_TFTransform==true) {
1545
1646
      Iterator it = contained.keySet().iterator();
1552
1653
        }
1553
1654
      }
1554
1655
    }
1555
 
    
 
1656
 
1556
1657
    //Doing IDFTransform
1557
1658
    if(m_IDFTransform==true) {
1558
1659
      Iterator it = contained.keySet().iterator();
1561
1662
        if( index.intValue() >= firstCopy ) {
1562
1663
          double val = ((Double)contained.get(index)).doubleValue();
1563
1664
          val = val*Math.log( m_NumInstances /
1564
 
                              (double) m_DocsCounts[index.intValue()] );
 
1665
              (double) m_DocsCounts[index.intValue()] );
1565
1666
          contained.put(index, new Double(val));
1566
1667
        }
1567
1668
      }        
1568
1669
    }
1569
 
    
 
1670
 
1570
1671
    // Convert the set to structures needed to create a sparse instance.
1571
1672
    double [] values = new double [contained.size()];
1572
1673
    int [] indices = new int [contained.size()];
1579
1680
    }
1580
1681
 
1581
1682
    Instance inst = new SparseInstance(instance.weight(), values, indices, 
1582
 
                                       outputFormatPeek().numAttributes());
 
1683
        outputFormatPeek().numAttributes());
1583
1684
    inst.setDataset(outputFormatPeek());
1584
1685
 
1585
1686
    v.addElement(inst);
1586
 
    
 
1687
 
1587
1688
    return firstCopy;    
1588
1689
  }
1589
 
  
 
1690
 
1590
1691
  /**
1591
1692
   * Normalizes given instance to average doc length (only the newly
1592
1693
   * constructed attributes).
1596
1697
   * @throws Exception if avg. doc length not set
1597
1698
   */
1598
1699
  private void normalizeInstance(Instance inst, int firstCopy) 
1599
 
    throws Exception {
 
1700
  throws Exception {
1600
1701
 
1601
1702
    double docLength = 0;
1602
1703
 
1626
1727
  }
1627
1728
  
1628
1729
  /**
 
1730
   * Returns the revision string.
 
1731
   * 
 
1732
   * @return            the revision
 
1733
   */
 
1734
  public String getRevision() {
 
1735
    return RevisionUtils.extract("$Revision: 1.25 $");
 
1736
  }
 
1737
 
 
1738
  /**
1629
1739
   * Main method for testing this class.
1630
1740
   *
1631
1741
   * @param argv should contain arguments to the filter: 
1635
1745
    runFilter(new StringToWordVector(), argv);
1636
1746
  }
1637
1747
}
 
1748