使用Apriori算法进行关联分析(python2)

summary:

  • 关联分析是用于发现大数据集中元素间有趣关系的一个工具集,可以采用两种方式来量化这些有趣的关系。第一种方式是频繁项集,它会给出经常出现在一起的元素项;第二种方式是关联规则,每条关联规则意味着元素项之间“如果……那么”的关系。
  • 发现元素项间不同的组合是个十分耗时的任务,不可避免需要大量昂贵的计算资源,这就需要更智能的方法在合理时间范围内找到频繁项集。
  • 使用Apriori原理可以减少在数据库上进行检查的集合的数目。Apriori算法从单元素项集开始,通过组合满足最小支持度要求的项集来形成更大的集合。
  • 缺点:每次增加频繁集的大学,Apriori算法都会重新扫描整个数据集。
  • 准备数据:标称型或数值型数据类型都可以,因为我们只保存集合。
from numpy import *

def loadDataSet():
    return [[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]

dataSet=loadDataSet()
dataSet

def createC1(dataSet): #生成只包含一个元素的项集的集合C1
    C1 = []
    for transaction in dataSet:
        for item in transaction:
            if not [item] in C1:
                C1.append([item])
                
    C1.sort()
    return map(frozenset, C1)#use frozen set so we
                            #can use it as a key in a dict    
C1=createC1(dataSet)
C1
D=map(set,dataSet)
D

#计算Ck的项集的在数据集D中的支持度support,并检查数据确保每个项集都是频繁的
def scanD(D, Ck, minSupport): 
    """
    D:Lst[frozenset]
    Ck:Lst[frozenset]
    minSupport:int
    """
    ssCnt = {} #统计Ck中的项在D中的项中出现的次数
    for tid in D:
        for can in Ck:
            if can.issubset(tid): #如果can是tid的子集
                ssCnt[can]=ssCnt.get(can,0)+1
#            if can.issubset(tid):
#                if not ssCnt.has_key(can): ssCnt[can]=1
#                else: ssCnt[can] += 1
    numItems = float(len(D)) #D中共有多少条记录
    retList = []
    supportData = {}
    for key in ssCnt:
        support = ssCnt[key]/numItems #计算支持度:数据集中包含该项集的记录所占的比例
        if support >= minSupport:
            retList.append(key)
#            retList.insert(0,key)
        supportData[key] = support
    return retList, supportData

L1,suppData0=scanD(D,C1,0.5)
print(L1)
print(suppData0)

def aprioriGen(Lk, k): #creates Ck:这里k表示一个项集中包含几个元素
    """
    Lk: List(frozenset)
    """
    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: #if first k-2 elements are equal
                retList.append(Lk[i] | Lk[j]) #set union
                """
                判断Lk集合的前k-2个元素相同,然后将Lk[i],Lk[j]合并
                这就能保证后面生成的L(k+1)集合中的项集中的元素个数为k+1
                
                这里k-2用于定位,举个栗子,当k=3,Lk=[{1,2},{1,3},{1,5},{2,3},{2,5},{3,5}]
                此时就判断Lk[i][1]和Lk[][1]即项集的第1个元素是否相等来决定是否将它们合并
                从而retList=[{1,2,3},{1,3,5},{1,2,5},{2,3,5}]
                
                若k=4,就判断Lk[i]和Lk[j]的前2个元素是否相等,
                Lk是输入,所有项集的元素都是k-1个
                因为我们要生成含有k个元素的所有项集的集合retList
                所以需要前k-2个元素相等,最后一个元素不相等,这样合并起来刚好有k个元素
                """
    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
    #下面利用L(k-1)来构建L(k),并添加新支持度字典数据
    while (len(L[k-2]) > 0): #当集合中项的个数大于0时
        Ck = aprioriGen(L[k-2], k) #构建一个k个项组成的候选项集的列表
        Lk, supK = scanD(D, Ck, minSupport)#scan DB to get Lk 
        supportData.update(supK) #将生成的新的支持度的字典添加进原来的包含支持度的字典中
        L.append(Lk) #
        k += 1 #k用于定位到相应的L的位置上,即当计算L2时定位到L[0],因为L[0]表示的是L1
    return L, supportData

L,suppData=apriori(dataSet,minSupport = 0.5)
print(L)
print(suppData)

aprioriGen(L[0], 2)
L,suppData=apriori(dataSet,minSupport=0.7)
print(L)
print(suppData)


def generateRules(L, supportData, minConf=0.7):  #supportData is a dict coming from scanD
    bigRuleList = []
    for i in range(1, len(L)):#only get the sets with two or more items
        i=2
        for freqSet in L[i]:
            H = [frozenset([item]) for item in freqSet]
            if (i > 1):
                rulesFromConseq(freqSet, H, supportData, bigRuleList, minConf)
                """
                当项集中的元素个数大于2时,调用rulesFromConseq
                rulesFromConseq:
                调用aprioriGen来生成conseq,便于生成不重复的关联规则
                根据关联规则调用calcConf计算conf
                """
            else:
                calcConf(freqSet, H, supportData, bigRuleList, minConf)
                """
                当项集中的元素个数等于2时,调用calcConf(筛选大于minconf的项集)
                """
    return bigRuleList         

def calcConf(freqSet, H, supportData, brl, minConf=0.7):
    prunedH = [] #create new list to return
    for conseq in H:
        conf = supportData[freqSet]/supportData[freqSet-conseq] #calc confidence
        if conf >= minConf: 
            print(freqSet-conseq,'-->',conseq,'conf:',conf)
            brl.append((freqSet-conseq, conseq, conf))
            prunedH.append(conseq)
    return prunedH

def rulesFromConseq(freqSet, H, supportData, brl, minConf=0.7):
    m = len(H[0])
    if (len(freqSet) > (m + 1)): #try further merging
        Hmp1 = aprioriGen(H, m+1)#create Hm+1 new candidates
        Hmp1 = calcConf(freqSet, Hmp1, supportData, brl, minConf)
        if (len(Hmp1) > 1):    #need at least two sets to merge
            #再对大于1个元素的频繁项集再细分计算关联规则
            rulesFromConseq(freqSet, Hmp1, supportData, brl, minConf)
            
def pntRules(ruleList, itemMeaning):
    for ruleTup in ruleList:
        for item in ruleTup[0]:
            print itemMeaning[item]
        print "           -------->"
        for item in ruleTup[1]:
            print itemMeaning[item]
        print "confidence: %f" % ruleTup[2]
        print       #print a blank line

L,suppData=apriori(dataSet,minSupport = 0.5)
rules=generateRules(L,suppData,minConf=0.7)
View Code

 

算法介绍

算法利用Apriori原理,第1步,得到频繁集(计算支持度);第2步,从频繁集中挖掘关联规则(计算可信度)。

  • 支持度support:数据集中包含该项集的记录占总记录的比例,即用于度量一个集合在原始数据种出现的频率
  • 可信度confidence:一条规则P→H的可信度的计算公式为 support({P,H})/support({P})
  • 频繁集frequent item sets:是指经常出现在一块的物品的集合
  • 关联规则association rules:是指两个物品间可能存在很强的关系

Apriori原理是指,一个项集是频繁的,那么这个项集的子集也是频繁的;反过来,一个项集是非频繁的,那么包含这个项集的超集也是非频繁的。利用Apriori原理可以减少在数据库上进行检查的集合的数目。

应用于购物(比如关联分析中著名的例子是啤酒与尿布,说的是美国中西部的一家连锁店发现,男人们会在周四购买尿布和啤酒),还可以应用于搜索引擎中的查询词之间的关联规则。

 

示例:发现毒蘑菇的相似特征

mushroom.dat的前几行如下:

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

 

第1个特征的值为1和2分别表示有毒和无毒 。下一个特征是蘑菇伞的形状,有六种可能的值,分别用整数3-8表示。

为了找到毒蘑菇中存在的公共特征,可以运用Apriori算法来寻找包含特征值为2的频繁项集。

mushDatSet=[line.split() for line in open('mushroom.dat').readlines()]
L,suppData=apriori.apriori(mushDatSet,minSupport=0.3)
for item in L[1]:
    if item.intersection('2'):print(item) #查看与特征值2相交的item
结果如下:
frozenset(['2', '59'])
frozenset(['39', '2'])
frozenset(['2', '67'])
frozenset(['2', '34'])
frozenset(['2', '23'])
frozenset(['2', '86'])
frozenset(['76', '2'])
frozenset(['90', '2'])
frozenset(['2', '53'])
frozenset(['93', '2'])
frozenset(['63', '2'])
frozenset(['2', '28'])
frozenset(['2', '85'])
frozenset(['2', '36'])

接下来你需要观察这些特征,以便了解毒蘑菇的哪些方面,如果看到其中任何一个特征就不要吃这些蘑菇了。
当然,尽管上述这些特征在毒蘑菇中很普遍,但是没有这些特征并不意味着该蘑菇就是无毒可食用的。

示例:发现国会投票中的模式(略)

需要注册自己的key,故略去。

注:

  • python中frozenset类型,是指被“冰冻”的集合,就是说它们是不可改变的,用户不能修改它们。frozenset和set的还有个区别是frozenset可以作为字典的键值使用。
  • python中的List.append(obj),List.extend(obj),List.insert(index,obj)之间的区别是,append是在列表末尾添加一个新元素obj,extend是在列表末尾添加obj中的所有元素,inset是在特定的位置添加一个新元素。
  • 参照该页面了解votesmart包。
  • 有一个组织(致力于将政府数据公开化的组织)是智能投票工程Project Vote Smart,它提供了一个公共的API,可以方便我们从votesmart.org获取数据。第一,安装python-votesmart,第二,获得API key(需要在http://votesmart.org/share/api/register申请自己的key),这样就可以使用votesmartAPI了。
  • python中set集合运算

你可能感兴趣的:(使用Apriori算法进行关联分析(python2))