Apriori算法的java实现

介绍

Apriori算法是一个经典的数据挖掘算法,Apriori的单词的意思是"先验的",说明这个算法是具有先验性质的,就是说要通过上一次的结果推导出下一次的结果,这个如何体现将会在下面的分析中会慢慢的体现出来。Apriori算法的用处是挖掘频繁项集的,频繁项集粗俗的理解就是找出经常出现的组合,然后根据这些组合最终推出我们的关联规则。

Apriori算法原理

Apriori算法是一种逐层搜索的迭代式算法,其中k项集用于挖掘(k+1)项集,这是依靠他的先验性质的:

频繁项集的所有非空子集一定是也是频繁的。

通过这个性质可以对候选集进行剪枝。用k项集如何生成(k+1)项集呢,这个是算法里面最难也是最核心的部分。

通过2个步骤

1、连接步,将频繁项自己与自己进行连接运算。

2、剪枝步,去除候选集项中的不符合要求的候选项,不符合要求指的是这个候选项的子集并非都是频繁项,要遵守上文提到的先验性质。

3、通过1,2步骤还不够,在后面还要根据支持度计数筛选掉不满足最小支持度数的候选集。


交易ID


商品ID列表


T100


I1,I2,I5


T200


I2,I4


T300


I2,I3


T400


I1,I2,I4


T500


I1,I3


T600


I2,I3


T700


I1,I3


T800


I1,I2,I3,I5


T900


I1,I2,I3

算法的步骤图:

算法的代码实现如下:

package com.gdut.mahao;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

public class Apriori {

	private final static int SUPPORT = 2; // 支持度阈值
	private final static double CONFIDENCE = 0.7; // 置信度阈值

	private final static String ITEM_SPLIT = ","; // 项之间的分隔符
	private final static String CON = "-->"; // 项之间的分隔符

	private final static List<String> transList = new ArrayList<String>(); // 所有交易

	static {// 初始化交易记录,在apriori算法中,应保证项集中的项是有序的
		transList.add("1,2,5,");
		transList.add("2,4,");
		transList.add("2,3,");
		transList.add("1,2,4,");
		transList.add("1,3,");
		transList.add("2,3,");
		transList.add("1,3,");
		transList.add("1,2,3,5,");
		transList.add("1,2,3,");
	}

	public Map<String, Integer> getFC() {
		Map<String, Integer> frequentCollectionMap = new HashMap<String, Integer>();// 所有的频繁集

		frequentCollectionMap.putAll(getItem1FC());

		Map<String, Integer> itemkFcMap = new HashMap<String, Integer>();
		itemkFcMap.putAll(getItem1FC());
		while (itemkFcMap != null && itemkFcMap.size() != 0) {
			Map<String, Integer> candidateCollection = getCandidateCollection(itemkFcMap);
			Set<String> ccKeySet = candidateCollection.keySet();
			// 对候选集项进行累加计数
			for (String trans : transList) {
				for (String candidate : ccKeySet) {
					boolean flag = true;// 用来判断交易中是否出现该候选项,如果出现,计数加1
					String[] candidateItems = candidate.split(ITEM_SPLIT);
					for (String candidateItem : candidateItems) {
						if (trans.indexOf(candidateItem + ITEM_SPLIT) == -1) {
							flag = false;
							break;
						}
					}
					if (flag) {
						Integer count = candidateCollection.get(candidate);
						candidateCollection.put(candidate, count + 1);
					}
				}
			}

			// 从候选集中找到符合支持度的频繁集项
			itemkFcMap.clear();
			for (String candidate : ccKeySet) {
				Integer count = candidateCollection.get(candidate);
				if (count >= SUPPORT) {
					itemkFcMap.put(candidate, count);
				}
			}
			// 合并所有频繁集
			frequentCollectionMap.putAll(itemkFcMap);
		}
		return frequentCollectionMap;
	}

	private Map<String, Integer> getCandidateCollection(
			Map<String, Integer> itemkFcMap) {
		Map<String, Integer> candidateCollection = new HashMap<String, Integer>();
		Set<String> itemkSet1 = itemkFcMap.keySet();
		Set<String> itemkSet2 = itemkFcMap.keySet();

		for (String itemk1 : itemkSet1) {
			for (String itemk2 : itemkSet2) {
				// 进行连接
				String[] tmp1 = itemk1.split(ITEM_SPLIT);
				String[] tmp2 = itemk2.split(ITEM_SPLIT);

				String c = "";
				if (tmp1.length == 1) {//itemkFcMap存放的是候选1项集集合时
					if (tmp1[0].compareTo(tmp2[0]) < 0) {
						c = tmp1[0] + ITEM_SPLIT + tmp2[0] + ITEM_SPLIT;
					}
				} else {
					boolean flag = true;//是否可以进行连接
					for (int i = 0; i < tmp1.length - 1; i++) {
						if (!tmp1[i].equals(tmp2[i])) {
							flag = false;
							break;
						}
					}
					if (flag && (tmp1[tmp1.length - 1].compareTo(tmp2[tmp2.length - 1]) < 0)) {
						c = itemk1 + tmp2[tmp2.length - 1] + ITEM_SPLIT;
					}
				}
				// 进行剪枝
				boolean hasInfrequentSubSet = false;// 是否有非频繁子项集,默认无
				if (!c.equals("")) {
					String[] tmpC = c.split(ITEM_SPLIT);
					//忽略的索引号ignoreIndex
					for (int ignoreIndex = 0; ignoreIndex < tmpC.length; ignoreIndex++) {
						String subC = "";
						for (int j = 0; j < tmpC.length; j++) {
							if (ignoreIndex != j) {
								subC +=  tmpC[j] + ITEM_SPLIT;
							}
						}
						if (itemkFcMap.get(subC) == null) {
							hasInfrequentSubSet = true;
							break;
						}
					}
				} else {
					hasInfrequentSubSet = true;
				}

				if (!hasInfrequentSubSet) {
					//把满足条件的候选项集添加到candidateCollection 集合中
					candidateCollection.put(c, 0);
				}
			}
		}
		return candidateCollection;
	}

	//得到频繁1项集
	private Map<String, Integer> getItem1FC() {
		Map<String, Integer> sItem1FcMap = new HashMap<String, Integer>();
		Map<String, Integer> rItem1FcMap = new HashMap<String, Integer>();// 频繁1项集

		for (String trans : transList) {
			String[] items = trans.split(ITEM_SPLIT);
			for (String item : items) {
				Integer count = sItem1FcMap.get(item + ITEM_SPLIT);
				if (count == null) {
					sItem1FcMap.put(item + ITEM_SPLIT, 1);
				} else {
					sItem1FcMap.put(item + ITEM_SPLIT, count + 1);
				}
			}
		}

		Set<String> keySet = sItem1FcMap.keySet();
		for (String key : keySet) {
			Integer count = sItem1FcMap.get(key);
			if (count >= SUPPORT) {
				rItem1FcMap.put(key, count);
			}
		}
		return rItem1FcMap;
	}

	//根据频繁项集集合得到关联规则
	public Map<String, Double> getRelationRules(
			Map<String, Integer> frequentCollectionMap) {
		Map<String, Double> relationRules = new HashMap<String, Double>();
		Set<String> keySet = frequentCollectionMap.keySet();
		for (String key : keySet) {
			double countAll = frequentCollectionMap.get(key);
			String[] keyItems = key.split(ITEM_SPLIT);
			if (keyItems.length > 1) {
				List<String> source = new ArrayList<String>();
				Collections.addAll(source, keyItems);
				List<Set<String>> result = new ArrayList<Set<String>>();
				buildSubSet(source, result);// 获得source的所有非空子集

				for (Set<String> itemList : result) {
					if (itemList.size() < source.size()) {// 只处理真子集
						List<String> otherList = new ArrayList<String>();//记录一个子集的补
						for (String sourceItem : source) {
							if (!itemList.contains(sourceItem)) {
								otherList.add(sourceItem);
							}
						}
						String reasonStr = "";// 规则的前置
						String resultStr = "";// 规则的结果
						for (String item : itemList) {
							reasonStr += item + ITEM_SPLIT;
						}
						for (String item : otherList) {
							resultStr = resultStr + item + ITEM_SPLIT;
						}
						double countReason = frequentCollectionMap
								.get(reasonStr);
						double itemConfidence = countAll / countReason;// 计算置信度
						//if (itemConfidence >= CONFIDENCE) {
							String rule = reasonStr + CON + resultStr;
							relationRules.put(rule, itemConfidence);
						//}
					}
				}
			}
		}
		return relationRules;
	}

	private void buildSubSet(List<String> sourceSet, List<Set<String>> result) {
		int n = sourceSet.size();
		//n个元素有2^n-1个非空子集
		int num = (int) Math.pow(2, n);
		for (int i = 1; i < num; i++) {
			String binary = Integer.toBinaryString(i);
			int size = binary.length();
			for (int k = 0; k < n-size; k++) {//将二进制表示字符串右对齐,左边补0
				binary = "0"+binary;
			}
			Set<String> set = new TreeSet<String>();
			for (int index = 0; index < sourceSet.size(); index++) {
				if(binary.charAt(index) == '1'){
					set.add(sourceSet.get(index));
				}
			}
			result.add(set);
		}
	}

	public static void main(String[] args) {
		Apriori apriori = new Apriori();
		Map<String, Integer> frequentCollectionMap = apriori.getFC();
		System.out.println("----------------频繁集" + "----------------");
		Set<String> fcKeySet = frequentCollectionMap.keySet();
		for (String fcKey : fcKeySet) {
			System.out.println(fcKey + "  :  "
					+ frequentCollectionMap.get(fcKey));
		}
		Map<String, Double> relationRulesMap = apriori
				.getRelationRules(frequentCollectionMap);
		System.out.println("----------------关联规则" + "----------------");
		Set<String> rrKeySet = relationRulesMap.keySet();
		for (String rrKey : rrKeySet) {
			System.out.println(rrKey + "  :  " + relationRulesMap.get(rrKey));
		}
	}

}

运行结果如下:

----------------频繁集----------------

3,  :  6

4,  :  2

5,  :  2

1,5,  :  2

1,2,  :  4

2,  :  7

1,3,  :  4

1,  :  6

2,5,  :  2

1,2,5,  :  2

2,3,  :  4

1,2,3,  :  2

2,4,  :  2

----------------关联规则----------------

2,3,-->1,  :  0.5

2,-->1,3,  :  0.2857142857142857

3,-->2,  :  0.6666666666666666

5,-->1,2,  :  1.0

2,5,-->1,  :  1.0

4,-->2,  :  1.0

2,-->1,5,  :  0.2857142857142857

5,-->2,  :  1.0

2,-->5,  :  0.2857142857142857

1,2,-->3,  :  0.5

1,-->2,3,  :  0.3333333333333333

5,-->1,  :  1.0

1,3,-->2,  :  0.5

1,2,-->5,  :  0.5

1,-->3,  :  0.6666666666666666

1,-->2,5,  :  0.3333333333333333

1,-->2,  :  0.6666666666666666

2,-->4,  :  0.2857142857142857

1,-->5,  :  0.3333333333333333

2,-->3,  :  0.5714285714285714

3,-->1,  :  0.6666666666666666

3,-->1,2,  :  0.3333333333333333

1,5,-->2,  :  1.0

2,-->1,  :  0.5714285714285714

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-08 19:57:06

Apriori算法的java实现的相关文章

Java实现Apriori算法

Apriori算法的Java实现,源码放在github上,大家有兴趣可以下下来看看, 源码地址: https://github.com/l294265421/algorithm-apriori 实现该算法主要阅读的书籍是: <Web数据挖掘>第二版,作者:Bing Liu,译者:俞勇 版权声明:本文为博主原创文章,未经博主允许不得转载.

Apriori算法学习和java实现

关联规则挖掘可以发现大量数据中项集之间有趣的关联或相关联系.一个典型的关联规则挖掘例子是购物篮分析,即通过发现顾客放入其购物篮中的不同商品之间的联系,分析顾客的购物习惯,从而可以帮助零售商指定营销策略,引导销售等.国外有"啤酒与尿布"的故事,国内有泡面和火腿的故事.本文以Apriori算法为例介绍关联规则挖掘并以java实现. 什么是关联规则: 对于记录的集合D和记录A,记录B,A,B属于D:  A--->B  [support(A->B)=p(AUB) ,confiden

频繁模式挖掘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算法--关联规则挖掘

我的数据挖掘算法代码:https://github.com/linyiqun/DataMiningAlgorithm 介绍 Apriori算法是一个经典的数据挖掘算法,Apriori的单词的意思是"先验的",说明这个算法是具有先验性质的,就是说要通过上一次的结果推导出下一次的结果,这个如何体现将会在下面的分析中会慢慢的体现出来.Apriori算法的用处是挖掘频繁项集的,频繁项集粗俗的理解就是找出经常出现的组合,然后根据这些组合最终推出我们的关联规则. Apriori算法原理 Aprio

玩转大数据:深入浅出大数据挖掘技术(Apriori算法、Tanagra工具、决策树)

一.本课程是怎么样的一门课程(全面介绍) 1.1.课程的背景 “大数据”作为时下最火热的IT行业的词汇,随之而来的数据仓库.数据分析.数据挖掘等等围绕大数据的商业价值的利用逐渐成为行业人士争相追捧的利润焦点. “大数据” 其实离我们的生活并不遥远,大到微博的海量用户信息,小到一个小区超市的月销售清单,都蕴含着大量潜在的商业价值. 正是由于数据量的快速增长,并且已经远远超过了人们的数据分析能力.因此,科学.商用等领域都迫切需要智能化.自动化的数据分析工具.在这样的背景下,数据挖掘技术应用而生,使得

利用Hbase的coprocessor实现增量式Apriori算法

Apriori在数据挖掘中是经典的频繁项集挖掘算法,其主要思想就是如果某个项集不频繁,则任何包含此项集的项集一定不频繁.而今天要实现的增量式的Apriori算法,有点像分布式的Apriori,因为我们可以把已挖掘的事务集和新增的事务集看作两个互相独立的数据集,挖掘新增的事务集,获取所有新增频繁集,然后与已有的频繁集做并集,对于两边都同时频繁的项集肯定全局频繁,而只有一边频繁的项集则需要统计其在两边的频繁计数,这样完成后就能获得所有的全局频繁集,并不需要重新挖掘已有的事务集,效率必然提高. 至于H

Apriori算法例子

1 Apriori介绍 Apriori算法使用频繁项集的先验知识,使用一种称作逐层搜索的迭代方法,k项集用于探索(k+1)项集.首先,通过扫描事务(交易)记录,找出所有的频繁1项集,该集合记做L1,然后利用L1找频繁2项集的集合L2,L2找L3,如此下去,直到不能再找到任何频繁k项集.最后再在所有的频繁集中找出强规则,即产生用户感兴趣的关联规则. 其中,Apriori算法具有这样一条性质:任一频繁项集的所有非空子集也必须是频繁的.因为假如P(I)< 最小支持度阈值,当有元素A添加到I中时,结果项

8皇后以及N皇后算法探究,回溯算法的JAVA实现,非递归,循环控制及其优化

上两篇博客 8皇后以及N皇后算法探究,回溯算法的JAVA实现,递归方案 8皇后以及N皇后算法探究,回溯算法的JAVA实现,非递归,数据结构“栈”实现 研究了递归方法实现回溯,解决N皇后问题,下面我们来探讨一下非递归方案 实验结果令人还是有些失望,原来非递归方案的性能并不比递归方案性能高 代码如下: package com.newflypig.eightqueen; import java.util.Date; /** * 使用循环控制来实现回溯,解决N皇后 * @author [email pr

机器学习(八)—Apriori算法

摘要:本文对Apriori算法进行了简单介绍,并通过Python进行实现,进而结合UCI数据库中的肋形蘑菇数据集对算法进行验证. “啤酒与尿布”的例子相信很多人都听说过吧,故事是这样的:在一家超市中,人们发现了一个特别有趣的现象,尿布与啤酒这两种风马牛不相及的商品居然摆在一起.但这一奇怪的举措居然使尿布和啤酒的销量大幅增加了.这可不是一个笑话,而是一直被商家所津津乐道的发生在美国沃尔玛连锁超市的真实案例.原来,美国的妇女通常在家照顾孩子,所以她们经常会嘱咐丈夫在下班回家的路上为孩子买尿布,而丈夫