apriori java_频繁模式挖掘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]

剪枝步: CK是LK的超集,也就是说,CK的成员可能是也可能不是频繁的。

通过扫描全部的事务(交易),确定CK中每一个候选的计数,推断是否小于最小支持度计数,假设不是。则觉得该候选是频繁的。为了压缩Ck,能够利用Apriori性质:任一频繁项集的全部非空子集也必须是频繁的,反之,假设某个候选的非空子集不是频繁的,那么该候选肯定不是频繁的,从而能够将其从CK中删除。

(该步利用了标红的先验性质)

图例

abb1ea47ec6fffb578ae7c555f0ac58a.png

伪代码

算法: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]

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 apriori(ArrayList dataList)

{

Map stepFrequentSetMap = new HashMap<>();

stepFrequentSetMap.putAll(findFrequentOneSets(dataList));

Map frequentSetMap = new HashMap();//频繁项集

frequentSetMap.putAll(stepFrequentSetMap);

while(stepFrequentSetMap!=null && stepFrequentSetMap.size()>0)

{

Map candidateSetMap = aprioriGen(stepFrequentSetMap);

Set 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 findFrequentOneSets(ArrayList dataList)

{

Map 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 aprioriGen(Map setMap)

{

Map candidateSetMap = new HashMap<>();

Set 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

{

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 setMap)

{

String[] strings = candidateSet.split(ITEM_SPLIT);

//找出候选集全部的子集,并推断每一个子集是否属于频繁子集

for(int i=0;i

{

String subString = "";

for(int j=0;j

{

if(j!=i)

{

subString += strings[j]+ITEM_SPLIT;

}

}

if(setMap.get(subString)==null)

return true;

}

return false;

}

/**

* 由频繁项集产生关联规则

* @param frequentSetMap

* @return

*/

public Map getRelationRules(Map frequentSetMap)

{

Map relationsMap = new HashMap<>();

Set keySet = frequentSetMap.keySet();

for(String key:keySet)

{

List 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 subset(String sourceSet)

{

List result = new ArrayList<>();

String[] strings = sourceSet.split(ITEM_SPLIT);

//非空真子集

for(int i=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

{

boolean flag = true;

for(int j=0;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 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 frequentSetMap = apriori2.apriori(dataList);

Set keySet = frequentSetMap.keySet();

for(String key:keySet)

{

System.out.println(key+" : "+frequentSetMap.get(key));

}

System.out.println("=关联规则==========");

Map relationRulesMap = apriori2.getRelationRules(frequentSetMap);

Set 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

数据挖掘:概念与技术

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值