关联分析(Apriori算法 )
假设我们经营一家商品种类并不多的杂货店,我们对那些经常在一起被购买的商品组合感兴趣。设
(1)通过Apriori算法实现从交易记录中找到商品的频繁项集。
(2)通过(1)中计算的频繁项集,挖掘关联规则
设交易清单为[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5],这里的数字代表商品;
设最小支持度为0.5;最小置信度为0.7
#1)通过Apriori算法实现从交易记录中找到商品的频繁项集
def loadDataSet():
return [[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]
# C1 是大小为1的所有候选项集的集合
def createC1(dataSet):
C1 = []
for transaction in dataSet:
for item in transaction:
if not [item] in C1:
C1.append([item]) #store all the item unrepeatly
C1.sort()
#return map(frozenset, C1)#frozen set, user can't change it.
return list(map(frozenset, C1))
#该函数用于从 C1 生成 L1 。
def scanD(D,Ck,minSupport):
#参数:数据集、候选项集列表 Ck以及感兴趣项集的最小支持度 minSupport
ssCnt={}
for tid in D:#遍历数据集
for can in Ck:#遍历候选项
if can.issubset(tid):#判断候选项中是否含数据集的各项
#if not ssCnt.has_key(can): # python3 can not support
if not can in ssCnt:
ssCnt[can]=1 #不含设为1
else:
ssCnt[can]+=1#有则计数加1
numItems=float(len(D))#数据集大小
retList = []#L1初始化
supportData = {}#记录候选项中各个数据的支持度
for key in ssCnt:
support = ssCnt[key]/numItems#计算支持度
if support >= minSupport:
retList.insert(0,key)#满足条件加入L1中
supportData[key] = support
return retList, supportData
#total apriori
def aprioriGen(Lk, k): #组合,向上合并
#creates Ck 参数:频繁项集列表 Lk 与项集元素个数 k
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: #若两个集合的前k-2个项相同时,则将两个集合合并
retList.append(Lk[i] | Lk[j]) #set union
return retList
#apriori
def apriori(dataSet, minSupport = 0.5):
C1 = createC1(dataSet)
D = list(map(set, dataSet)) #python3
L1, supportData = scanD(D, C1, minSupport)#单项最小支持度判断 0.5,生成L1
L = [L1]
k = 2
while (len(L[k-2]) > 0):#创建包含更大项集的更大列表,直到下一个大的项集为空
Ck = aprioriGen(L[k-2], k)#Ck
Lk, supK = scanD(D, Ck, minSupport)#get Lk
supportData.update(supK)
L.append(Lk)
k += 1
return L, supportData
apriori(loadDataSet())[0]
通过设置最小支持度为0.5,算法遍历,我们得到了支持度大于0.5的项集,也就是频繁项集,可以看到频繁项集有{5}, {2}, {3},
{1},{2, 3}, {3, 5}, {2, 5}, {1, 3},{2, 3, 5},这些上平编号的组合。
#(2)通过(1)中计算的频繁项集,挖掘关联规则
#生成关联规则
def generateRules(L, supportData, minConf=0.7):
#频繁项集列表、包含那些频繁项集支持数据的字典、最小可信度阈值
bigRuleList = [] #存储所有的关联规则
for i in range(1, len(L)): #只获取有两个或者更多集合的项目,从1,即第二个元素开始
# 两个及以上的才可能有关联一说,单个元素的项集不存在关联问题
for freqSet in L[i]:
H1 = [frozenset([item]) for item in freqSet]
#该函数遍历L中的每一个频繁项集并对每个频繁项集创建只包含单个元素集合的列表
if (i > 1):
#如果频繁项集元素数目超过2,那么会考虑对它做进一步的合并
rulesFromConseq(freqSet, H1, supportData, bigRuleList, minConf)
else:#第一层时,后件数为1
calcConf(freqSet, H1, supportData, bigRuleList, minConf)# 调用函数2
return bigRuleList
#生成候选规则集合:计算规则的可信度以及找到满足最小可信度要求的规则
def calcConf(freqSet, H, supportData, brl, minConf=0.7):
#针对项集中只有两个元素时,计算可信度
prunedH = []#返回一个满足最小可信度要求的规则列表
for conseq in H:#后件,遍历 H中的所有项集并计算它们的可信度值
conf = supportData[freqSet]/supportData[freqSet-conseq] #可信度计算,结合支持度
if conf >= minConf:
print (freqSet-conseq,'-->',conseq,'conf:',conf)
#如果某条规则满足最小可信度值,那么将这些规则输出到屏幕显示
brl.append((freqSet-conseq, conseq, conf))#添加到规则里,brl 是前面通过检查
prunedH.append(conseq)#同样需要放入列表到后面检查
return prunedH
#合并
def rulesFromConseq(freqSet, H, supportData, brl, minConf=0.7):
#参数:一个是频繁项集,另一个是可以出现在规则右部的元素列表 H
m = len(H[0])
if (len(freqSet) > (m + 1)): #频繁项集元素数目大于单个集合的元素数
Hmp1 = aprioriGen(H, m+1)#存在不同顺序、元素相同的集合,合并具有相同部分的集合
Hmp1 = calcConf(freqSet, Hmp1, supportData, brl, minConf)#计算可信度
if (len(Hmp1) > 1):
#满足最小可信度要求的规则列表多于1,则递归来判断是否可以进一步组合这些规则
rulesFromConseq(freqSet, Hmp1, supportData, brl, minConf)
generateRules(apriori(loadDataSet())[0],apriori(loadDataSet())[1])
每个频繁项集可以产生多个关联规则。如果某条规则并不满足最小可信度(我们设置minConf=0.7)要求,那么该规则的所有子集也不会满足最小可信度要求。
apriori算法,可以首先从一个频繁项集开始,接着创建一个规则列表,其中规则右部只包含一个元素,然后对这些规则进行测试,合并所有剩余规则来创建一个新的规则列表。Apriori算法的两个输入参数分别是最小支持度和数据集。该算法首先会生成所有单个物品的项集列表,接着扫描交易记录来查看哪些项集满足最小支持度要求,那些不满足最小支持度的集合会被去掉。然后。对剩下的集合进行组合以生成包含两个元素的项集。接下里,再重新扫描交易记录,去掉不满足最小支持度的项集,该过程重复进行直到所有项集都被去掉。
上面的实验我们可以看到满足关联规则的项集和他们的可信度。 frozenset({5}) --> frozenset({2}) conf:
1.0 frozenset({2}) --> frozenset({5}) conf: 1.0 frozenset({1}) --> frozenset({3}) conf: 1.0