频繁模式挖掘apriori算法介绍及Java实现
频繁模式是频繁地出如今数据集中的模式(如项集、子序列或者子结构)。比如。频繁地同一时候出如今交易数据集中的商品(如牛奶和面包)的集合是频繁项集。
一些基本概念
支持度:support(A=>B)=P(A并B)
置信度:confidence(A=>B)=P(B|A)
频繁k项集:假设项集I的支持度满足提前定义的最小支持度阈值。则称I为频繁项集,包括k个项的项集称为k项集。
算法思想
Apriori算法是Agrawal和R. Srikant于1994年提出。为布尔关联规则挖掘频繁项集的原创性算法。
通过名字能够看出算法基于这样一个事实:算法使用频繁项集性质的先验知识。
apriori算法使用一种成为逐层搜索的迭代算法,当中k项集用于探索(k+1)项集。首先,通过扫描数据库,累计每一个项的计数。并搜集满足最小支持度的项,找出频繁1项集的集合。该集合记为L1。然后,使用L1找出频繁2项集的集合L2,使用L2找出L3。如此下去,直到不能再找到频繁k项集。
能够想象。该算法基本思路计算复杂度是很大的。为了提高频繁项集的产生效率,使用先验性质(频繁项集的全部非空子集也一定是频繁的;换句话说。若某个集合存在一个非空子集不是频繁项集,则该集合不是频繁项集)来压缩搜索空间。
怎样在算法中使用先验性质?为了理解这一点。我们考察怎样使用Lk-1找出Lk,当中k>=2。
主要由两步构成:连接步和剪枝步。
连接步:为找出Lk。通过将Lk-1与自身相连接产生候选集k项集的集合。
该候选集的集合记为Ck。设l1和l2是Lk-1中的项集。记号li[j]表示li的第j项(比如。l1[k-2]表示l1的倒数第2项)。为了有效实现。apriori算法假定事务或项集中的项按字典序排列。
对于(k-1)项集li,这意味着把项排序,使得li[1]<li[2]<...<li[k-1]。连接Lk-1和Lk-1;当中Lk-1的元素是可连接的。假设它们前(k-2)项同样。即Lk-1的元素l1和l2是可连接的,假设(l1[1]=l2[1])^(l1[2]=l2[2])^...^(l1[k-2]=l2[k-2])^(l1[k-1]<l2[k-1])。条件l1[k-1]<l2[k-1]是简单保证不产生反复。连接l1和l2产生的结果项集是{l1[1],l1[2],...,l1[k-1],l2[k-1]}
剪枝步: CK是LK的超集,也就是说,CK的成员可能是也可能不是频繁的。
通过扫描全部的事务(交易),确定CK中每一个候选的计数,推断是否小于最小支持度计数,假设不是。则觉得该候选是频繁的。为了压缩Ck,能够利用Apriori性质:任一频繁项集的全部非空子集也必须是频繁的,反之,假设某个候选的非空子集不是频繁的,那么该候选肯定不是频繁的,从而能够将其从CK中删除。
(该步利用了标红的先验性质)
图例
伪代码
- 算法:Apriori
- 输入:D - 事务数据库;min_sup - 最小支持度计数阈值
- 输出:L - D中的频繁项集
- 方法:
- L1=find_frequent_1-itemsets(D); // 找出全部频繁1项集
- For(k=2;Lk-1!=null;k++){
- Ck=apriori_gen(Lk-1); // 产生候选,并剪枝
- For each 事务t in D{ // 扫描D进行候选计数
- Ct =subset(Ck,t); // 得到t的子集
- For each 候选c 属于 Ct
- c.count++;
- }
- Lk={c属于Ck | c.count>=min_sup}
- }
- Return L=全部的频繁集;
- Procedure apriori_gen(Lk-1:frequent(k-1)-itemsets)
- For each项集l1属于Lk-1
- For each项集 l2属于Lk-1
- If((l1[1]=l2[1])&&( l1[2]=l2[2])&&…….
- && (l1[k-2]=l2[k-2])&&(l1[k-1]<l2[k-1])) then{
- c=l1连接l2 //连接步:产生候选
- if has_infrequent_subset(c,Lk-1) then
- delete c; //剪枝步:删除非频繁候选
- else add c to Ck;
- }
- Return Ck;
- Procedure has_infrequent_sub(c:candidate k-itemset; Lk-1:frequent(k-1)-itemsets)
- For each(k-1)-subset s of c
- If s不属于Lk-1 then
- Return true;
- Return false;
Java实现
该java代码基本上是严格依照伪代码的流程写的。比較easy理解。
- package com.zhyoulun.apriori;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- public class Apriori2
- {
- private final static int SUPPORT = 2; // 支持度阈值
- private final static double CONFIDENCE = 0.7; // 置信度阈值
- private final static String ITEM_SPLIT = ";"; // 项之间的分隔符
- private final static String CON = "->"; // 项之间的分隔符
- /**
- * 算法主程序
- * @param dataList
- * @return
- */
- public Map<String, Integer> apriori(ArrayList<String> dataList)
- {
- Map<String, Integer> stepFrequentSetMap = new HashMap<>();
- stepFrequentSetMap.putAll(findFrequentOneSets(dataList));
- Map<String, Integer> frequentSetMap = new HashMap<String, Integer>();//频繁项集
- frequentSetMap.putAll(stepFrequentSetMap);
- while(stepFrequentSetMap!=null && stepFrequentSetMap.size()>0)
- {
- Map<String, Integer> candidateSetMap = aprioriGen(stepFrequentSetMap);
- Set<String> candidateKeySet = candidateSetMap.keySet();
- //扫描D,进行计数
- for(String data:dataList)
- {
- for(String candidate:candidateKeySet)
- {
- boolean flag = true;
- String[] strings = candidate.split(ITEM_SPLIT);
- for(String string:strings)
- {
- if(data.indexOf(string+ITEM_SPLIT)==-1)
- {
- flag = false;
- break;
- }
- }
- if(flag)
- candidateSetMap.put(candidate, candidateSetMap.get(candidate)+1);
- }
- }
- //从候选集中找到符合支持度的频繁项集
- stepFrequentSetMap.clear();
- for(String candidate:candidateKeySet)
- {
- Integer count = candidateSetMap.get(candidate);
- if(count>=SUPPORT)
- stepFrequentSetMap.put(candidate, count);
- }
- // 合并全部频繁集
- frequentSetMap.putAll(stepFrequentSetMap);
- }
- return frequentSetMap;
- }
- /**
- * find frequent 1 itemsets
- * @param dataList
- * @return
- */
- private Map<String, Integer> findFrequentOneSets(ArrayList<String> dataList)
- {
- Map<String, Integer> resultSetMap = new HashMap<>();
- for(String data:dataList)
- {
- String[] strings = data.split(ITEM_SPLIT);
- for(String string:strings)
- {
- string += ITEM_SPLIT;
- if(resultSetMap.get(string)==null)
- {
- resultSetMap.put(string, 1);
- }
- else {
- resultSetMap.put(string, resultSetMap.get(string)+1);
- }
- }
- }
- return resultSetMap;
- }
- /**
- * 依据上一步的频繁项集的集合选出候选集
- * @param setMap
- * @return
- */
- private Map<String, Integer> aprioriGen(Map<String, Integer> setMap)
- {
- Map<String, Integer> candidateSetMap = new HashMap<>();
- Set<String> candidateSet = setMap.keySet();
- for(String s1:candidateSet)
- {
- String[] strings1 = s1.split(ITEM_SPLIT);
- String s1String = "";
- for(String temp:strings1)
- s1String += temp+ITEM_SPLIT;
- for(String s2:candidateSet)
- {
- String[] strings2 = s2.split(ITEM_SPLIT);
- boolean flag = true;
- for(int i=0;i<strings1.length-1;i++)
- {
- if(strings1[i].compareTo(strings2[i])!=0)
- {
- flag = false;
- break;
- }
- }
- if(flag && strings1[strings1.length-1].compareTo(strings2[strings1.length-1])<0)
- {
- //连接步:产生候选
- String c = s1String+strings2[strings2.length-1]+ITEM_SPLIT;
- if(hasInfrequentSubset(c, setMap))
- {
- //剪枝步:删除非频繁的候选
- }
- else {
- candidateSetMap.put(c, 0);
- }
- }
- }
- }
- return candidateSetMap;
- }
- /**
- * 使用先验知识,推断候选集是否是频繁项集
- * @param candidate
- * @param setMap
- * @return
- */
- private boolean hasInfrequentSubset(String candidateSet, Map<String, Integer> setMap)
- {
- String[] strings = candidateSet.split(ITEM_SPLIT);
- //找出候选集全部的子集,并推断每一个子集是否属于频繁子集
- for(int i=0;i<strings.length;i++)
- {
- String subString = "";
- for(int j=0;j<strings.length;j++)
- {
- if(j!=i)
- {
- subString += strings[j]+ITEM_SPLIT;
- }
- }
- if(setMap.get(subString)==null)
- return true;
- }
- return false;
- }
- /**
- * 由频繁项集产生关联规则
- * @param frequentSetMap
- * @return
- */
- public Map<String, Double> getRelationRules(Map<String, Integer> frequentSetMap)
- {
- Map<String, Double> relationsMap = new HashMap<>();
- Set<String> keySet = frequentSetMap.keySet();
- for(String key:keySet)
- {
- List<String> keySubset = subset(key);
- for(String keySubsetItem:keySubset)
- {
- //子集keySubsetItem也是频繁项
- Integer count = frequentSetMap.get(keySubsetItem);
- if(count!=null)
- {
- Double confidence = (1.0*frequentSetMap.get(key))/(1.0*frequentSetMap.get(keySubsetItem));
- if(confidence>CONFIDENCE)
- relationsMap.put(keySubsetItem+CON+expect(key, keySubsetItem), confidence);
- }
- }
- }
- return relationsMap;
- }
- /**
- * 求一个集合全部的非空真子集
- *
- * @param sourceSet
- * @return
- * 为了以后能够用在其它地方。这里我们不是用递归的方法
- *
- * 參考:http://blog.163.com/xiaohui_1123@126/blog/static/3980524020109784356915/
- * 思路:如果集合S(A,B,C,D)。其大小为4。拥有2的4次方个子集,即0-15,二进制表示为0000,0001。...,1111。
- * 相应的子集为空集。{D},...。{A,B,C,D}。
- */
- private List<String> subset(String sourceSet)
- {
- List<String> result = new ArrayList<>();
- String[] strings = sourceSet.split(ITEM_SPLIT);
- //非空真子集
- for(int i=1;i<(int)(Math.pow(2, strings.length))-1;i++)
- {
- String item = "";
- String flag = "";
- int ii=i;
- do
- {
- flag += ""+ii%2;
- ii = ii/2;
- } while (ii>0);
- for(int j=flag.length()-1;j>=0;j--)
- {
- if(flag.charAt(j)=='1')
- {
- item = strings[j]+ITEM_SPLIT+item;
- }
- }
- result.add(item);
- }
- return result;
- }
- /**
- * 集合运算,A/B
- * @param A
- * @param B
- * @return
- */
- private String expect(String stringA,String stringB)
- {
- String result = "";
- String[] stringAs = stringA.split(ITEM_SPLIT);
- String[] stringBs = stringB.split(ITEM_SPLIT);
- for(int i=0;i<stringAs.length;i++)
- {
- boolean flag = true;
- for(int j=0;j<stringBs.length;j++)
- {
- if(stringAs[i].compareTo(stringBs[j])==0)
- {
- flag = false;
- break;
- }
- }
- if(flag)
- result += stringAs[i]+ITEM_SPLIT;
- }
- return result;
- }
- public static void main(String[] args)
- {
- ArrayList<String> dataList = new ArrayList<>();
- dataList.add("1;2;5;");
- dataList.add("2;4;");
- dataList.add("2;3;");
- dataList.add("1;2;4;");
- dataList.add("1;3;");
- dataList.add("2;3;");
- dataList.add("1;3;");
- dataList.add("1;2;3;5;");
- dataList.add("1;2;3;");
- System.out.println("=数据集合==========");
- for(String string:dataList)
- {
- System.out.println(string);
- }
- Apriori2 apriori2 = new Apriori2();
- System.out.println("=频繁项集==========");
- Map<String, Integer> frequentSetMap = apriori2.apriori(dataList);
- Set<String> keySet = frequentSetMap.keySet();
- for(String key:keySet)
- {
- System.out.println(key+" : "+frequentSetMap.get(key));
- }
- System.out.println("=关联规则==========");
- Map<String, Double> relationRulesMap = apriori2.getRelationRules(frequentSetMap);
- Set<String> rrKeySet = relationRulesMap.keySet();
- for (String rrKey : rrKeySet)
- {
- System.out.println(rrKey + " : " + relationRulesMap.get(rrKey));
- }
- }
- }
计算结果
- =数据集合==========
- 1;2;5;
- 2;4;
- 2;3;
- 1;2;4;
- 1;3;
- 2;3;
- 1;3;
- 1;2;3;5;
- 1;2;3;
- =频繁项集==========
- 1;2; : 4
- 1;3; : 4
- 5; : 2
- 2;3; : 4
- 4; : 2
- 2;4; : 2
- 1;5; : 2
- 3; : 6
- 2; : 7
- 1; : 6
- 1;2;5; : 2
- 1;2;3; : 2
- 2;5; : 2
- =关联规则==========
- 4;->2; : 1.0
- 5;->1;2; : 1.0
- 5;->1; : 1.0
- 1;5;->2; : 1.0
- 5;->2; : 1.0
- 2;5;->1; : 1.0
參考:
http://blog.csdn.net/zjd950131/article/details/8071414
http://www.cnblogs.com/zacard-orc/p/3646979.html
数据挖掘:概念与技术
转载请注明出处:http://blog.csdn.net/zhyoulun/article/details/41978401
频繁模式挖掘apriori算法介绍及Java实现的更多相关文章
- 频繁模式挖掘 Apriori算法 FP-tree
啤酒 尿布 组合营销 X=>Y,其中x属于项集I,Y属于项集I,且X.Y的交集等于空集. 2类算法 Apriori算法 不断地构造候选集.筛选候选集来挖掘出频繁项集,需要多次扫描原始数据.磁盘I ...
- 数据挖掘(七):Apriori算法:频繁模式挖掘
1 算法思想 算法使用频繁项集性质的先验知识.Apriori使用一种称作逐层搜索的迭代方法,k项集用于探索(k+1)项集.首先,通过扫描数据库,累积每个项的计数,并收集满足最小支持度的项,找出频繁1项 ...
- 频繁模式挖掘中Apriori、FP-Growth和Eclat算法的实现和对比
最近上数据挖掘的课程,其中学习到了频繁模式挖掘这一章,这章介绍了三种算法,Apriori.FP-Growth和Eclat算法:由于对于不同的数据来说,这三种算法的表现不同,所以我们本次就对这三种算法在 ...
- 频繁模式挖掘中Apriori、FP-Growth和Eclat算法的实现和对比(Python实现)
最近上数据挖掘的课程,其中学习到了频繁模式挖掘这一章,这章介绍了三种算法,Apriori.FP-Growth和Eclat算法:由于对于不同的数据来说,这三种算法的表现不同,所以我们本次就对这三种算法在 ...
- 【甘道夫】并行化频繁模式挖掘算法FP Growth及其在Mahout下的命令使用
今天调研了并行化频繁模式挖掘算法PFP Growth及其在Mahout下的命令使用,简单记录下试验结果,供以后查阅: 环境:Jdk1.7 + Hadoop2.2.0单机伪集群 + Mahout0.6 ...
- 八、频繁模式挖掘Frequent Pattern Mining
频繁模式挖掘(Frequent Pattern Mining): 频繁项集挖掘是通常是大规模数据分析的第一步,多年以来它都是数据挖掘领域的活跃研究主题.建议用户参考维基百科的association r ...
- 关联规则—频繁项集Apriori算法
频繁模式和对应的关联或相关规则在一定程度上刻画了属性条件与类标号之间的有趣联系,因此将关联规则挖掘用于分类也会产生比较好的效果.关联规则就是在给定训练项集上频繁出现的项集与项集之间的一种紧密的联系.其 ...
- Apriori算法介绍(Python实现)
导读: 随着大数据概念的火热,啤酒与尿布的故事广为人知.我们如何发现买啤酒的人往往也会买尿布这一规律?数据挖掘中的用于挖掘频繁项集和关联规则的Apriori算法可以告诉我们.本文首先对Apriori算 ...
- 推荐系统第4周--- 基于频繁模式的推荐系统和关联规则挖掘Apriori算法
数据挖掘:关联规则挖掘
随机推荐
- Android基础&进阶
http://blog.csdn.net/liuhe688/article/details/9494411
- Android学习总结——欢迎页和导航页的实现
activity_welcome.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayo ...
- Spark MLlib Deep Learning Deep Belief Network (深度学习-深度信念网络)2.3
Spark MLlib Deep Learning Deep Belief Network (深度学习-深度信念网络)2.3 http://blog.csdn.net/sunbow0 第二章Deep ...
- 在OC和Swift中使用IBDesignable/IBInspectable
iOS8新特性IBDesignable/IBInspectable,可以直接在XIB或者Storyboard中直接,设置UI类的属性.例 如:UIView.layer.borderWidth.bord ...
- 《JavaScript 闯关记》之事件
JavaScript 程序采用了异步事件驱动编程模型.在这种程序设计风格下,当文档.浏览器.元素或与之相关的对象发生某些有趣的事情时,Web 浏览器就会产生事件(event).例如,当 Web 浏览器 ...
- JS判断RadioButtonList是否有选中项
提交表单之前对RadioButtonList控件的选中项进行判断: 方法一: <script type="text/javascript"> function chec ...
- C#实现防拷贝工具示例
思路是用加密程序 对硬盘号,cpu号和MAC号取出字符串并加密 产生一个序列号 每次程序启动后重新产生这个序列号并比对,如果一致则验证通过 using System;using System.Coll ...
- Eclipse闪退解决办法
解决方式: 1.通过在命令行中输入“where java”,找到除jdk目录下的所有java相关程序,直接删掉(一般会在C:\WINDOWS\system32下) 2.内存不足,打开Eclipse目录 ...
- PHP学习笔记二十四【Get Set】
<?php Class Person{ private $n1; private $n2; private $n3; //使用__set方法来管理所有的属性 public function __ ...
- C++文件
参考: C++文件读写详解(ofstream,ifstream,fstream):http://blog.csdn.net/kingstar158/article/details/6859379 fs ...