Apriori 关联分析算法原理分析与代码实现

前言

  想必大家都听过数据挖掘领域那个经典的故事 - "啤酒与尿布" 的故事。

  那么,具体是怎么从海量销售信息中挖掘出啤酒和尿布之间的关系呢?

  这就是关联分析所要完成的任务了。

  本文将讲解关联分析领域中最为经典的Apriori算法,并给出具体的代码实现。

关联分析领域的一些概念

  1. 频繁项集: 数据集中经常出现在一起的物品的集合。例如 "啤酒和尿布"

  2. 关联规则: 指两个物品集之间可能存在很强的关系。例如 "{啤酒} -> {尿布}" 就是一条关联规则。

  3. 支持度: 数据集中,出现了某个物品集的数据项占总数据项的比重。

  4. 可信度: 这个概念是针对某条关联规则而定的。它是指两个物品集的支持度和其中某个物品集的支持度之比,如 "支持度{啤酒,尿布} / 支持度{尿布}"。

  因此,用这些属于来解释啤酒与尿布的故事,那就是:{啤酒,尿布}是一个频繁项集;"{啤酒} -> {尿布}" 就是一条关联规则;顾客买尿布的同时买啤酒的可能性为 "支持度{啤酒,尿布} / 支持度{尿布}"。

  那么对海量的数据,假如要得到支持度大于0.8的所有频繁项集,该怎么做?

  如果用蛮力法一个个统计,是根本不现实的,那样计算量实在太大。

  本文将要介绍的Apriori关联分析算法意义就在于能够大幅度减少这种情况的计算量,并从频繁项集中高效检索出关联规则,从而大大减少关联规则学习所需要消耗的计算量。

Apriori算法基本原理

  如果{0,1}是频繁项集,那么{0}和{1}也都是频繁项集。

  这显然是正确的命题。

  其逆否命题 - ”如果{0}和{1}不都是频繁项集,那么{0,1}不是频繁项集" 自然也是正确的。-> 这就是 Apriori 算法的核心思想之一。

  这样,一旦发现某个集合不是频繁项集,那么它的所有超集也都不是频繁项集,就不用浪费功夫去对它们进行检索了。

  检索出频繁项集之后,接下来检索出所有合乎要求的关联规则。

  如果某条规则不满足最小可信度要求,那么该规则的所有子集也不会满足。 -> 这是 Apriori 算法的核心思想的另一部分。

  PS:这里务必思考清楚规则是怎么划分的,什么叫某个规则的子集。

  这样,和上一步同理,也能高效的从频繁项集中检索出关联规则了。

  具体实现将分为频繁集检索和关联规则学习两个部分进行讲解。

频繁项集检索实现思路与实现代码

  一种经典的实现方法是 "分级法":

  算法框架是在两个大的步骤 - 筛选/过滤之间不断迭代,直到所有情况分析完毕。

  每次筛选的结果都要指定元素个数的情况,因此所谓分级,也就是依次讨论指定元素个数情况的项集。

  在筛选之后,就是过滤。

  过滤有两层意义,一个是项集必须在数据集中存在。这是第一层过滤;还有一层过滤,是指支持度过滤。只有满足支持度要求的项集才能保存下来。

  过滤之后,基于过滤集再进行筛选,每次筛选的元素个数都比上一次筛选的元素个数多一个。

  然后继续过滤。如此反复,直到最后一次筛选过滤完成。

  伪代码实现:

当集合中项的个数大于0时:
    构建一个 k 个项组成的候选项集的列表
    检查数据以确认每个项集都是频繁的
    保留频繁项集并构建 k+1 项组成的候选项集列表

  其中检查每个项集是否频繁部分的伪代码:

对数据集中的每条交易记录:
    对每个候选集元素:
        检查是否为数据集元素,是才保留。
对每个数据集
    如果支持度达到要求才保留
返回过滤后的频繁项集 - 也即过滤集

  Python实现及测试代码:

  1 def loadDataSet():
  2     ‘返回测试数据‘
  3
  4     return [[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]
  5
  6 #===================================
  7 # 输入:
  8 #        dataSet: 数据集
  9 # 输出:
 10 #        map(frozenset, C1): 候选集
 11 #===================================
 12 def createC1(dataSet):
 13     ‘创建候选集‘
 14
 15     C1 = []
 16     for transaction in dataSet:
 17         for item in transaction:
 18             if not [item] in C1:
 19                 C1.append([item])
 20
 21     C1.sort()
 22
 23     # 返回的集合元素都是frozenset类型 -> 因为以后要用来做键。
 24     return map(frozenset, C1)
 25
 26 #=============================================
 27 # 输入:
 28 #        D: 数据集 (set格式)
 29 #        Ck: 候选集
 30 #        minSupport: 最小支持度
 31 # 输出:
 32 #        retList: 过滤集
 33 #        supportData: 支持集(挖掘关联规则时使用)
 34 #=============================================
 35 def scanD(D, Ck, minSupport):
 36     ‘由候选集得到过滤集‘
 37
 38     # 统计候选元素出现的次数
 39     ssCnt = {}
 40     for tid in D:
 41         for can in Ck:
 42             if can.issubset(tid):
 43                 if not ssCnt.has_key(can): ssCnt[can]=1
 44                 else: ssCnt[can] += 1
 45
 46     # 构建过滤集和支持集
 47     numItems = float(len(D))
 48     retList = []
 49     supportData = {}
 50     for key in ssCnt:
 51         support = ssCnt[key]/numItems
 52         if support >= minSupport:
 53             retList.insert(0,key)
 54         supportData[key] = support
 55
 56     return retList, supportData
 57
 58 #===================================
 59 # 输入:
 60 #        Lk: 过滤集
 61 #        k: 当前项集元素个数
 62 # 输出:
 63 #        retList: 候选集
 64 #===================================
 65 def aprioriGen(Lk, k):
 66     ‘由过滤集得到候选集‘
 67
 68     # 重组过滤集,得到新的候选集。
 69     retList = []
 70     lenLk = len(Lk)
 71     for i in range(lenLk):
 72         for j in range(i+1, lenLk):
 73             # 留意下重组技巧
 74             L1 = list(Lk[i])[:k-2]; L2 = list(Lk[j])[:k-2]
 75             L1.sort();
 76             L2.sort()
 77             if L1==L2:
 78                 retList.append(Lk[i] | Lk[j])
 79
 80     return retList
 81
 82 #=============================================
 83 # 输入:
 84 #        dataSet: 数据集
 85 #        minSupport: 最小支持度
 86 # 输出:
 87 #        L: 频繁集
 88 #        supportData: 支持集(挖掘关联规则时使用)
 89 #=============================================
 90 def apriori(dataSet, minSupport = 0.5):
 91     ‘求频繁项集及其对应支持度‘
 92
 93     C1 = createC1(dataSet)
 94     D = map(set, dataSet)
 95     L1, supportData = scanD(D, C1, minSupport)
 96     L = [L1]
 97     k = 2
 98     while (len(L[k-2]) > 0):
 99         Ck = aprioriGen(L[k-2], k)
100         Lk, supK = scanD(D, Ck, minSupport)
101         supportData.update(supK)
102         L.append(Lk)
103         k += 1
104
105     return L, supportData
106
107 def main():
108     ‘Apriori频繁集检索‘
109
110     L, s = apriori (loadDataSet())
111
112     print L
113     print s

  测试结果:

  

关联规则学习实现思路与实现代码

  上一部分的工作是从数据集中检索出频繁集;而这一部分是根据频繁集学习关联规则。

  上一部分的工作是通过筛选集中的元素个数进行分级;而这一部分是针对规则右部的元素个数进行分级。

  另外还要注意,只用检索单个频繁集之内的关联规则就可以了。

  实现代码:

 1 #===================================
 2 # 输入:
 3 #        L: 频繁集
 4 #        supportData: 支持集
 5 #        minConf: 最小可信度
 6 # 输出:
 7 #        bigRuleList: 规则集
 8 #===================================
 9 def generateRules(L, supportData, minConf=0.7):
10     ‘从某个频繁集中学习关联规则‘
11
12     bigRuleList = []
13     for i in range(1, len(L)):
14         for freqSet in L[i]:
15             H1 = [frozenset([item]) for item in freqSet]
16             if (i > 1):
17                 rulesFromConseq(freqSet, H1, supportData, bigRuleList, minConf)
18             else:
19                 calcConf(freqSet, H1, supportData, bigRuleList, minConf)
20     return bigRuleList
21
22 #===================================
23 # 输入:
24 #        L: 频繁集
25 #        supportData: 支持集
26 #        minConf: 最小可信度
27 # 输出:
28 #        bigRuleList: 规则集
29 #===================================
30 def calcConf(freqSet, H, supportData, brl, minConf=0.7):
31     ‘可信度过滤‘
32
33     prunedH = []
34     for conseq in H:
35         conf = supportData[freqSet]/supportData[freqSet-conseq]
36         if conf >= minConf:
37             brl.append((freqSet-conseq, conseq, conf))
38             prunedH.append(conseq)
39
40     return prunedH
41
42 def rulesFromConseq(freqSet, H, supportData, brl, minConf=0.7):
43     ‘从某个频繁项集中学习关联规则‘
44
45     # 本次学习的规则右部中的元素个数
46     m = len(H[0])
47     if (len(freqSet) > (m + 1)):
48         # 重组规则右部
49         Hmp1 = aprioriGen(H, m+1)
50         # 规则学习
51         Hmp1 = calcConf(freqSet, Hmp1, supportData, brl, minConf)
52         if (len(Hmp1) > 1):
53             # 递归学习函数
54             rulesFromConseq(freqSet, Hmp1, supportData, brl, minConf)
55
56 def main():
57     ‘关联规则学习‘
58
59     L, s = apriori (loadDataSet())
60
61     rules = generateRules(L, s)
62     print rules

  测试结果:

  

  测试数据为: [[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]

  结果的意思也就是说:1->3,5->2,2->5 的概率为 1。

  显然这是和预计相吻合的。

小结

  1. Apriori关联算法在网络购物网站中用的非常多,可以基于此算法搭建商品推荐系统。

  2. 但Apriori算法也有一个缺点,那就是频繁集的检索速度还是不够快,因为每级都要重新检索一遍候选集(虽然候选集越来越小)。

  3. 针对 2 中的问题,下篇文章将介绍一个更为强大的发现频繁集的算法 - FP-growth。(但它不能用来发现关联规则)

时间: 2024-10-12 15:20:06

Apriori 关联分析算法原理分析与代码实现的相关文章

第十四篇:Apriori 关联分析算法原理分析与代码实现

前言 想必大家都听过数据挖掘领域那个经典的故事 - "啤酒与尿布" 的故事. 那么,具体是怎么从海量销售信息中挖掘出啤酒和尿布之间的关系呢? 这就是关联分析所要完成的任务了. 本文将讲解关联分析领域中最为经典的Apriori算法,并给出具体的代码实现. 关联分析领域的一些概念 1. 频繁项集: 数据集中经常出现在一起的物品的集合.例如 "啤酒和尿布" 2. 关联规则: 指两个物品集之间可能存在很强的关系.例如 "{啤酒} -> {尿布}"

Adaboost算法原理分析和实例+代码(简明易懂)

Adaboost算法原理分析和实例+代码(简明易懂) [尊重原创,转载请注明出处] http://blog.csdn.net/guyuealian/article/details/70995333     本人最初了解AdaBoost算法着实是花了几天时间,才明白他的基本原理.也许是自己能力有限吧,很多资料也是看得懵懵懂懂.网上找了一下关于Adaboost算法原理分析,大都是你复制我,我摘抄你,反正我也搞不清谁是原创.有些资料给出的Adaboost实例,要么是没有代码,要么省略很多步骤,让初学者

Tomcat7.0源码分析——请求原理分析(中)

前言 在<TOMCAT7.0源码分析--请求原理分析(上)>一文中已经介绍了关于Tomcat7.0处理请求前作的初始化和准备工作,请读者在阅读本文前确保掌握<TOMCAT7.0源码分析--请求原理分析(上)>一文中的相关知识以及HTTP协议和TCP协议的一些内容.本文重点讲解Tomcat7.0在准备好接受请求后,请求过程的原理分析. 请求处理架构 在正式开始之前,我们先来看看图1中的Tomcat请求处理架构. 图1 Tomcat请求处理架构 图1列出了Tomcat请求处理架构中的主

Tomcat源码分析——请求原理分析(下)

前言 本文继续讲解TOMCAT的请求原理分析,建议朋友们阅读本文时首先阅读过<TOMCAT源码分析——请求原理分析(上)>和<TOMCAT源码分析——请求原理分析(中)>.在<TOMCAT源码分析——请求原理分析(中)>一文我简单讲到了Pipeline,但并未完全展开,本文将从Pipeline开始讲解请求原理的剩余内容. 管道 在Tomcat中管道Pipeline是一个接口,定义了使得一组阀门Valve按照顺序执行的规范,Pipeline中定义的接口如下: getBas

Tomcat源码分析——请求原理分析(中)

前言 在<TOMCAT源码分析——请求原理分析(上)>一文中已经介绍了关于Tomcat7.0处理请求前作的初始化和准备工作,请读者在阅读本文前确保掌握<TOMCAT源码分析——请求原理分析(上)>一文中的相关知识以及HTTP协议和TCP协议的一些内容.本文重点讲解Tomcat7.0在准备好接受请求后,请求过程的原理分析. 请求处理架构 在正式开始之前,我们先来看看图1中的Tomcat请求处理架构. 图1 Tomcat请求处理架构 图1列出了Tomcat请求处理架构中的主要组件,这里

常见经典排序算法学习总结,附算法原理及实现代码(插入、shell、冒泡、选择、归并、快排等)

博主在学习过程中深感基础的重要,经典排序算法是数据结构与算法学习过程中重要的一环,这里对笔试面试最常涉及到的7种排序算法(包括插入排序.希尔排序.选择排序.冒泡排序.快速排序.堆排序.归并排序)进行了详解.每一种算法都有基本介绍.算法原理分析.算法代码. 转载请注明出处:http://blog.csdn.net/lsh_2013/article/details/47280135 插入排序 1)算法简介 插入排序(Insertion Sort)的算法描述是一种简单直观的排序算法.它的工作原理是通过

Tomcat7.0源码分析——请求原理分析(上)

前言 谈起Tomcat的诞生,最早可以追溯到1995年.近20年来,Tomcat始终是使用最广泛的Web服务器,由于其使用Java语言开发,所以广为Java程序员所熟悉.很多人早期的J2EE项目,由程序员自己实现Jsp页面或者Servlet接受请求,后来借助Struts1.Struts2.Spring等中间件后,实际也是利用Filter或者Servlet处理请求,大家肯定要问了,这些Servlet处理的请求来自哪里?Tomcat作为Web服务器是怎样将HTTP请求交给Servlet的呢? 本文就

Tomcat7.0源码分析——请求原理分析

Tomcat7.0源码分析--请求原理分析 谈起Tomcat的诞生,最早可以追溯到1995年.近20年来,Tomcat始终是使用最广泛的Web服务器,由于其使用Java语言开发,所以广为Java程序员所熟悉.很多人早期的J2EE项目,由程序员自己实现Jsp页面或者Servlet接受请求,后来借助Struts1.Struts2.spring等中间件后,实际也是利用Filter或者Servlet处理请求,大家肯定要问了,这些Servlet处理的请求来自哪里?Tomcat作为Web服务器是怎样将HTT

朴素贝叶斯分类算法原理分析与代码实现

前言 本文介绍机器学习分类算法中的朴素贝叶斯分类算法并给出伪代码,Python代码实现. 词向量 朴素贝叶斯分类算法常常用于文档的分类,而且实践证明效果是挺不错的. 在说明原理之前,先介绍一个叫词向量的概念. --- 它一般是一个布尔类型的集合,该集合中每个元素都表示其对应的单词是否在文档中出现. 对应关系和词汇表一一对应. 比如说,词汇表只有三个单词:'apple', 'orange', 'melo',某文档中,apple和melo出现过,那么其对应的词向量就是 {1, 0, 1}. 这种模型