关联分析
关联分析即从数据集中发现项之间的隐藏关系。apriori算法主要是基于频繁项集的关联分析。
关联规则挖掘有两个步骤:
- 寻找频繁项集
- 从频繁项集产生关联规则
apriori性质
任一频繁项集的所有非空子集也必须是频繁项集。这个项集可以在生成k-itemset的候选项时,如果这个候选项的(k-1)子集中有某个子集不存在(k-1)-itemset中,那么这个候选项直接删除,即不是k-itemset频繁项集。
apriori算法具体步骤
apriori算法实现
def loadDataSet():
''' 生成测试数据集
'''
return [
[1,3,4],[2,3,5],[1,2,3,5],[2,5]
]
def createC1(dataSet):
''' 获取1-item候选集
:param dataSet:
:return: 1-item候选集
'''
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(dataSet, Ck, minSupport):
''' 获取k-item频繁项集
:param dataSet:
:param Ck: 候选集
:param minSupport:
:return: 频繁项集
'''
ssCnt = {}
for tid in dataSet:
for can in Ck:
if can.issubset(tid):
if not can in ssCnt.keys():
ssCnt[can] = 1
else:
ssCnt[can] += 1
numItems = float(len(dataSet))
retList = []
supportData = {}
for key in ssCnt:
support = ssCnt[key]/numItems
if support >= minSupport:
retList.insert(0, key)
supportData[key] = support
return retList,supportData
def genCk(Lk, K):
'''从k-item频繁项集中生成k+1-item候选集,原则:保证前K-2项相同,
:param Lk: 频繁项集
:param K:
:return: 候选集
'''
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):
'''寻找频繁项集
:param dataSet:
:param minSupport: 最小支持度--某个频繁项集在所有事务中出现的频率的最小值
:return:所有维度的频繁项集,以及支持度
'''
C1 = createC1(dataSet)
L1,supportData = scanD(dataSet, C1, minSupport)
L = [L1]
k = 2
while (len(L[k-2]) > 0):
Ck = genCk(L[k-2], k)
Lk, supK = scanD(dataSet, Ck, minSupport)
supportData.update(supK)
L.append(Lk)
k += 1
return L,supportData
一个优化:genCk函树用来生成候选项,生成的候选项Ck可能很多,导致寻找Lk时计算量很大。为了压缩Ck,可用用上述apriori性质做剪枝。
添加has_infrequent_subset函数,genCk函数添加候选时调用这个函数做一步判断。
def genCk(Lk, K):
'''从k-item频繁项集中生成k+1-item候选集,原则:保证前K-2项相同,
:param Lk: 频繁项集
:param K:
:return: 候选集
'''
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:
Lkij = Lk[i] | Lk[j]
if has_infrequent_subset(Lkij, Lk):
retList.append(Lkij)
return retList
def has_infrequent_subset(candidate, itemsets):
''' 假设candidate是k候选项,判断candidate的k-1子集中是否有不存在k-1候选项中的项
:param candidate:
:param itemsets:
:return:
'''
tmpSet = set(candidate)
for item in tmpSet:
cc = tmpSet.copy()
cc.remove(item)
if not frozenset(cc) in itemsets:
return False
return True
apriori算法介绍完毕!!