zoukankan      html  css  js  c++  java
  • 使用Apriori算法进行关联分析

    关联分析力图在大规模数据集中寻找关系,这些关系有两种形式:频繁项集、关联规则。

    频繁项集:经常出现在一块的物品的集合

    关联规则:两种物品之间可能存在的关系

    支持度:数据集上包含该项集的记录所占的比例

    可信度/置信度:针对物品A-->物品B的关联规则来定义。物品A-->物品B的置信度 = 支持度(A | B)/支持度(A)

    Apriori算法原理:如果某个项集是频繁的,则它的所有子集也是频繁的。==》如果某个项集是非频繁的,则它的所有超集也是非频繁的。

    寻找频繁项集:

    辅助函数:

    def loadDataSet():
        return [[1,3,4],[2,3,5],[1,2,3,5],[2,5]]
    def createC1(dataSet):
        C1 = []
        for transaction in dataSet:
            for item in transaction:
                if not [item] in C1:    #这里并不是简单地添加每个物品项,而是添加只包含该物品项的一个列表。
                    C1.append([item])
        C1.sort()
        return list(map(frozenset, C1))   #frozenset创建不可变集合
    def scanD(D, Ck, minSupport):   #数据集,候选项集列表,最小支持度,过滤不符合最小支持度的项集
        ssCnt = {}
        for tid in D:
            for can in Ck:
                if can.issubset(tid):
                    if can not in ssCnt: 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
    

     完整的Apriori算法

    def aprioriGen(Lk, k):   #参数为当前频繁项集列表,需要生成的新的频繁项集的元素个数。因为每次生成的新的项元素个数比当前多1,所以[:k-2]表示当前项除了最后一个元素,即为[:,-1]
        retList = []
        print(Lk)
        print('k:',k)
        lenLk = len(Lk)
        for i in range(lenLk):
            for j in range(i+1, lenLk):
                print('i:',Lk[i])
                print('j:',Lk[j])
                L1 = list(Lk[i])[:k-2]
                L2 = list(Lk[j])[:k-2]
                L1.sort()
                L2.sort()
                if L1==L2:
                    retList.append(Lk[i] | Lk[j])  #集合操作符,求并集
                    print(retList)
        return retList
    def apriori(dataSet, minSupport = 0.5):
        C1 = createC1(dataSet)
        D = list(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
    

     测试:

    if __name__=='__main__':
        dataSet=loadDataSet()
        L,suppData=apriori(dataSet,0.5)
        print(L)
        print(suppData)
    

     输出:

    [[frozenset({1}), frozenset({3}), frozenset({2}), frozenset({5})], [frozenset({3, 5}), frozenset({1, 3}), frozenset({2, 5}), frozenset({2, 3})], [frozenset({2, 3, 5})], []]
    {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}
    

    从频繁项集中挖掘关联规则

    如果某条规则不满足最小可信度要求,则该规则的所有子集也不满足最小可信度要求。

    分级法:首先从一个频繁项集开始,接着创建一个规则列表,其中规则右部只包含一个元素,然后对这些元素进行测试。接下来合并所有剩余规则来创建一个新的规则列表,其中规则右部包含两个元素。

    关联规则生成函数:

    def generateRules(L, supportData, minConf=0.7):  #频繁项集列表,支持度列表,最小可信度
        bigRuleList = []    #包含可信度的规则列表
        for i in range(1, len(L)):  #因为无法对只有单个元素的频繁项集构建规则,智能从L[1]开始,L[1]是包含两个元素的频繁项集列表
            for freqSet in L[i]:    #遍历当前L[i]的所有频繁项集
                H1 = [frozenset([item]) for item in freqSet]    #从频繁项集中得到元素列表
                if (i > 1):     #i>1时,频繁项集至少有三个元素
                    rulesFromConseq(freqSet, H1, supportData, bigRuleList, minConf)     #对H1进一步合并成含有两个元素的频繁项集列表
                else:   #频繁项集有两个元素,则计算可信度
                    calcConf(freqSet, H1, supportData, bigRuleList, minConf)
        return bigRuleList
    def calcConf(freqSet, H, supportData, brl, minConf=0.7):    #计算规则的可信度并且找到满足最小可信度要求的规则;函数内部没有重置brl,所以brl可以保存满足条件的规则。
        prunedH = []    #保存满足最小可信度的规则列表
        for conseq in H:    #
            conf = supportData[freqSet]/supportData[freqSet-conseq]     #计算可信度
            print(freqSet - conseq, '====>', conseq, '可信度:', conf)
            if conf >= minConf:
                # print(freqSet-conseq,'====>',conseq,'可信度:',conf)
                brl.append((freqSet-conseq, conseq, conf))  #对列表brl补充,brl即为前面通过检查的bigRuleList
                prunedH.append(conseq)
        print('prunedH:',prunedH)
        return prunedH
    def rulesFromConseq(freqSet, H, supportData, brl, minConf=0.7):     #频繁项集,可以出现在规则右面的元素列表H
        m=len(H[0])     #第一次调用时m=1
        if len(freqSet) > m + 1: #如果频繁项集的元素个数大于H的元素长度加1,例如freqSet=[2,3,5],H=[2,3,5]时,3>1+1,此时把H的元素融合成[[2,3],[2,5],[3,5]]
            Hmp1 = aprioriGen(H, m+1)   #Hmpl=[[2,3],[2,5],[3,5]]
            print('freqSet:',freqSet)
            print('Hmp1:',Hmp1)
            Hmp1 = calcConf(freqSet, Hmp1, supportData, brl, minConf)
            if len(Hmp1) > 1:   #如果不止一条规则满足要求,则使用Hmp1迭代调用rulesFromConseq来判断是否可以进一步组合这些规则
                rulesFromConseq(freqSet, Hmp1, supportData, brl, minConf)
    

     测试:

    if __name__=='__main__':
        dataSet=loadDataSet()
        L,suppData=apriori(dataSet,0.5)
        rules=generateRules(L,suppData,0.7)
        print(rules)
    

     输出:

    frozenset({5}) ====> frozenset({3}) 可信度: 0.6666666666666666
    frozenset({3}) ====> frozenset({5}) 可信度: 0.6666666666666666
    prunedH: []
    frozenset({3}) ====> frozenset({1}) 可信度: 0.6666666666666666
    frozenset({1}) ====> frozenset({3}) 可信度: 1.0
    prunedH: [frozenset({3})]
    frozenset({5}) ====> frozenset({2}) 可信度: 1.0
    frozenset({2}) ====> frozenset({5}) 可信度: 1.0
    prunedH: [frozenset({2}), frozenset({5})]
    frozenset({3}) ====> frozenset({2}) 可信度: 0.6666666666666666
    frozenset({2}) ====> frozenset({3}) 可信度: 0.6666666666666666
    prunedH: []
    freqSet: frozenset({2, 3, 5})
    Hmp1: [frozenset({2, 3}), frozenset({2, 5}), frozenset({3, 5})]
    frozenset({5}) ====> frozenset({2, 3}) 可信度: 0.6666666666666666
    frozenset({3}) ====> frozenset({2, 5}) 可信度: 0.6666666666666666
    frozenset({2}) ====> frozenset({3, 5}) 可信度: 0.6666666666666666
    prunedH: []
    [(frozenset({1}), frozenset({3}), 1.0), (frozenset({5}), frozenset({2}), 1.0), (frozenset({2}), frozenset({5}), 1.0)]
    View Code

     参考

    上述代码有逻辑错误:

    在函数rulesFromConseq中,如果H有三个元素,例如原文中的H=[2,3,5],freqSet=[2,3,5],程序会将H融合成[[2,3],[2,5],[3,5]],不会校验[2,3]==>[5]、[2,5]==>[3]、[3,5]==>[2]的可信度,所以结果少了这些规则。

    修改:

    def generateRules(L, supportData, minConf=0.7):  #频繁项集列表,支持度列表,最小可信度
        bigRuleList = []    #包含可信度的规则列表
        for i in range(1, len(L)):  #因为无法对只有单个元素的频繁项集构建规则,智能从L[1]开始,L[1]是包含两个元素的频繁项集列表
            for freqSet in L[i]:    #遍历当前L[i]的所有频繁项集
                H1 = [frozenset([item]) for item in freqSet]    #从频繁项集中得到元素列表
                if (i > 1):     #i>1时,频繁项集至少有三个元素
                    H1 = calcConf(freqSet, H1, supportData, bigRuleList, minConf)   #计算可信度,过滤可信度低的候选规则
                    rulesFromConseq(freqSet, H1, supportData, bigRuleList, minConf)     #对H1进一步合并成含有两个元素的频繁项集列表
                else:   #频繁项集有两个元素,则计算可信度
                    calcConf(freqSet, H1, supportData, bigRuleList, minConf)
        return bigRuleList
    

    测试输出:

    [(frozenset({1}), frozenset({3}), 1.0), (frozenset({5}), frozenset({2}), 1.0), (frozenset({2}), frozenset({5}), 1.0), (frozenset({3, 5}), frozenset({2}), 1.0), (frozenset({2, 3}), frozenset({5}), 1.0)]
    

     if…else…多余,修改为下:

    def generateRules(L, supportData, minConf=0.7):  #频繁项集列表,支持度列表,最小可信度
        bigRuleList = []    #包含可信度的规则列表
        for i in range(1, len(L)):  #因为无法对只有单个元素的频繁项集构建规则,只能从L[1]开始,L[1]是包含两个元素的频繁项集列表
            for freqSet in L[i]:    #遍历当前L[i]的所有频繁项集
                H1 = [frozenset([item]) for item in freqSet]    #从频繁项集中得到元素列表
                rulesFromConseq(freqSet, H1, supportData, bigRuleList, minConf)     #对H1进一步合并成含有两个元素的频繁项集列表
        return bigRuleList
    def rulesFromConseq(freqSet, H, supportData, brl, minConf=0.7):     #频繁项集,可以出现在规则右面的元素列表H
        m=len(H[0])     #第一次调用时m=1
        if len(freqSet) > m: #如果频繁项集的元素个数大于H的元素长度,例如freqSet=[2,3,5],H=[2,3,5]时,3>1,此时把H的元素融合成[[2,3],[2,5],[3,5]]
            # print('freqSet:',freqSet)
            # print('Hmp1:',Hmp1)
            Hmp1 = calcConf(freqSet, H, supportData, brl, minConf)
            if len(Hmp1) > 1:   #如果不止一条规则满足要求,则使用Hmp1迭代调用rulesFromConseq来判断是否可以进一步组合这些规则
                Hmp1=aprioriGen(Hmp1,m+1)
                rulesFromConseq(freqSet, Hmp1, supportData, brl, minConf)   #递归
    

     进一步修改rulesFromConseq里的递归函数如下:

    def rulesFromConseq(freqSet, H, supportData, brl, minConf=0.7):
        m = len(H[0])
        while (len(freqSet) > m): # 判断长度 > m,这时即可求H的可信度
            H = calcConf(freqSet, H, supportData, brl, minConf)
            if (len(H) > 1): # 判断求完可信度后是否还有可信度大于阈值的项用来生成下一层H
                H = aprioriGen(H, m + 1)
                m += 1
            else: # 不能继续生成下一层候选关联规则,提前退出循环
                break
    
  • 相关阅读:
    pgspider timescale 扩展docker 镜像
    pgspider perl 语言扩展
    postgresql_anonymizer 方便的数据脱敏扩展
    pgspider jsonb_deep_sum 扩展docker 镜像以及简单试用
    pgspider pgddl 扩展doker 镜像以及试用
    pgspider wal2json doker 镜像
    pgspider Citus节点数据移动操作
    pgspider Citus worker 账户密码问题
    pgspider Citu 副本以及节点移除简单学习
    Citus 官方docker demo 中membership-manager原理简单说明
  • 原文地址:https://www.cnblogs.com/zhhy236400/p/9969568.html
Copyright © 2011-2022 走看看