Apriori算法学习和java实现
来源:互联网 发布:普林斯顿数学指南 知乎 编辑:程序博客网 时间:2024/06/06 12:51
关联规则挖掘可以发现大量数据中项集之间有趣的关联或相关联系。一个典型的关联规则挖掘例子是购物篮分析,即通过发现顾客放入其购物篮中的不同商品之间的联系,分析顾客的购物习惯,从而可以帮助零售商指定营销策略,引导销售等。国外有"啤酒与尿布"的故事,国内有泡面和火腿的故事。
本文以Apriori算法为例介绍关联规则挖掘并以Java实现。
什么是关联规则:
对于记录的集合D和记录A,记录B,A,B属于D: A--->B [support(A->B)=p(AUB) ,confidence(A->B)=p(B|A) ]
关联规则的表示形式:
泡面 ------>火腿[support=0.2,confidence=0.8]
规则的支持度和置信度是两个规则兴趣度度量,它们分别反映发现规则的有用性和确定性。上式表示同时购买泡面和火腿的记录占全部记录的2%(实际应该没这么多的,不然天天吃泡面),置信度0.8表示在购买泡面的记录中,有80%的人同时购买火腿(反正我就是属于80%的。
如果挖掘的关联规则满足最小支持阈值和最小置信度阈值,则称关联规则是有趣的。
重要性质:频繁项集的所有非空子集都必须是频繁的。(一个集合如果不能通过测试,则它的所有超集也不能通过测试)
Apriori算法思想:逐层搜索的迭代方法,首先寻找1-项频繁集的集合,集合记做L1, L1用于寻找两项频繁集合L2,L2用于寻找L3,如此下去,直到不能找K项频繁集合。
1连接步;为找L(k) ,通过将L(k-1)与自身连接产生候选K项集的集合。
2减枝步;根据项的支持度计数去掉非频繁的候选集合,确定频繁集反复迭代直到不能产生满足最小支持度的集合为止。
Apriori重要性质:频繁项集的所有非空子集都必须是频繁的在减枝中的应用就在于,对于候选集只要它不是频繁的,就可以删除掉,这样大大减少数据量。下面直接上算法流程图:
下面举例说明:
package bao;import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; public class Example { public static void main(String[] args) throws Exception { // 初始化事务集 List<Set<String>> trans = new LinkedList<Set<String>>(); trans.add(new ItemSet(new String[] { "I1", "I2", "I5" })); trans.add(new ItemSet(new String[] { "I2", "I4" })); trans.add(new ItemSet(new String[] { "I2", "I3" })); trans.add(new ItemSet(new String[] { "I1", "I2", "I4" })); trans.add(new ItemSet(new String[] { "I1", "I3" })); trans.add(new ItemSet(new String[] { "I2", "I3" })); trans.add(new ItemSet(new String[] { "I1", "I3" })); trans.add(new ItemSet(new String[] { "I1", "I2", "I3", "I5" })); trans.add(new ItemSet(new String[] { "I1", "I2", "I3" })); int MSF = 2; // 设定最小支持频次为2 Map<Integer, Set<ItemSet>> rst = findFrequentItemSets(trans, MSF); // 输出频繁项集 System.out.println("Frequent Item Sets:"); for (Entry<Integer, Set<ItemSet>> entry : rst.entrySet()) { Integer itemSetSize = entry.getKey(); System.out.printf("Frequent %d Item Sets:\n", itemSetSize); for (ItemSet set : entry.getValue()) System.out.printf("%s, %d\n", set, set.frequence); } double MCONF = 0.6; // 设定最小置信度为60% Map<ItemSet, ItemSet> directMap = new HashMap<ItemSet, ItemSet>(); for (Entry<Integer, Set<ItemSet>> entry : rst.entrySet()) { for (ItemSet set : entry.getValue()) directMap.put(set, set); } // 根据频繁项集构造关联规则 System.out.println(); System.out.println("Association Rules:"); for (Entry<Integer, Set<ItemSet>> entry : rst.entrySet()) { for (ItemSet set : entry.getValue()) { double cnt1 = directMap.get(set).frequence; List<ItemSet> subSets = set.listNotEmptySubItemSets(); for (ItemSet subSet : subSets) { int cnt2 = directMap.get(subSet).frequence; double conf = cnt1 / cnt2; if (cnt1 / cnt2 >= MCONF) { ItemSet remainSet = new ItemSet(); remainSet.addAll(set); remainSet.removeAll(subSet); System.out.printf("%s => %s, %.2f\n", subSet, remainSet, conf); } } } } } /** * 查找事务集中的所有频繁项集,返回Map为:L -> 所有频繁L项集的列表 */ static Map<Integer, Set<ItemSet>> findFrequentItemSets( Iterable<Set<String>> transIterable, int MSF) { Map<Integer, Set<ItemSet>> ret = new TreeMap<Integer, Set<ItemSet>>(); // 首先确定频繁1项集 Iterator<Set<String>> it = transIterable.iterator(); Set<ItemSet> oneItemSets = findFrequentOneItemSets(it, MSF); ret.put(1, oneItemSets); int preItemSetSize = 1; Set<ItemSet> preItemSets = oneItemSets; // 基于获得的所有频繁L-1项集迭代查找所有频繁L项集,直到不存在频繁L-1项集 while (!preItemSets.isEmpty()) { int curItemSetSize = preItemSetSize + 1; // 获取频繁L项集的所有候选L项集 List<ItemSet> candidates = aprioriGenCandidates(preItemSets); // 扫描事务集以确定所有候选L项集出现的频次 it = transIterable.iterator(); while (it.hasNext()) { Set<String> tran = it.next(); for (ItemSet candidate : candidates) if (tran.containsAll(candidate)) candidate.frequence++; } // 将出现频次不小于最小支持频次的候选L项集选为频繁L项集 Set<ItemSet> curItemSets = new HashSet<ItemSet>(); for (ItemSet candidate : candidates) if (candidate.frequence >= MSF) curItemSets.add(candidate); if (!curItemSets.isEmpty()) ret.put(curItemSetSize, curItemSets); preItemSetSize = curItemSetSize; preItemSets = curItemSets; } return ret; } /** * 扫描事务集以确定频繁1项集 */ static Set<ItemSet> findFrequentOneItemSets(Iterator<Set<String>> trans, int MSF) { // 扫描事务集以确定各个项出现的频次 Map<String, Integer> frequences = new HashMap<String, Integer>(); while (trans.hasNext()) { Set<String> tran = trans.next(); for (String item : tran) { Integer frequence = frequences.get(item); frequence = frequence == null ? 1 : frequence + 1; frequences.put(item, frequence); } } // 用每个出现频次不小于最小支持频次的项构造一个频繁1项集 Set<ItemSet> ret = new HashSet<ItemSet>(); for (Entry<String, Integer> entry : frequences.entrySet()) { String item = entry.getKey(); Integer frequence = entry.getValue(); if (frequence >= MSF) { ItemSet set = new ItemSet(new String[] { item }); set.frequence = frequence; ret.add(set); } } return ret; } /** * 根据所有频繁L-1项集获得所有频繁L项集的候选L项集 */ static List<ItemSet> aprioriGenCandidates(Set<ItemSet> preItemSets) { List<ItemSet> ret = new LinkedList<ItemSet>(); // 尝试将所有频繁L-1项集两两连接然后作剪枝处理以获得候选L项集 for (ItemSet set1 : preItemSets) { for (ItemSet set2 : preItemSets) { if (set1 != set2 && set1.canMakeJoin(set2)) { // 连接 ItemSet union = new ItemSet(); union.addAll(set1); union.add(set2.last()); // 剪枝 boolean missSubSet = false; List<ItemSet> subItemSets = union.listDirectSubItemSets(); for (ItemSet itemSet : subItemSets) { if (!preItemSets.contains(itemSet)) { missSubSet = true; break; } } if (!missSubSet) ret.add(union); } } } return ret; } /** * 由多个项组成的项集,每个项是一个字符串。使用TreeSet使项集中的项有序,以辅助算法实现 */ static class ItemSet extends TreeSet<String> { private static final long serialVersionUID = 23883315835136949L; int frequence; // 项集出现的频次 public ItemSet() { this(new String[0]); } public ItemSet(String[] items) { for (String item : items) add(item); } /** * 测试本项集(假定阶为L-1)能否与别一个项集连接以生成L阶项集 */ public boolean canMakeJoin(ItemSet other) { // 若两个项集的阶不同,则不能连接生成L阶项集 if (other.size() != this.size()) return false; // 假定项集的阶为L-1,在项有序的前提下,当且仅当两个项集的前L-2个项相同 // 而本项集的第L-1个项小于另一个项集的第L-1个项时,可以连接生成L阶项集 Iterator<String> it1 = this.iterator(); Iterator<String> it2 = other.iterator(); while (it1.hasNext()) { String item1 = it1.next(); String item2 = it2.next(); int result = item1.compareTo(item2); if (result != 0) { if (it1.hasNext()) return false; return result < 0 ? true : false; } } return false; } /** * 假定本项集的阶为L,列举本项集的所有阶为L-1的子项集 */ public List<ItemSet> listDirectSubItemSets() { List<ItemSet> ret = new LinkedList<ItemSet>(); // 只有本项集的阶大于1,才可能存在非空子项集 if (size() > 1) { for (String rmItem : this) { ItemSet subSet = new ItemSet(); subSet.addAll(this); subSet.remove(rmItem); ret.add(subSet); } } return ret; } /** * 列出本项集除自身外的所有非空子项集 */ public List<ItemSet> listNotEmptySubItemSets() { List<ItemSet> ret = new LinkedList<ItemSet>(); int size = size(); if (size > 0) { char[] mapping = new char[size()]; initMapping(mapping); while (nextMapping(mapping)) { ItemSet set = new ItemSet(); Iterator<String> it = this.iterator(); for (int i = 0; i < size; i++) { String item = it.next(); if (mapping[i] == '1') set.add(item); } if (set.size() < size) ret.add(set); } } return ret; } private void initMapping(char[] mapping) { for (int i = 0; i < mapping.length; i++) mapping[i] = '0'; } private boolean nextMapping(char[] mapping) { int pos = 0; while (pos < mapping.length && mapping[pos] == '1') { mapping[pos] = '0'; pos++; } if (pos < mapping.length) { mapping[pos] = '1'; return true; } return false; } } }
- Apriori算法学习和java实现
- Apriori算法学习和java实现
- java实现Apriori算法
- Apriori算法实现(java)
- Apriori 算法 java 的实现
- Apriori算法Java实现示例
- Apriori算法的java实现
- Apriori算法的JAVA实现
- Apriori算法的Java实现
- Apriori和FPgrowth算法学习
- Apriori算法的java实现(星星学习笔记)
- java实现关联分析算法Apriori
- 数据挖掘apriori算法Java代码实现
- 数据挖掘apriori算法Java代码实现
- web挖掘之Apriori算法 JAVA实现
- Apriori算法----详细分析和代码实现
- 机器学习入门算法及其java实现-Apriori(文本关联性)算法
- Apriori算法实现
- 接着昨天的贪吃蛇
- WireShark教程
- thinkphp 中定制success和error提示跳转页面
- L1-034. 点赞
- (一)R语言环境安装与基本使用
- Apriori算法学习和java实现
- 关于FileReader和FileWriter
- WireShark教程 – 黑客发现之旅(3)
- 轻便的python
- error:declared inside parameter list
- 移动机器人入门篇
- WireShark教程 – 黑客发现之旅(4)
- Java连接MySQL数据库——含步骤和代码
- 插件编写