source: src/main/java/weka/associations/ItemSet.java @ 25

Last change on this file since 25 was 4, checked in by gnappo, 14 years ago

Import di weka.

File size: 13.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 *    ItemSet.java
19 *    Copyright (C) 1999 University of Waikato, Hamilton, New Zealand
20 *
21 */
22
23package weka.associations;
24
25import weka.core.FastVector;
26import weka.core.Instance;
27import weka.core.Instances;
28import weka.core.RevisionHandler;
29import weka.core.RevisionUtils;
30
31import java.io.Serializable;
32import java.util.Enumeration;
33import java.util.Hashtable;
34
35/**
36 * Class for storing a set of items. Item sets are stored in a lexicographic
37 * order, which is determined by the header information of the set of instances
38 * used for generating the set of items. All methods in this class assume that
39 * item sets are stored in lexicographic order.
40 * The class provides the general methods used for item sets in class - and
41 * standard association rule mining.
42 *
43 * @author Eibe Frank (eibe@cs.waikato.ac.nz)
44 * @version $Revision: 5130 $
45 */
46public class ItemSet
47  implements Serializable, RevisionHandler {
48
49  /** for serialization */
50  private static final long serialVersionUID = 2724000045282835791L;
51 
52  /** The items stored as an array of of ints. */
53  protected int[] m_items;
54
55  /** Counter for how many transactions contain this item set. */
56  protected int m_counter;
57
58  /** The total number of transactions */
59  protected int m_totalTransactions;
60 
61  /**
62   * Treat zeros as missing (rather than a value in their
63   * own right)
64   */
65  protected boolean m_treatZeroAsMissing = false;
66
67  /**
68   * Constructor
69   * @param totalTrans the total number of transactions in the data
70   */
71  public ItemSet(int totalTrans) {
72    m_totalTransactions = totalTrans;
73  }
74
75   /**
76   * Constructor
77   * @param totalTrans the total number of transactions in the data
78   * @param array the attribute values encoded in an int array
79   */
80  public ItemSet(int totalTrans, int[] array){
81       
82       m_totalTransactions = totalTrans;
83       m_items = array;
84       m_counter =1;
85   }
86 
87  /** Contsructor
88   * @param array the item set represented as an int array
89   */ 
90  public ItemSet(int[] array){
91       
92       m_items = array;
93       m_counter = 0;
94   }
95
96  /**
97   * Checks if an instance contains an item set.
98   *
99   * @param instance the instance to be tested
100   * @return true if the given instance contains this item set
101   */
102  public boolean containedBy(Instance instance) {
103
104    if (instance instanceof weka.core.SparseInstance && m_treatZeroAsMissing) {
105      int numInstVals = instance.numValues();
106      int numItemSetVals = m_items.length;
107
108      for (int p1 = 0, p2 = 0; p1 < numInstVals || p2 < numItemSetVals; ) {
109        int instIndex = Integer.MAX_VALUE;
110        if (p1 < numInstVals) {
111          instIndex = instance.index(p1);
112        }
113        int itemIndex = p2;
114
115        if (m_items[itemIndex] > -1) {
116          if (itemIndex != instIndex) {
117            return false;
118          } else {
119            if (instance.isMissingSparse(p1)) {
120              return false;
121            }
122            if (m_items[itemIndex] != (int)instance.valueSparse(p1)) {
123              return false;
124            }
125          }
126
127          p1++;
128          p2++;
129        } else {
130          if (itemIndex < instIndex) {
131            p2++;
132          } else if (itemIndex == instIndex){
133            p2++;
134            p1++;
135          }
136        }     
137      }
138    } else {
139      for (int i = 0; i < instance.numAttributes(); i++) 
140        if (m_items[i] > -1) {
141          if (instance.isMissing(i) || 
142              (m_treatZeroAsMissing && (int)instance.value(i) == 0))
143            return false;
144          if (m_items[i] != (int)instance.value(i))
145            return false;
146        }
147    }
148
149    return true;
150  }
151
152  /** Deletes all item sets that don't have minimum support.
153   * @return the reduced set of item sets
154   * @param maxSupport the maximum support
155   * @param itemSets the set of item sets to be pruned
156   * @param minSupport the minimum number of transactions to be covered
157   */
158  public static FastVector deleteItemSets(FastVector itemSets, 
159                                          int minSupport,
160                                          int maxSupport) {
161
162    FastVector newVector = new FastVector(itemSets.size());
163
164    for (int i = 0; i < itemSets.size(); i++) {
165      ItemSet current = (ItemSet)itemSets.elementAt(i);
166      if ((current.m_counter >= minSupport) 
167          && (current.m_counter <= maxSupport))
168        newVector.addElement(current);
169    }
170    return newVector;
171  }
172
173  /**
174   * Tests if two item sets are equal.
175   *
176   * @param itemSet another item set
177   * @return true if this item set contains the same items as the given one
178   */
179  public boolean equals(Object itemSet) {
180
181    if ((itemSet == null) || !(itemSet.getClass().equals(this.getClass()))) {
182      return false;
183    }
184    if (m_items.length != ((ItemSet)itemSet).m_items.length)
185      return false;
186    for (int i = 0; i < m_items.length; i++)
187      if (m_items[i] != ((ItemSet)itemSet).m_items[i])
188        return false;
189    return true;
190  }
191
192  /**
193   * Return a hashtable filled with the given item sets.
194   *
195   * @param itemSets the set of item sets to be used for filling the hash table
196   * @param initialSize the initial size of the hashtable
197   * @return the generated hashtable
198   */
199  public static Hashtable getHashtable(FastVector itemSets, int initialSize) {
200
201    Hashtable hashtable = new Hashtable(initialSize);
202
203    for (int i = 0; i < itemSets.size(); i++) {
204      ItemSet current = (ItemSet)itemSets.elementAt(i);
205      hashtable.put(current, new Integer(current.m_counter));
206    }
207    return hashtable;
208  }
209
210  /**
211   * Produces a hash code for a item set.
212   *
213   * @return a hash code for a set of items
214   */
215  public int hashCode() {
216
217    long result = 0;
218
219    for (int i = m_items.length-1; i >= 0; i--)
220      result += (i * m_items[i]);
221    return (int)result;
222  }
223
224  /** Merges all item sets in the set of (k-1)-item sets
225   * to create the (k)-item sets and updates the counters.
226   * @return the generated (k)-item sets
227   * @param totalTrans thetotal number of transactions
228   * @param itemSets the set of (k-1)-item sets
229   * @param size the value of (k-1)
230   */
231  public static FastVector mergeAllItemSets(FastVector itemSets, int size, 
232                                            int totalTrans) {
233
234    FastVector newVector = new FastVector();
235    ItemSet result;
236    int numFound, k;
237
238    for (int i = 0; i < itemSets.size(); i++) {
239      ItemSet first = (ItemSet)itemSets.elementAt(i);
240    out:
241      for (int j = i+1; j < itemSets.size(); j++) {
242        ItemSet second = (ItemSet)itemSets.elementAt(j);
243        result = new ItemSet(totalTrans);
244        result.m_items = new int[first.m_items.length];
245       
246        // Find and copy common prefix of size 'size'
247        numFound = 0;
248        k = 0;
249        while (numFound < size) {
250          if (first.m_items[k] == second.m_items[k]) {
251            if (first.m_items[k] != -1) 
252              numFound++;
253            result.m_items[k] = first.m_items[k];
254          } else 
255            break out;
256          k++;
257        }
258       
259        // Check difference
260        while (k < first.m_items.length) {
261          if ((first.m_items[k] != -1) && (second.m_items[k] != -1))
262            break;
263          else {
264            if (first.m_items[k] != -1)
265              result.m_items[k] = first.m_items[k];
266            else
267              result.m_items[k] = second.m_items[k];
268          }
269          k++;
270        }
271        if (k == first.m_items.length) {
272          result.m_counter = 0;
273         
274          newVector.addElement(result);
275        }
276      }
277    }
278    return newVector;
279  }
280
281  /**
282   * Prunes a set of (k)-item sets using the given (k-1)-item sets.
283   *
284   * @param toPrune the set of (k)-item sets to be pruned
285   * @param kMinusOne the (k-1)-item sets to be used for pruning
286   * @return the pruned set of item sets
287   */
288  public static FastVector pruneItemSets(FastVector toPrune, Hashtable kMinusOne) {
289
290    FastVector newVector = new FastVector(toPrune.size());
291    int help, j;
292
293    for (int i = 0; i < toPrune.size(); i++) {
294      ItemSet current = (ItemSet)toPrune.elementAt(i);
295      for (j = 0; j < current.m_items.length; j++)
296        if (current.m_items[j] != -1) {
297          help = current.m_items[j];
298          current.m_items[j] = -1;
299          if (kMinusOne.get(current) == null) {
300            current.m_items[j] = help;
301            break;
302          } else{ 
303            current.m_items[j] = help;
304          }
305        }
306      if (j == current.m_items.length) 
307        newVector.addElement(current);
308    }
309    return newVector;
310  }
311
312  /**
313   * Prunes a set of rules.
314   *
315   * @param rules a two-dimensional array of lists of item sets. The first list
316   * of item sets contains the premises, the second one the consequences.
317   * @param minConfidence the minimum confidence the rules have to have
318   */
319  public static void pruneRules(FastVector[] rules, double minConfidence) {
320
321    FastVector newPremises = new FastVector(rules[0].size()),
322      newConsequences = new FastVector(rules[1].size()),
323      newConf = new FastVector(rules[2].size());
324
325    for (int i = 0; i < rules[0].size(); i++) 
326      if (!(((Double)rules[2].elementAt(i)).doubleValue() <
327            minConfidence)) {
328        newPremises.addElement(rules[0].elementAt(i));
329        newConsequences.addElement(rules[1].elementAt(i));
330        newConf.addElement(rules[2].elementAt(i));
331      }
332    rules[0] = newPremises;
333    rules[1] = newConsequences;
334    rules[2] = newConf;
335  }
336
337  /**
338   * Converts the header info of the given set of instances into a set
339   * of item sets (singletons). The ordering of values in the header file
340   * determines the lexicographic order.
341   *
342   * @param instances the set of instances whose header info is to be used
343   * @return a set of item sets, each containing a single item
344   * @exception Exception if singletons can't be generated successfully
345   */
346  public static FastVector singletons(Instances instances) throws Exception {
347
348    FastVector setOfItemSets = new FastVector();
349    ItemSet current;
350
351    for (int i = 0; i < instances.numAttributes(); i++) {
352      if (instances.attribute(i).isNumeric())
353        throw new Exception("Can't handle numeric attributes!");
354      for (int j = 0; j < instances.attribute(i).numValues(); j++) {
355        current = new ItemSet(instances.numInstances());
356        current.m_items = new int[instances.numAttributes()];
357        for (int k = 0; k < instances.numAttributes(); k++)
358          current.m_items[k] = -1;
359        current.m_items[i] = j;
360       
361        setOfItemSets.addElement(current);
362      }
363    }
364    return setOfItemSets;
365  }
366
367  /**
368   * Outputs the support for an item set.
369   *
370   * @return the support
371   */
372  public int support() {
373
374    return m_counter;
375  }
376
377  /**
378   * Returns the contents of an item set as a string.
379   *
380   * @param instances contains the relevant header information
381   * @return string describing the item set
382   */
383  public String toString(Instances instances) {
384
385    StringBuffer text = new StringBuffer();
386
387    for (int i = 0; i < instances.numAttributes(); i++)
388      if (m_items[i] != -1) {
389        text.append(instances.attribute(i).name()+'=');
390        text.append(instances.attribute(i).value(m_items[i])+' ');
391      }
392    text.append(m_counter);
393    return text.toString();
394  }
395
396  /**
397   * Updates counter of item set with respect to given transaction.
398   *
399   * @param instance the instance to be used for ubdating the counter
400   */
401  public void upDateCounter(Instance instance) {
402
403    if (containedBy(instance))
404      m_counter++;
405  }
406
407  /**
408   * Updates counters for a set of item sets and a set of instances.
409   *
410   * @param itemSets the set of item sets which are to be updated
411   * @param instances the instances to be used for updating the counters
412   */
413  public static void upDateCounters(FastVector itemSets, Instances instances) {
414
415    for (int i = 0; i < instances.numInstances(); i++) {
416      Enumeration enu = itemSets.elements();
417      while (enu.hasMoreElements()) 
418        ((ItemSet)enu.nextElement()).upDateCounter(instances.instance(i));
419    }
420  }
421
422  /** Gets the counter
423   * @return the counter
424   */ 
425  public int counter(){
426     
427      return m_counter;
428  }
429 
430  /** Gest the item set as an int array
431   * @return int array represneting an item set
432   */ 
433  public int[] items(){
434     
435      return m_items;
436  }
437 
438  /** Gest the index of the value of the specified attribute
439   * @param k the attribute index
440   * @return the index of the attribute value
441   */ 
442  public int itemAt(int k){
443     
444      return m_items[k];
445  }
446 
447  /** Sets the counter
448   * @param count the counter
449   */ 
450  public void setCounter(int count){
451     
452      m_counter = count;
453  }
454 
455  /** Sets an item sets
456   * @param items an int array representing an item set
457   */ 
458  public void setItem(int[] items){
459     
460      m_items = items;
461  }
462 
463  /** Sets the index of an attribute value
464   * @param value the inex of the attribute value
465   * @param k the index of the attribute
466   */ 
467  public void setItemAt(int value, int k){
468     
469      m_items[k] = value;
470  }
471 
472  /**
473   * Sets whether zeros (i.e. the first value of a nominal attribute)
474   * should be treated as missing values.
475   *
476   * @param z true if zeros should be treated as missing values.
477   */
478  public void setTreatZeroAsMissing(boolean z) {
479    m_treatZeroAsMissing = z;
480  }
481 
482  /**
483   * Gets whether zeros (i.e. the first value of a nominal attribute)
484   * is to be treated int he same way as missing values.
485   *
486   * @return true if zeros are to be treated like missing values.
487   */
488  public boolean getTreatZeroAsMissing() {
489    return m_treatZeroAsMissing;
490  }
491 
492  /**
493   * Returns the revision string.
494   *
495   * @return            the revision
496   */
497  public String getRevision() {
498    return RevisionUtils.extract("$Revision: 5130 $");
499  }
500}
Note: See TracBrowser for help on using the repository browser.