Part3-Chapter11-使用Apriori算法进行关联分析

本文介绍了关联分析中的频繁项集和关联规则,以及如何通过支持度和可信度来衡量。Apriori算法被用来高效地找出频繁项集,并通过示例展示了其在数据集上的应用。代码实现和运行结果显示了生成的关联规则及其置信度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

有时候面对一堆杂乱的数据,我们需要寻找到其中蕴含的规律,这种时候我们就要借助关联分析。它寻找的规律有两种形式:频繁项集和关联规则。

频繁项集:经常出现在一块的数据的集合。

关联规则:暗示几个特征间可能存在很强的关系。

那么如何来定义要寻找的频繁和关系呢?有很多种方法,但最重要的有两类:支持度以及可信度或置信度。

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

可信度或置信度:它的定义类似条件概率,关系A→B的可信度 = (A,B)的支持度 / A的支持度。也就是说,它是指如果A表现出某些特定特征时,B表现出另外一些特定的特征的概率。

如果我们想找到这两个指标高于一定值的所有项集,一个直观的做法是得到一个数据所有可能的组合,然后依次计算其值。但这样的方法在处理大型数据时显然不可取,为了解决这个问题,我们引入了Apriori方法。

Apriori:
我们直到,如果(A,B,C…)是频繁项集,那么它其中的每一个项集都应该是频繁项集。那么根据逻辑学,如果一个子项集不是频繁项集,那么其父项集也必然不是频繁项集。

这就是Apriori方法的原理。我们从小至大的计算每个项集的支持度,如果其支持度小于设定值,就将其,以及其父项集移除出搜索集,这样就能极大地减小计算的复杂度。

伪代码:
对数据集中的每条记录trans:
对每个候选项集can:
	检查一下can是否是trans的子集:
	如果是:则增加can的计数值
对每个候选集:
如果其支持度大于给定值,则保留
返回所有频繁集列表

代码如下:

import numpy as np

#载入测试集
def loadDataSet():
    return [[1,3,4],[2,3,5],[1,2,3,5],[2,5]]

#取数据集的每个不重复的单元数据,建立一个frozenset
def createC1(dataSet):
    C1 = []
    #遍历每一行
    for trans in dataSet:
        #遍历每一列
        for item in trans:
            if [item] not in C1:
                    C1.append([item])
    C1.sort()
    return [frozenset(t) for t in C1]

#找到支持度符合要求的单元数据,并返回这些单元数据组成的集合及表示其支持度的dict
#D:转换为set类型的数据集
#Ck:每个单元项组成的frozenset
#minSupport:最小支持度
def scanD(D,Ck,minSupport):
    #数据行数
    numItems = len(D)
    #单元项出现次数
    ssCnt = {}
    #对数据集的每一行:
    for tid in D:
        #对每个单元项:
        for can in Ck:
            #如果单元项在该行:
            if can.issubset(tid):
                #若此单元项未记录,则记录它
                if can not in ssCnt:
                    ssCnt[can] = 1
                #若已有记录,则记录+1
                else:
                    ssCnt[can] += 1
    #符合支持度的单元项列表
    retList = []
    #记录每个符合支持度的单元项的支持度
    supportData = {}
    #对出现次数记录列表中的每一项:
    for key in ssCnt:
        support = ssCnt[key]/numItems
        if support >= minSupport:
            retList.append(key)
            supportData[key] = support
    return retList,supportData

#将数据集转换为集合
#dataSet:数据集
#书中得到D是使用了map函数,但我实测后发现用这种方法会出现各种奇怪的问题
#但直接使用set()又不能转换列表,于是干脆自己写了个转换函数
def tranSet(dataset):
    D = []
    #遍历数据集的每一行:
    for i in range(len(dataSet)):
        #将其转换为集合且加入列表D中
        D.append(set(dataSet[i]))
    return D

#由含每个项含k和数据的集合合成含k+1个数据的集合
#Lk:每个项含k个数据的集合
#k:集合所含数据数
def aprioriGen(Lk,k):
    #合并后的集合
    retList = []
    lenLk = len(Lk)
    #遍历初始集合
    for i in range(lenLk):
        #将初始集合中的每个项与其后项对比
        for j in range(i+1,lenLk):
            #为了提高效率,只用比较前k-2项即可
            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])
    return retList

#apriori算法执行函数
#dataSet:数据集
#minSupport:最小支持度
def apriori(dataSet,minSupport = 0.5):
    #得到由不重复的单元数据组成的frozenset
    C1 = createC1(dataSet)
    #每一单元项内去重
    D = tranSet(dataSet)
    #得到由符合支持度的单元数据组成的列表及其相应支持度
    L1,supportData = scanD(D,C1,minSupport)
    #初始化全体支持列表
    L = [L1]
    k = 2
    #当每个项含k-1个数据的集合非空时,继续进行合并
    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

#计算关联度控制函数
#L:所有符合支持度的组合组成的集合
#supportData:包含支持度的dict
#minConf:最小关联度
def generateRules(L,supportData,minConf = 0.7):
    #关联度列表
    bigRuleList = []
    #遍历所有符合支持度的组合组成的集合的每一层,因为i=0时每个项只包含一个数据,无法计算关联度,故舍去
    for i in range(1,len(L)):
        #遍历每一层内的每一项
        for freqSet in L[i]:
            #得到由该项内所有数据构成的frozenset
            H1 = [frozenset([item]) for item in freqSet]
            #若每一项内数据数大于2:
            if i > 1 :
                rulesFromConseq(freqSet,H1,supportData,bigRuleList,minConf)
            #否则直接计算关联度
            else:
                calcConf(freqSet,H1,supportData,bigRuleList,minConf)
    return bigRuleList

#计算关联度
#freqSet:当前项
#H:由当前项转换的frozenset
#supportData:支持度dict
#brl:关联度列表的引用
#minConf:最小关联度
def calcConf(freqSet,H,supportData,brl,minConf = 0.7):
    #当前层符合最小关联度的集合的后件集合,用于计算当前层符合最小关联度的集合数,进而判断是否继续计算
    prunedH = []
    #遍历当前项的每一个数据
    for conseq in H :
        #计算关联度,即当前关系的支持度除以其前件的支持度
        conf = supportData[freqSet]/supportData[freqSet - conseq]
        #若关联度大于最小关联度:
        if conf >= minConf:
            print(freqSet - conseq,"-->",conseq,"conf:",conf)
            brl.append((freqSet - conseq,conseq,conf))
            prunedH.append(conseq)
    return prunedH

#计算数据量超过两个的项的关联度
#freqSet:当前项
#H:由当前项转换的frozenset
#supportData:支持度dict
#brl:关联度列表的引用
#minConf:最小支持度
def rulesFromConseq(freqSet,H,supportData,brl,minConf = 0.7):
    #计算前件数量
    m = len(H[0])
    #若数据长度大于后件数,即有前件,可以构成关联规则,则继续生成
    #书上这里是大于m+1,我无法理解这是为什么,上网找了其它人的学习笔记
    #发现有人在这里改成了现在的样子,与书上代码相比,多了三条前件含两个数据的关联度,可以认为这是作者的一处失误
    if len(freqSet) > m :
        #计算当前项的关联度
        Hmp1 = calcConf(freqSet,H,supportData,brl,minConf)
        #若符合关联度的项数量超过1,则生成下一层的关联规则,即左端-1,右端+1
        #这里我一开始不理解,想了一下意思应该是:如果a,c→b,且a,b→c,那么可能就会有a→b,c
        #即若当前符合支持度的项数超过1,那么就有可能有新的关联规则未发现
        if len(Hmp1) > 1:
            #生成下一层的项集合
            Hmp1 = aprioriGen(H,m+1)
            #迭代计算该层关联度
            rulesFromConseq(freqSet,Hmp1,supportData,brl,minConf)

#主函数
if __name__ == '__main__' :
    dataSet = loadDataSet()
    L,supportData = apriori(dataSet,0.5)
    print("频繁项集:\n",L)
    print("关联规则:")
    rules = generateRules(L,supportData,0.5)

运行结果如下:

频繁项集:
[[frozenset({1}), frozenset({3}), frozenset({2}), frozenset({5})], [frozenset({1, 3}), frozenset({2, 3}), frozenset({3, 5}), frozenset({2, 5})], [frozenset({2, 3, 5})], []]
关联规则:
frozenset({3}) --> frozenset({1}) conf: 0.6666666666666666
frozenset({1}) --> frozenset({3}) conf: 1.0
frozenset({3}) --> frozenset({2}) conf: 0.6666666666666666
frozenset({2}) --> frozenset({3}) conf: 0.6666666666666666
frozenset({5}) --> frozenset({3}) conf: 0.6666666666666666
frozenset({3}) --> frozenset({5}) conf: 0.6666666666666666
frozenset({5}) --> frozenset({2}) conf: 1.0
frozenset({2}) --> frozenset({5}) conf: 1.0
frozenset({3, 5}) --> frozenset({2}) conf: 1.0
frozenset({2, 5}) --> frozenset({3}) conf: 0.6666666666666666
frozenset({2, 3}) --> frozenset({5}) conf: 1.0
frozenset({5}) --> frozenset({2, 3}) conf: 0.6666666666666666
frozenset({3}) --> frozenset({2, 5}) conf: 0.6666666666666666
frozenset({2}) --> frozenset({3, 5}) conf: 0.6666666666666666

书后面还介绍了两个应用,分别是发现国会投票中的模式和发现毒蘑菇的象征。

前者是使用了美国的一个投票网站的api来导入数据,处理后使用apriori算法进行分析,但我在申请apiKey的时候总是提示报错,想了想,反正api也尝试过,干脆就算了。

后者是使用了一个蘑菇数据集,分别表示了蘑菇的毒性和一些其它特征,直接使用apriori算法进行计算就ok了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值