使用Apriori算法进行关联分析

我们很多人可能知道“啤酒与尿布”的故事(如果不知道课百度下)。这就是关联分析中最有名的例子。

1、什么是关联分析?

关联分析是一种在大规模数据集中寻找有趣关系的任务,这些关系可以有两种形式:频繁项集或者关联规则

频繁项集(frequent item set):是经常出现在一块的物品集合

关联规则(association rules):暗示两种物品之间可能存在很强的关系

举个例子:


但是我们如何定义这些关系呢?当寻找频繁项集时,频繁(frequent)的定义是什么?那么我们就要讲到支持度和可信度。

支持度(support):该数据集中包含该项集的记录所占的比例。从上面例子中可以得到:{豆奶}的支持度是4/5,{豆奶,尿布}的支持度是3/5。支持度是针对项集来说的,只保留满足最小支持度的项集

可信度(confidence):是针对一条诸如{尿布}-->{葡萄酒}的关联规则来定义的。这条规则的可信度被定义为:

“支持度({尿布,葡萄酒})/支持度({尿布})”


支持度和可信度是用来量化关联分析是否成功的方法。假设想找到支持度大于0.8的所有项集,应该如何去做?一个办法就是生产一个物品所有可能组合的清单,然后对每一种组合统计它出现的频繁程度。

但是当物品成千上万时,上述做法非常非常慢。真对这个问题,我们引进Apriori原理。

2、Apriori原理:

原理作用:这个原理是针对计算支持度时候,要遍历所有的数据,这样会造成计算量过大,非常耗时,使用Apriori原理,可以减少遍历次数,减少时间。

原理内容:Apriori原理是说如果某个项集是频繁的,那么它的所有子集也是频繁的。

也就是说:如果{0,1}是频繁的,那么{0},{1}也一定是频繁的,反过来也就是说:如果一个项集是非频繁集,那么它的所有超集也是非频繁的。(这个很有用)

例如:我么如果知道{2,3}是非频繁的,那么{0,1,2,3}{1,2,3}{0,2,3}也是非频繁的。也就是说一旦计算出{2,3}的支持度,知道他是非频繁的之后,就不需要在计算{0,1,2,3}{1,2,3}{0,2,3}的支持度了。

3、使用Apriori算法来发现频繁集

关联分析包括两项:发现频繁项集和发现关联规则。我们需要先找到频繁项集,然后才能获得关联规则,所以我们先说怎么样发现频繁项集。

Apriori算法:该算法的的输入参数分别是最小支持度和数据集。该算法首先会生成所有单个物品的项集列表。接着扫描交易记录查看哪些项集满足最小支持度要求,那些不满足支持度的集合会被去掉。然后,对剩下来的集合进行组合以生成包含两个元素的项集。接下来,在重新扫描交易记录,去掉不满足最小支持度的项集。该过程重复进行直到所有项集都被去掉。


下面我们需要创建一些辅助函数:

<span style="color:#ff0000;">#加载数据</span>
def loadDataSet():
    return [[1,3,4],[2,3,5],[1,2,3,5],[2,5]]
<span style="color:#ff0000;">#把所有的数据的单项放入C1</span>
def createC1(dataSet):
    C1=[]
    for transaction in dataSet:
        for item in transaction:
            if not [item] in C1:
                C1.append([item])
    C1.sort()
    return map(frozenset, C1)
<span style="color:#ff0000;">#将大于minsupport的返回</span>
def scanD(D, Ck, minSupport):
    ssCnt = {}
    for tid in D:
        for can in Ck:
            if can.issubset(tid):
                if not ssCnt.has_key(can):ssCnt[can]=1
                else: ssCnt[can] += 1
    numItems = float(len(D))
    retList = []
    supportData = {}
    for key in ssCnt:
        support = ssCnt[key]/numItems
        if support >= minSupport:
            retList.insert(0,key)
        supportData[key] = support
    return retList, supportData

我们可以测试一下上面函数的返回值,通过加载 loadDataSet中的数据

<span style="font-size:18px;">>>> dataSet = apriori.loadDataSet()
>>> dataSet
[[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]
>>> C1 = apriori.createC1(dataSet)
>>> C1
[frozenset([1]), frozenset([2]), frozenset([3]), frozenset([4]), frozenset([5])]
>>> D = map(set,dataSet)
>>> D
[set([1, 3, 4]), set([2, 3, 5]), set([1, 2, 3, 5]), set([2, 5])]
>>> L1,suppData = apriori.scanD(D,C1,0.5)
>>> L1
[frozenset([1]), frozenset([3]), frozenset([2]), frozenset([5])]
>>> suppData
{frozenset([4]): 0.25, frozenset([5]): 0.75, frozenset([2]): 0.75, frozenset([3]): 0.75, frozenset([1]): 0.5}
>>> </span>
创建了这些辅助函数,下面我们要组织完整的Apriori算法

<span style="font-size:18px;">#创建候选项集,函数的作用是:假如我输入[frozenset([1]), frozenset([3]), frozenset([2]), frozenset([5])]</span>
<span style="font-size:18px;"><span style="white-space:pre">				</span>   输出[frozenset([1, 3]), frozenset([1, 2]), frozenset([1, 5]), frozenset([2, 3]), <span style="white-space:pre">					</span>frozenset([3, 5]), frozenset([2, 5])],依次类推
def aprioriGen(Lk,k):
    retList = []
    lenLk = len(Lk)
    for i in range(lenLk):
        for j in range(i+1,lenLk):
            L1 = list(Lk[i])[:k-2];L2 = list(Lk[j])[:k-2];
            print("L1:",L1,"L2:",L2)
            L1.sort();L2.sort()
            if L1 == L2:
                retList.append(Lk[i] | Lk[j])
    return retList
def apriori(dataSet, minSupport = 0.5):
    C1 = createC1(dataSet)
    D = map(set,dataSet)
    L1,supportData = scanD(D,C1,minSupport)#数据集,候选数据集列表,支持率
    L= [L1]
    k = 2
    while(len(L[k-2]) > 0):
        Ck = aprioriGen(L[k-2],k)
        Lk, supK = scanD(D, Ck, minSupport)
        supportData.update(supK) 
        L.append(Lk)
        k += 1
    return L, supportData</span>
我们可以通过代码对以上函数进行测试:
<span style="font-size:18px;">>>> L,suppData=apriori.apriori(dataSet)
('L1:', [], 'L2:', [])
('L1:', [], 'L2:', [])
('L1:', [], 'L2:', [])
('L1:', [], 'L2:', [])
('L1:', [], 'L2:', [])
('L1:', [], 'L2:', [])
('L1:', [1], 'L2:', [2])
('L1:', [1], 'L2:', [2])
('L1:', [1], 'L2:', [3])
('L1:', [2], 'L2:', [2])
('L1:', [2], 'L2:', [3])
('L1:', [2], 'L2:', [3])
>>> L
[[frozenset([1]), frozenset([3]), frozenset([2]), frozenset([5])], [frozenset([1, 3]), frozenset([2, 5]), frozenset([2, 3]), frozenset([3, 5])], [frozenset([2, 3, 5])], []]
>>> apriori.aprioriGen(L[0],2)
('L1:', [], 'L2:', [])
('L1:', [], 'L2:', [])
('L1:', [], 'L2:', [])
('L1:', [], 'L2:', [])
('L1:', [], 'L2:', [])
('L1:', [], 'L2:', [])
[frozenset([1, 3]), frozenset([1, 2]), frozenset([1, 5]), frozenset([2, 3]), frozenset([3, 5]), frozenset([2, 5])]
</span><pre name="code" class="python">>>> suppData
{frozenset([5]): 0.75, frozenset([3]): 0.75, frozenset([2, 3, 5]): 0.5, frozenset([1, 2]): 0.25, frozenset([1, 5]): 0.25, frozenset([3, 5]): 0.5, frozenset([4]): 0.25, frozenset([2, 3]): 0.5, frozenset([2, 5]): 0.75, frozenset([1]): 0.5, frozenset([1, 3]): 0.5, frozenset([2]): 0.75}
>>> 

 
现在我们就利用Apriori算法得到了频繁项集。和他的支持度 

4、下面我们要做的就是从频繁项集中挖掘关联规则

要找到关联规则,我们首先从一个频繁项集开始。在上面我们给出了频繁项集的量化定义,即它满足最小支持度的要求,对于关联规则我们也有类似的量化方法,即可信度。

通过观察我们可以知道,如果某条规则并不满足最小的可信度要求,那么该规则的所有子集也不满足最小可信度要求。例如:0,1,2--》3不满足最小可信度要求,那么就知道任何左部为{0,1,2}子集的规则也不会满足最小可信度要求。可以通过这个性质来减少需要测试的规则数目。

关联规则生成函数:

def generateRules(L,supportData, minConf=0.7):
    bigRuleList = []
    for i in range(1,len(L)):
        for freqSet in L[i]:
            H1 = [frozenset([item]) for  item in freqSet]
            if(i > 1):
                rulesFromConseq(freqSet,H1, supportData, bigRuleList, minConf)
            else:
                calcConf(freqSet, H1, supportData, bigRuleList, minConf)
    return bigRuleList

def calcConf(freqSet, H, supportData, br1, minConf=0.7):
    prunedH = []
    for conseq in H:
        conf = supportData[freqSet]/supportData[freqSet-conseq]
        if conf >= minConf:
            print(freqSet-conseq,'-->',conseq,'conf:',conf)
            br1.append((freqSet-conseq, conseq, conf))
            prunedH.append(conseq)
    return prunedH
def rulesFromConseq(freqSet, H, supportData, br1, minConf=0.7):
    m = len(H[0])
    if(len(freqSet) > (m + 1)):
        Hmp1 = aprioriGen(H,m + 1)
        Hmp1 = calcConf(freqSet, Hmp1, supportData, br1, minConf)
        if(len(Hmp1) > 1):
            rulesFromConseq(freqSet, H, supportData, br1, minConf)

结果:

>>> reload(apriori)
<module 'apriori' from 'C:\Python27\apriori.py'>
>>> rules = apriori.generateRules(L,suppData)
(frozenset([1]), '-->', frozenset([3]), 'conf:', 1.0)
(frozenset([5]), '-->', frozenset([2]), 'conf:', 1.0)
(frozenset([2]), '-->', frozenset([5]), 'conf:', 1.0)
('L1:', [], 'L2:', [])
('L1:', [], 'L2:', [])
('L1:', [], 'L2:', [])
>>> rules
[(frozenset([1]), frozenset([3]), 1.0), (frozenset([5]), frozenset([2]), 1.0), (frozenset([2]), frozenset([5]), 1.0)]
一旦降低可信度的阈值,可以获得更多的规则。

总结:虽然我们用Apriori原理来减少在数据库上进行检查的集合的数目。这样可以提高速度。

  但是,每次增加频繁项集的大小,Apriori算法都会重新扫描整个数据集,当数据集很大的时候,还是会降低频        繁项集的发现的速度。如果有需要,可以看下FPfrowth算法,该算法对数据库进行两次遍历,能够显著加快发  现频繁项集的速度。













评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值