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

算法描述

  先验算法是实现频繁项挖掘的一种经典算法,利用关联式规则不断扩展频繁项子集以获得全部的频繁项集合。解释一下关联式规则,所谓关联式是指在大量的数据中找出的项与项之间的关系。例如消费者购买了产品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 [email protected]
 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 = i;
 26         }
 27
 28         @Override
 29         public boolean equals(Object obj) {
 30             TransactionItem it = (TransactionItem) obj;
 31             return this.itemValue == 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 & item
184     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                 }else
211                     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      * @return
237      */
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

数据挖掘经典算法——先验算法,布布扣,bubuko.com

时间: 2024-10-30 10:52:19

数据挖掘经典算法——先验算法的相关文章

数据挖掘经典算法——最大期望算法

算法定义 最大期望算法(Exception Maximization Algorithm,后文简称EM算法)是一种启发式的迭代算法,用于实现用样本对含有隐变量的模型的参数做极大似然估计.已知的概率模型内部存在隐含的变量,导致了不能直接用极大似然法来估计参数,EM算法就是通过迭代逼近的方式用实际的值带入求解模型内部参数的算法. 算法描述 算法的形式如下: 随机对参数赋予初值: While(求解参数不稳定){ E步骤:求在当前参数值和样本下的期望函数Q: M步骤:利用期望函数重新计算模型中新的估计值

先验算法(Apriori algorithm) - 机器学习算法

Apriori is an algorithm for frequent item set mining and association rule learning over transactional databases. It proceeds by identifying the frequent individual items in the database and extending them to larger and larger item sets as long as tho

《数据挖掘导论》实验课——实验七、数据挖掘之K-means聚类算法

实验七.数据挖掘之K-means聚类算法 一.实验目的 1. 理解K-means聚类算法的基本原理 2. 学会用python实现K-means算法 二.实验工具 1. Anaconda 2. sklearn 3. matplotlib 三.实验简介 1 K-means算法简介 k-means算法是一种聚类算法,所谓聚类,即根据相似性原则,将具有较高相似度的数据对象划分至同一类簇,将具有较高相异度的数据对象划分至不同类簇.聚类与分类最大的区别在于,聚类过程为无监督过程,即待处理数据对象没有任何先验

大公司面试经典数据结构与算法题C#解答

几个大公司(IBM.MicroSoft and so on)面试经典数据结构与算法题C#解答 1.链表反转 我想到了两种比较简单的方法 第一种是需要开一个新的链表,将原链表的元素从后到前的插入到新链表中(也就是原链表第一个元素被插入成新链表的最后一个元素). 第二种是不需要开新的链表,而是逐步反转原链表中元素的指向,例如: 原链表是 1->2->3->4->null  被  逐步修改为 ①2->1->null.3->4->null ②3->2->

数据挖掘十大算法--Apriori算法

一.Apriori 算法概述 Apriori 算法是一种最有影响力的挖掘布尔关联规则的频繁项集的 算法,它是由Rakesh Agrawal 和RamakrishnanSkrikant 提出的.它使用一种称作逐层搜索的迭代方法,k- 项集用于探索(k+1)- 项集.首先,找出频繁 1- 项集的集合.该集合记作L1.L1 用于找频繁2- 项集的集合 L2,而L2 用于找L2,如此下去,直到不能找到 k- 项集.每找一个 Lk 需要一次数据库扫描.为提高频繁项集逐层产生的效率,一种称作Apriori

数据挖掘之分类算法---knn算法(有matlab样例)

knn算法(k-Nearest Neighbor algorithm).是一种经典的分类算法. 注意,不是聚类算法.所以这样的分类算法必定包含了训练过程. 然而和一般性的分类算法不同,knn算法是一种懒惰算法.它并不是 像其它的分类算法先通过训练建立分类模型.,而是一种被动的分类 过程.它是边測试边训练建立分类模型. 算法的一般描写叙述步骤例如以下: 1.首先计算每一个測试样本点到其它每一个点的距离. 这个距离能够是欧氏距离,余弦距离等. 2. 然后取出距离小于设定的距离阈值的点. 这些点即为依

经典的排序算法

这些天复习了排序这个模块,排序算法在程序员的日常工作中是必不可少的,有时候我们不知不觉就用到了排序,这是因为高级语言系统已经比较完美的封装和优化了排序算法,并且在笔试,面试等方面我们都能见到它的身影.下面结合那本大三的教材:严版的<数据结构>,来说一说这几个经典的排序算法,如果有不对的欢迎指正! 首先我们还是先说基础概念(按书上说的),万变离不开概念,没有概念没有规矩,那可不行. 1:内部排序和外部排序(我们重点说内部排序(因为我们最常用到)) 内排序:在排序的时间数据对象全部存放在内存的排序

何恺明经典去雾算法

何恺明经典去雾算法 一:由简至美的最佳论文(作者:何恺明  视觉计算组) [视觉机器人:个人感觉学习他的经典算法固然很重要,但是他的解决问题的思路也是非常值得我们学习的] 那是2009年4月24日的早上,我收到了一封不同寻常的email.发信人是CVPR 2009的主席们,他们说我的文章获得了CVPR 2009的最佳论文奖(Best Paper Award).我反复阅读这封邮件以确认我没有理解错误.这真是一件令人难以置信的事情. 北京灰霾照片的去雾结果 CVPR的中文名是计算机视觉与模式识别会议

数据挖掘之分类算法---knn算法(有matlab例子)

knn算法(k-Nearest Neighbor algorithm).是一种经典的分类算法. 注意,不是聚类算法.所以这种分类算法必然包括了训练过程. 然而和一般性的分类算法不同,knn算法是一种懒惰算法.它并非 像其他的分类算法先通过训练建立分类模型.,而是一种被动的分类 过程.它是边测试边训练建立分类模型. 算法的一般描述过程如下: 1.首先计算每个测试样本点到其他每个点的距离. 这个距离可以是欧氏距离,余弦距离等. 2. 然后取出距离小于设定的距离阈值的点. 这些点即为根据阈值环绕在测试