使用Apriori进行关联分析(二)

使用Apriori进行关联分析(二)

  书接上文(使用Apriori进行关联分析(一)),介绍如何挖掘关联规则。

发现关联规则

  我们的目标是通过频繁项集挖掘到隐藏的关联规则。

  所谓关联规则,指通过某个元素集推导出另一个元素集。比如有一个频繁项集{底板,胶皮,胶水},那么一个可能的关联规则是{底板,胶皮}→{胶水},即如果客户购买了底板和胶皮,则该客户有较大概率购买胶水。这个频繁项集可以推导出6个关联规则:

  {底板,胶水}→{胶皮},

  {底板,胶皮}→{胶水},

  {胶皮,胶水}→{底板},

  {底板}→{胶水, 胶皮},

  {胶水}→{底板, 胶皮},

  {胶皮}→{底板, 胶水}

  箭头左边的集合称为“前件”,右边集合称为“后件”,根据前件会有较大概率推导出后件,这个概率就是之前提到的置信度。需要注意的是,如果A→B成立,B→A不一定成立。

  一个具有N个元素的频繁项集,共有M个可能的关联规则:

  下图是一个频繁4项集的所有关联规则网格示意图, 

  上图中深色区域表示低可信度规则,如果012→3是一条低可信度规则,则所有其它3为后件的规则都是低可信度。这需要从可信度的概念去理解,Confidence(012→3) = P(3|0,1,2),Confidence(01→23)=P(2,3|0,1),P(3|0,1,2) >= P(2,3|0,1)。由此可以对关联规则做剪枝处理。

  还是以上篇的超市交易数据为例,我们发现了如下的频繁项集:

  对于寻找关联规则来说,频繁1项集L1没有用处,因为L1中的每个集合仅有一个数据项,至少有两个数据项才能生成A→B这样的关联规则。

  当最小置信度取0.5时,L2最终能够挖掘出9条关联规则:

  从频繁3项集开始,挖掘的过程就较为复杂。

  假设有一个频繁4项集(这是杜撰的,文中的数据不能生成L4),其挖掘过程如下:

  因为书中的代码假设购买商品是有顺序的,所以在生成3后件时,{P2,P4}和{P3,P4}并不能生成{P2,P23,P4},如果想去掉假设,需要使用上篇中改进后的代码。

  发掘关联规则的代码如下:

复制代码
 1 #生成关联规则
 2 #L: 频繁项集列表
 3 #supportData: 包含频繁项集支持数据的字典
 4 #minConf 最小置信度
 5 def generateRules(L, supportData, minConf=0.7):
 6     #包含置信度的规则列表
 7     bigRuleList = []
 8     #从频繁二项集开始遍历
 9     for i in range(1, len(L)):
10         for freqSet in L[i]:
11             H1 = [frozenset([item]) for item in freqSet]
12             if (i > 1):
13                 rulesFromConseq(freqSet, H1, supportData, bigRuleList, minConf)
14             else:
15                 calcConf(freqSet, H1, supportData, bigRuleList, minConf)
16     return bigRuleList
17 
18 
19 # 计算是否满足最小可信度
20 def calcConf(freqSet, H, supportData, brl, minConf=0.7):
21     prunedH = []
22     #用每个conseq作为后件
23     for conseq in H:
24         # 计算置信度
25         conf = supportData[freqSet] / supportData[freqSet - conseq]
26         if conf >= minConf:
27             print(freqSet - conseq, '-->', conseq, 'conf:', conf)
28             # 元组中的三个元素:前件、后件、置信度
29             brl.append((freqSet - conseq, conseq, conf))
30             prunedH.append(conseq)
31 
32     #返回后件列表
33     return prunedH
34 
35 
36 # 对规则进行评估
37 def rulesFromConseq(freqSet, H, supportData, brl, minConf=0.7):
38     m = len(H[0])
39     if (len(freqSet) > (m + 1)):
40         Hmp1 = aprioriGen(H, m + 1)
41        # print(1,H, Hmp1)
42         Hmp1 = calcConf(freqSet, Hmp1, supportData, brl, minConf)
43         if (len(Hmp1) > 0):
44             rulesFromConseq(freqSet, Hmp1, supportData, brl, minConf)
复制代码

 

  由此可以看到,apriori算法需要经常扫描全表,效率并不算高。

Apriori算法是一种基于频繁项集的关联规则挖掘算法,它可以用来发现事物之间的相关性,并且在市场营销、销售预测、商品推荐等领域都有广泛的应用。 Java中实现Apriori算法主要分为以下步骤: 1. 数据预处理:将原始数据转化为事务集合形式,每个事务包含多个项,项之间用逗号或其他符号分隔。 2. 建立候选项集:根据用户设定的最小支持度阈值,生成大小为1的候选项集。 3. 频繁项集生成:根据候选项集和事务数据集,计算每个项集的支持度,并根据最小支持度阈值筛选出频繁项集。 4. 关联规则挖掘:根据频繁项集,生成关联规则,并计算每个规则的置信度和支持度。 以下是一个简单的Java代码实现: ``` public class Apriori { // 计算候选项集 public static List<Set<String>> candidateSet(List<Set<String>> frequentItemSets) { List<Set<String>> candidateSets = new ArrayList<>(); for (int i = 0; i < frequentItemSets.size(); i++) { for (int j = i + 1; j < frequentItemSets.size(); j++) { Set<String> set1 = frequentItemSets.get(i); Set<String> set2 = frequentItemSets.get(j); // 求并集 Set<String> candidateSet = new HashSet<>(set1); candidateSet.addAll(set2); if (candidateSet.size() == set1.size() + 1) { candidateSets.add(candidateSet); } } } return candidateSets; } // 计算支持度 public static int supportCount(List<Set<String>> transactions, Set<String> itemSet) { int count = 0; for (Set<String> transaction : transactions) { if (transaction.containsAll(itemSet)) { count++; } } return count; } // 计算频繁项集 public static List<Set<String>> frequentItemSet(List<Set<String>> transactions, double minSupport) { List<Set<String>> frequentItemSets = new ArrayList<>(); Map<Set<String>, Integer> itemSetCount = new HashMap<>(); // 统计每个项集的支持度计数 for (Set<String> transaction : transactions) { for (String item : transaction) { Set<String> itemSet = new HashSet<>(); itemSet.add(item); if (itemSetCount.containsKey(itemSet)) { itemSetCount.put(itemSet, itemSetCount.get(itemSet) + 1); } else { itemSetCount.put(itemSet, 1); } } } // 获得频繁项集 for (Set<String> itemSet : itemSetCount.keySet()) { double support = (double) itemSetCount.get(itemSet) / transactions.size(); if (support >= minSupport) { frequentItemSets.add(itemSet); } } // 迭代计算频繁项集 List<Set<String>> lastItemSets = frequentItemSets; while (!lastItemSets.isEmpty()) { List<Set<String>> candidateSets = candidateSet(lastItemSets); itemSetCount.clear(); for (Set<String> transaction : transactions) { for (Set<String> candidateSet : candidateSets) { if (transaction.containsAll(candidateSet)) { if (itemSetCount.containsKey(candidateSet)) { itemSetCount.put(candidateSet, itemSetCount.get(candidateSet) + 1); } else { itemSetCount.put(candidateSet, 1); } } } } lastItemSets = new ArrayList<>(); for (Set<String> itemSet : itemSetCount.keySet()) { double support = (double) itemSetCount.get(itemSet) / transactions.size(); if (support >= minSupport) { frequentItemSets.add(itemSet); lastItemSets.add(itemSet); } } } return frequentItemSets; } // 计算关联规则 public static List<Rule> associationRules(List<Set<String>> transactions, double minSupport, double minConfidence) { List<Rule> rules = new ArrayList<>(); List<Set<String>> frequentItemSets = frequentItemSet(transactions, minSupport); for (Set<String> frequentItemSet : frequentItemSets) { if (frequentItemSet.size() > 1) { List<Set<String>> subSets = getSubSets(frequentItemSet); for (Set<String> subSet : subSets) { Set<String> complementSet = new HashSet<>(frequentItemSet); complementSet.removeAll(subSet); double confidence = (double) supportCount(transactions, frequentItemSet) / supportCount(transactions, subSet); if (confidence >= minConfidence) { rules.add(new Rule(subSet, complementSet, confidence)); } } } } return rules; } // 获取所有子集 public static List<Set<String>> getSubSets(Set<String> itemSet) { List<Set<String>> subSets = new ArrayList<>(); if (itemSet.isEmpty()) { subSets.add(itemSet); } else { List<Set<String>> subSetsWithoutFirst = getSubSets(itemSet.stream().skip(1).collect(Collectors.toSet())); subSets.addAll(subSetsWithoutFirst); subSetsWithoutFirst.forEach(subSet -> { Set<String> subSetWithFirst = new HashSet<>(subSet); subSetWithFirst.add(itemSet.iterator().next()); subSets.add(subSetWithFirst); }); } return subSets; } // 关联规则类 public static class Rule { private Set<String> antecedent; private Set<String> consequent; private double confidence; public Rule(Set<String> antecedent, Set<String> consequent, double confidence) { this.antecedent = antecedent; this.consequent = consequent; this.confidence = confidence; } public Set<String> getAntecedent() { return antecedent; } public Set<String> getConsequent() { return consequent; } public double getConfidence() { return confidence; } @Override public String toString() { return antecedent + " => " + consequent + " (confidence: " + confidence + ")"; } } public static void main(String[] args) { List<Set<String>> transactions = new ArrayList<>(); transactions.add(new HashSet<>(Arrays.asList("A", "B", "C"))); transactions.add(new HashSet<>(Arrays.asList("A", "C", "D", "E"))); transactions.add(new HashSet<>(Arrays.asList("A", "C", "E", "F"))); transactions.add(new HashSet<>(Arrays.asList("B", "C", "E"))); transactions.add(new HashSet<>(Arrays.asList("B", "D", "E", "F"))); double minSupport = 0.4; double minConfidence = 0.7; List<Rule> rules = associationRules(transactions, minSupport, minConfidence); rules.forEach(System.out::println); } } ``` 以上代码实现了Apriori算法中的候选项集计算、支持度计算、频繁项集计算和关联规则挖掘等步骤。你可以根据自己的需求进行调整和修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值