首页 > 代码库 > 数据挖掘经典算法——先验算法

数据挖掘经典算法——先验算法

算法描述

  先验算法是实现频繁项挖掘的一种经典算法,利用关联式规则不断扩展频繁项子集以获得全部的频繁项集合。解释一下关联式规则,所谓关联式是指在大量的数据中找出的项与项之间的关系。例如消费者购买了产品A,一般都会购买产品B,这就是一条关联式。

  先验算法被设计用来处理包含事务的数据库,这里的每一个事务都被当成是一组项集,给定一个阈值C,我们需要找出至少出现C次的事务子集(即子项)。这边这个C值就是最小支持度,规定了一个项集出现多少次才能被认为是一个频繁项。

  先验算法的核心思想基于以下一个事实:一个项集是频繁项集,其所有子集一定是频繁项集;一个项集不是频繁项,其超集一定不是频繁项集。那么我们在寻找事务中的最大频繁项的过程中,只需要扩展是频繁项的子集,这就大大地缩减了搜索空间。下面是该算法的伪代码实现:

 

  其中T代表的是事务集合,表示最小支持度,Li对应的是第i次迭代得到的频繁项集,Ci表示对于第i次迭代的候选项集。伪代码的第一行遍历了事务中的所有项,统计每一项出现的频数,保留所有出现次数高于最小支持度的项。

算法的优缺点

优点:

  •   算法简单,易于理解,对数据的要求度低;

 

缺点:

  •   在选取较小的支持度选取时,可能带来较多的候选集,大量的集合操作会导致算法效率低下;
  •   每一次迭代都需要重新扫描数据库,I/O开销比较大;

 

Apriori算法的Java实现

  

  1 import java.util.ArrayList;  2 import java.util.HashMap;  3 import java.util.HashSet;  4 import java.util.Iterator;  5 import java.util.List;  6 import java.util.Map;  7 import java.util.Set;  8   9 /** 10  * 这是一个简单的先验算法的实现,包含了如下假设: 11  * 1.事务对应一个TID和一个项集合,每个项对应一个int类型的数值,保证同一个事务内部的项唯一 12  * 2.算法在实现方式上还存在很多可以优化剪枝的部分,这里省略了优化,是结构更加清晰 13  * 3.这只是一个样例程序 14  * @author LuZhou 15  * @email 448287076@qq.com 16  */ 17 public class Aprior { 18      19      20     public static class TransactionItem { 21          22         private Integer itemValue; 23          24         public TransactionItem( int i ){ 25             itemValue =http://www.mamicode.com/ i; 26         } 27          28         @Override 29         public boolean equals(Object obj) { 30             TransactionItem it = (TransactionItem) obj; 31             return this.itemValue =http://www.mamicode.com/= it.itemValue; 32         } 33          34          35         @Override 36         public String toString() { 37             return itemValue.toString(); 38         } 39          40         @Override 41         public int hashCode() { 42             return itemValue % 31;  43         } 44     } 45      46      47     public static class ItemCollection{ 48         private Set<TransactionItem> items = new HashSet<Aprior.TransactionItem>(); 49          50         public ItemCollection(){ 51         } 52          53         public ItemCollection(int[] items){ 54             for (int i = 0; i < items.length; i++) { 55                 this.add(new TransactionItem(items[i])); 56             } 57         } 58          59         public boolean itemContains(Set<TransactionItem> sub){ 60             return items.containsAll(sub); 61         } 62          63         @Override 64         public boolean equals(Object obj) { 65             ItemCollection ic = (ItemCollection) obj; 66             return ic.items.containsAll(items) &&  67                     items.containsAll(ic.items); 68         } 69          70         @Override 71         public int hashCode() { 72             int v = 0; 73             for (TransactionItem ts : items) { 74                 v =  ( v + ts.hashCode() ) % 31; 75             } 76             return v; 77         } 78          79         public boolean contains(ItemCollection sub){ 80             return items.containsAll(sub.items); 81         } 82          83         public boolean containItem(TransactionItem item){ 84             return items.contains(item); 85         } 86          87         public Set<TransactionItem> getItems(){ 88             return items; 89         } 90          91         public void add(TransactionItem item){ 92             items.add(item); 93         } 94          95         @Override 96         public String toString() { 97             StringBuilder sb = new StringBuilder(); 98             sb.append("{"); 99             for (TransactionItem item : getItems()) {100                 sb.append( item.toString() );101                 sb.append(",");102             }103             sb.append("}");104             return sb.toString();105         }106 107     }108     109     public static class Transaction{110         private int id;111         private ItemCollection ic;112         113         public Transaction(int id , ItemCollection itemCollection){114             this.id = id;115             this.ic  = itemCollection;116         }117         118         public boolean itemContains(ItemCollection sub){119             return ic.contains(sub);120         }121         122         public Set<TransactionItem> getItems(){123             return ic.getItems();124         }125         126     }127     128     private Set<TransactionItem> restItems = new HashSet<Aprior.TransactionItem>();129     private List<Transaction> transactions = new ArrayList<Aprior.Transaction>();130     131     //统计一项的出现次数132     private int itemsFrequency( ItemCollection sub ){133         int frequency = 0 ;134         135         for (Transaction t : transactions) {136             if(t.itemContains(sub)){137                 frequency ++;138             }        139         }140         141         return frequency;142     }143     144     //确定扩展项是否为频繁项145     private Set< ItemCollection > filterWithThreadshold(146             Set< ItemCollection > items, int threadshold ){147         148         Set< ItemCollection > result = new HashSet<ItemCollection>();149         for (ItemCollection subItems : items) {150             if( threadshold <= itemsFrequency(subItems))151                 result.add(subItems);152         }153         154         return result;155     }156     157     //根据现有的子项集获取所有的可能扩展158     private Set< ItemCollection > extendItems( Set< ItemCollection > current){159         Set< ItemCollection > extend = new HashSet<Aprior.ItemCollection>();160         161         //找出剩余的项集162         restItems.clear();163         for (ItemCollection ic : current) {164             for (TransactionItem item : ic.getItems()) {165                 restItems.add(item);166             }167         }168         169         //需要找到当前频繁项子集170         for (ItemCollection itemCollection : current) {171             for (TransactionItem rest : restItems) {172                 if( ! itemCollection.containItem(rest) ){173                     //找到一个b 不属于 频繁项集 A 但是存在于剩余项中 用其构造其余的子项174                     extend.add( buildCollection( itemCollection, rest ));175                 }176             }177             178         }179         180         return extend;181     }182     183     //result = ic.items & item184     private ItemCollection buildCollection(ItemCollection ic,TransactionItem item){185         ItemCollection ex = new ItemCollection();186         187         Iterator<TransactionItem> it = ic.getItems().iterator();188         while(it.hasNext()){189             ex.add( it.next() );190         }191         192         ex.add(item);193         194         return ex;195     }196     197     198     //初始化剩余项199     private Set<ItemCollection> initCollection( int threadshold ){200         201         Map<TransactionItem , Integer> tc = new HashMap<Aprior.TransactionItem, Integer>();202         203         for ( Transaction t : transactions ) {204             205             for ( TransactionItem item : t.getItems() ) {206                 207                 if( !restItems.contains(item) ){208                     restItems.add(item);209                     tc.put(item, 1);210                 }else211                     tc.put( item, 1 + tc.get(item) );212                 213             }214         }215         216         217         Set<ItemCollection> collection = new HashSet<Aprior.ItemCollection>();218         219         Iterator< TransactionItem > it = tc.keySet().iterator();220         while( it.hasNext() ){221             TransactionItem item = it.next();222             if( threadshold <= tc.get( item ) ){223                 ItemCollection ic = new ItemCollection();224                 ic.add( item );225                 collection.add( ic );226             }227         }228             229         return collection;230     }231     232     233     /**234      * 找出频繁项235      * @param threadshold 最小支持度236      * @return237      */238     public Set< ItemCollection > frequentItem( int threadshold ){239         240         Set< ItemCollection > current = initCollection( threadshold );241         Set< ItemCollection > result = new HashSet<Aprior.ItemCollection>();242         243         while( current.size() > 0 ){244             245             result.addAll( current );246             247             Set<ItemCollection> extendList = extendItems( current );248             249             current = filterWithThreadshold( extendList, threadshold );250             251         }252         253         254         return result;255     }256     257     public void addTransaction(Transaction ts){258         transactions.add(ts);259     }260     261     262     public static void main(String args[]){263         264         final int MINSUPPROT = 2;265         Aprior aprior = new Aprior();266         /**267          * 数据集包括268          * T1 {1,3,4}269          * T2 {2,3,5}270          * T3 {1,2,3,5}271          * T4 {2,5}272          * 最小支持度为2,请最大频繁项273          */274         aprior.addTransaction(new Transaction(1, new ItemCollection(new int[]{1,3,4})));275         aprior.addTransaction(new Transaction(2, new ItemCollection(new int[]{2,3,5})));276         aprior.addTransaction(new Transaction(3, new ItemCollection(new int[]{1,2,3,5})));277         aprior.addTransaction(new Transaction(4, new ItemCollection(new int[]{2,5})));278         279         System.out.println(aprior.frequentItem( MINSUPPROT ));280         281     }282     283 284 }

 

参考资料

http://en.wikipedia.org/wiki/Apriori_algorithm

http://rakesh.agrawal-family.com/papers/vldb94apriori.pdf

http://www.cnblogs.com/gaizai/archive/2010/03/31/1701573.html