Apriori algorithm是关联规则里一项基本算法。是由Rakesh Agrawal和Ramakrishnan Srikant两位博士在1994年提出的关联规则挖掘算法。关联规则的目的就是在一个数据集中找出项与项之间的关系,也被称为购物蓝分析 (Market Basket analysis),因为“购物蓝分析”很贴切的表达了适用该算法情景中的一个子集。
 该算法的具体思想可以参考这个网址了解:
 接下来,我向分享如何用代码实现Apriori算法,步骤如下:
 1.创建apriori类
 

class Apriori:
    def __init__(self,min_sup=0.2,dataDic={}):
        self.data = dataDic  ##构建数据记录词典,形如{'T800': ['I1', 'I2', 'I3', 'I5'],...}
        self.size = len(dataDic) #统计数据记录的个数
        self.min_sup = min_sup  ##最小支持度的阈值
        self.min_sup_val = min_sup * self.size ##最小支持度计数

2.过滤掉小于最小支持度阈值的物品

def find_frequent_1_itemsets(self):
        FreqDic = {} #{itemset1:freq1,itemsets2:freq2},用于统计物品的支持度计数
        for event in self.data:  ##event为每一条记录,如T800
            for item in self.data[event]: ##item就是I1,I2,I3,I4,I5
                if item in FreqDic:
                    FreqDic[item] += 1
                else:
                    FreqDic[item] = 1
        L1 = []
        for itemset in FreqDic:
            if FreqDic[itemset] >= self.min_sup_val: ##过滤掉小于最小支持度阈值的物品
                L1.append([itemset])
        return L1

3.过滤掉非频繁项集

def has_infrequent_subset(self,c,L_last,k):
        ## c为当前集合,L_last为上一个频繁项集的集合,k为当前频繁项集内的元素个数,
        ## 该函数用于检查当前集合的子集是否 都为频繁项集
        subsets = list(itertools.combinations(c,k-1)) #itertools是排列组合模块,目的就c分解,如[1,2,3]将分成[(1,2),(1,3),(2,3)]
        for each in subsets:
            each = list(each) #将元组转化为列表
            if each not in L_last:  ##子集是否 都为频繁项集
                return True
        return False

补充说明:
itertools是排列组合模块,例如 list(itertools.combinations([1,2,3],2))就能分解成[(1,2),(1,3),(2,3)]

4.合并形成新的频繁项集

def apriori_gen(self,L_last): #L_last means frequent(k-1) itemsets
        k = len(L_last[0]) + 1
        Ck = []
        ##
        for itemset1 in L_last:
            for itemset2 in L_last:
                #join step
                flag = 0
                for i in range(k-2):
                    print k-2
                    if itemset1[i] != itemset2[i]:
                        flag = 1 ##若前k-2项中如果有一个项是不相等,新合并的集合是不可能是频繁项集
                        break;
                if flag == 1:continue
                if itemset1[k-2] < itemset2[k-2]:
                    c = itemset1 + [itemset2[k-2]]
                else:
                    continue

                #pruning setp
                if self.has_infrequen`t`_subset(c,L_last,k):##判断子集是否为频繁项集
                    continue
                else:
                    Ck.append(c)
        return Ck

5.关联分析迭代形成频繁项集

def do(self):
        L_last = self.find_frequent_1_itemsets() ##过滤掉小于最小支持度阈值的物品
        L = L_last
        i = 0
        while L_last != []:
            Ck = self.apriori_gen(L_last) ##合并形成新的频繁项集
            FreqDic = {}
            for event in self.data:
                #get all suported subsets
                for c in Ck: ##统计新形成的频繁项集的个数
                    if set(c) <= set(self.data[event]):#判断新合成的频繁项目是否为数据记录的子集
                        if tuple(c) in FreqDic:
                            FreqDic[tuple(c)]+=1
                        else:
                            FreqDic[tuple(c)]=1
            print FreqDic
            Lk = []
            for c in FreqDic:
                print c
                print '------'
                if FreqDic[c] > self.min_sup_val:##判断新形成的频繁项集是否大于最小支持度的阈值
                    Lk.append(list(c))
            L_last = Lk
            L += Lk
        return L  ## L就是新形成的频繁项集的集合

测试样例
Data = {'T100':['I1','I2','I5'],
'T200':['I2','I4'],
'T300':['I2','I3'],
'T400':['I1','I2','I4'],
'T500':['I1','I3'],
'T600':['I2','I3'],
'T700':['I1','I3'],
'T800':['I1','I2','I3','I5'],
'T900':['I1','I2','I3']}

完整代码:

#! -*- coding:utf-8 -*-
import itertools

class Apriori:
    def __init__(self,min_sup=0.2,dataDic={}):
        self.data = dataDic  ##构建数据记录词典,形如{'T800': ['I1', 'I2', 'I3', 'I5'],...}
        self.size = len(dataDic) #统计数据记录的个数
        self.min_sup = min_sup  ##最小支持度的阈值
        self.min_sup_val = min_sup * self.size ##最小支持度计数

    def find_frequent_1_itemsets(self):
        FreqDic = {} #{itemset1:freq1,itemsets2:freq2},用于统计物品的支持度计数
        for event in self.data:  ##event为每一条记录,如T800
            for item in self.data[event]: ##item就是I1,I2,I3,I4,I5
                if item in FreqDic:
                    FreqDic[item] += 1
                else:
                    FreqDic[item] = 1
        L1 = []
        for itemset in FreqDic:
            if FreqDic[itemset] >= self.min_sup_val: ##过滤掉小于最小支持度阈值的物品
                L1.append([itemset])
        return L1

    def has_infrequent_subset(self,c,L_last,k):
        ## c为当前集合,L_last为上一个频繁项集的集合,k为当前频繁项集内的元素个数,
        ## 该函数用于检查当前集合的子集是否 都为频繁项集
        subsets = list(itertools.combinations(c,k-1)) #itertools是排列组合模块,目的就c分解,如[1,2,3]将分成[(1,2),(1,3),(2,3)]
        for each in subsets:
            each = list(each) #将元组转化为列表
            if each not in L_last:  ##子集是否 都为频繁项集
                return True
        return False

    def apriori_gen(self,L_last): #L_last means frequent(k-1) itemsets
        k = len(L_last[0]) + 1
        Ck = []
        ##
        for itemset1 in L_last:
            for itemset2 in L_last:
                #join step
                flag = 0
                for i in range(k-2):
                    print k-2
                    if itemset1[i] != itemset2[i]:
                        flag = 1 ##若前k-2项中如果有一个项是不相等,新合并的集合是不可能是频繁项集
                        break;
                if flag == 1:continue
                if itemset1[k-2] < itemset2[k-2]:
                    c = itemset1 + [itemset2[k-2]]
                else:
                    continue

                #pruning setp
                if self.has_infrequent_subset(c,L_last,k):##判断子集是否为频繁项集
                    continue
                else:
                    Ck.append(c)
        return Ck

    def do(self):
        L_last = self.find_frequent_1_itemsets() ##过滤掉小于最小支持度阈值的物品
        L = L_last
        i = 0
        while L_last != []:
            Ck = self.apriori_gen(L_last) ##合并形成新的频繁项集
            FreqDic = {}
            for event in self.data:
                #get all suported subsets
                for c in Ck: ##统计新形成的频繁项集的个数
                    if set(c) <= set(self.data[event]):#判断新合成的频繁项目是否为数据记录的子集
                        if tuple(c) in FreqDic:
                            FreqDic[tuple(c)]+=1
                        else:
                            FreqDic[tuple(c)]=1
            print FreqDic
            Lk = []
            for c in FreqDic:
                print c
                print '------'
                if FreqDic[c] > self.min_sup_val:##判断新形成的频繁项集是否大于最小支持度的阈值
                    Lk.append(list(c))
            L_last = Lk
            L += Lk
        return L  ## L就是新形成的频繁项集的集合

#******Test******
Data = {'T100':['I1','I2','I5'],
        'T200':['I2','I4'],
        'T300':['I2','I3'],
        'T400':['I1','I2','I4'],
        'T500':['I1','I3'],
        'T600':['I2','I3'],
        'T700':['I1','I3'],
        'T800':['I1','I2','I3','I5'],
        'T900':['I1','I2','I3']}

a=Apriori(dataDic=Data)
# print a.do()
a.do()