Apriori关联分析

Apriori关联分析

关联分析同样是无监督学习中的算法,个人理解,k-means算法是计算无类别连续量之间的关系,而Apriori算法则是计算无类别离散量之间的关系。

对于联系量来说,样本之间的关系可以用距离来表示,但对于离散量,我们要定义新的关系:

  • 频繁项集:是经常出现在一块的属性的集合,比如对于西瓜{色泽=浅绿,触感=硬滑}

  • 支持度:是对于一个集合来说的,是数据集中包含该项集的比例,比如一共有10个西瓜,其中有7个西瓜满足{色泽=浅绿,触感=硬滑},则该频繁项集的支持度为0.7

    频繁项集就是支持度大于一定值的集合

  • 置信度:是对于一种关联关系来说,比如色泽=浅绿 → \rightarrow 触感=硬滑,这个关系的置信度为0.7,意义是如果一个西瓜色泽是浅绿,则有百分之70的概率其触感是硬滑,置信度的计算方式
    C o n f ( P → H ) = s u p p o r t ( P ∪ H ) s u p p r o t ( P ) , 其 中 C o n f 为 置 信 度 函 数 , s u p p o r t 为 支 持 度 函 数 Conf(P\rightarrow H)=\frac{support(P\cup H)}{supprot(P)},\\ 其中Conf为置信度函数,support为支持度函数 Conf(PH)=supprot(P)support(PH),Confsupport
    含义很好理解,就是出现 P P P H H H的概率除以出现 P P P的概率,找出置信度高的关系很有必要。

如果想要找出所有频繁项集,一个方法是遍历数据暴力搜索所有可能的集合,这样搜索非常慢,但是Apriori原理会帮助到我们,Apriori原理是如果某个项集是频繁的,那么它所有子集也是频繁的,如果一个项集是非频繁的,那么任何包含这个项集的集合也是非频繁的

那么我们只需要遍历搜索的时候只需要从最小的频繁项集出发,这样大大减少了计算时间

而对于找出置信度高的关系,也要从频繁项集出发

python实现

  • 找出频繁项集:
  1. 首先得到多个只含一个属性的集合,比如{色泽=浅绿},{色泽=乌黑},{触感=硬滑}等
  2. 对于上述每个集合,求出其是否出现在每一个样本中,便可得到支持度
  3. 筛选出支持度大于阈值的集合 C C C,其中每个元素为支持度大于阈值的项集
  4. 对于项集 C C C中的每个元素生成组合项集
  5. 对于组合项集同样看其是否出现则每个样本中,算出支持度
  6. 重复步骤3,直至集合 C C C为空
def createC1(dataSet):#步骤1
    C1 = []
    for transaction in dataSet:
        for item in transaction:
            if not [item] in C1:
                C1.append([item])
    C1.sort()
    return list(map(frozenset,C1))

def scanD(D,Ck,minSupport):#遍历样本计算项集的支持度
    ssCnt = {}
    for tid in D:#D为数据集 则tid为每个样本
        for can in Ck:#集合C中的元素,即要求支持度的项集
            if can.issubset(tid): 
                if can not in ssCnt.keys():
                    ssCnt[can]=0
                ssCnt[can] += 1
    #ssCnt这个集合记录了C中每个集合的出现次数
    numItems = float(len(D))
    retList = []
    supportData = {}
    for key in ssCnt:
        support = ssCnt[key]/numItems
        if support >= minSupport:
            retList.append(key)
        supportData[key] = support
    retList.sort()
    return retList,supportData #返回支持度大于阈值的项集及其对应的支持度

def aprioriGen(Lk,k): #对于频繁项集的集合生成其组合,如{1},{2}生成{1,2}
    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]
            L1.sort();L2.sort()
            if L1 == L2:
                retList.append(Lk[i]|Lk[j])
    return retList

def apriori(dataSet,minSupport=0.5):#Apriori算法主函数
    C1 = createC1(dataSet) #步骤1
    D = list(map(set,dataSet))
    L1,supportData = scanD(D,C1,minSupport) #步骤2和步骤3
    L = [L1] #记录频繁项集,L=[[包含一个元素的频繁项集],[包含两个元素的频繁项集]]
    k = 2
    while (len(L[k-2]) > 0):
        Ck = aprioriGen(L[k-2],k) #步骤4
        Lk,supK = scanD(D,Ck,minSupport) #步骤5
        supportData.update(supK)
        L.append(Lk)
        k += 1
    return L,supportData
  • 计算关联度:

    既然是关联关系,则从包含两个元素的频繁项集开始,并且还由一个原理就是

    如果A → \rightarrow B的置信度较低,则任意左部为A的子集的关系的置信度也会较低

    1. 若频繁项集只有两个元素如{1,2}:
    • 输入为{1,2}和[{1},{2}]
    • 算出{2} → \rightarrow {1}(实际是算{1,2}/{1} → \rightarrow {1})的置信度和{1} → \rightarrow {2}的置信度(实际是算{1,2}/{2} → \rightarrow {2})
    1. 若频繁项集有大于两个元素如{1,2,3,4}:
    • 输入为S={1,2,3,4}和H=[{1},{2},{3},{4}]
    • 首先对于H生成组合[{1,2},{1,3},{1,4},{2,3},{2,4},{3,4}]
    • 算出{3,4} → \rightarrow {1,2}(实际是算{1,2,3,4}/{1,2} → \rightarrow {1,2}),以此类推,并记录符合置信度阈值的左部项集
    • 对于符合置信度的项集,例如[{1,2},{1,3}],同样生成组合[{1,2,3}],更新H
    • 算出{4} → \rightarrow {1,2,3}(实际是算{1,2,3,4}/{1,2,3} → \rightarrow {1,2,3})的置信度,同样返回置信度高的关系的左部,并生产组合更新H
    • 如果H为空了则可以停止

    可以看出第2,3步和第4,5步是一样的,则可以采用递归,有点绕是不是

    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]#步骤1
                if i>1 :
                    rulesFromConseq(freqSet,H1,supportData,bigRuleList,minConf)
                    #步骤1.1和1.2
                else:
                    calcConf(freqSet,H1,supportData,bigRuleList,minConf)
                    #步骤2
        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])
        print(H)
        if (len(freqSet) > (m+1)):
            Hmp1 = aprioriGen(H,m+1) #步骤2.2
            Hmp1 = calcConf(freqSet,Hmp1,supportData,br1,minConf)#步骤2.3
            if len(Hmp1) > 1: 
                rulesFromConseq(freqSet,Hmp1,supportData,br1,minConf)
    

测试

对于一个蘑菇数据(部分)

1 3 9 13 23 25 34 36 38 40 52 54 59 63 67 76 85 86 90 93 98 107 113 
2 3 9 14 23 26 34 36 39 40 52 55 59 63 67 76 85 86 90 93 99 108 114 
2 4 9 15 23 27 34 36 39 41 52 55 59 63 67 76 85 86 90 93 99 108 115 
1 3 10 15 23 25 34 36 38 41 52 54 59 63 67 76 85 86 90 93 98 107 113 
2 3 9 16 24 28 34 37 39 40 53 54 59 63 67 76 85 86 90 94 99 109 114 

第一项为蘑菇毒性(2为有毒,1为无毒)

第二项为蘑菇形状(有六种可能取值3~8),第三项第4项以此类推

为了探究毒蘑菇的共同特征,可以使用Apriori算法,设置minSupport=0.3

可以得到包含2个属性的频繁项集

{2, 23}
{34, 2}
{2, 36}
{2, 59}
{2, 63}
{2, 67}
{2, 76}
{2, 85}
{2, 86}
{90, 2}
{2, 93}
{2, 39}
{2, 28}
{2, 53}

可以查23代表什么,34代表什么,从而得到毒蘑菇的特征

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值