1.主要概念
关联分析:从大规模数据集中寻找物品间隐含关系
频繁项集:经常出现在一起的物品的集合
关联规则:两种物品之间可能存在的关系
支持度:数据集中包含该项集的记录所占的比例
置信度(可信度): 对于规则A-->B 定义可信度=支持度(A,B)/支持度(A),即规则在A中的适应程度
2.Aprior原理
假设四种商品0,1,2,3,则所有可能的项集如下所示:
N中物品,项集可能数有2的N次幂-1,若计算每一种可能项集的支持度,计算量太大。
Aprior原理:某个项集是频繁的,所有子集也是频繁的;若某个项集非频繁,他的所有超集也是非频繁的。
若23非频繁,则023,123,0123必定也非频繁,因此不需要计算其支持度,这样可以大大减少求解的数量。
3.Aprior算法发现频繁集
加载数据集:
def loadDataSet():
return [[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]
根据数据集创建单元素项集C1:
def createC1(dataSet):
C1 = []
#数据集的每一项
for transaction in dataSet:
#每一项的单个元素
for item in transaction:
if not [item] in C1:
C1.append([item])
#进行排序
C1.sort()
#返回一个排序的单元素集合 frozenset表示集合不能被修改
return list(map(frozenset, C1))#use frozen set so we
#can use it as a key in a dict
分解数据集的每一个单元素,放入一个集合中
由C1过滤掉不符合最小支持度的单元素,得到L1
def scanD(D, Ck, minSupport):
#key 项 value次数
ssCnt = {}
#遍历数据集
for tid in D:
#遍历频繁项集
for can in Ck:
#某一项是数据的子集
if can.issubset(tid):
#python3语法改变
if not can in ssCnt: ssCnt[can]=1
else: ssCnt[can] += 1
#总数据数
numItems = float(len(D))
#非频繁项
retList = []
#key 项 value 支持度
supportData = {}
for key in ssCnt:
#支持度
support = ssCnt[key]/numItems
if support >= minSupport:
#记录非频繁项
retList.insert(0,key)
supportData[key] = support
return retList, supportData
返回为单元素的非频繁项集,以及单元素频繁项集的支持度。
由Lk得到Ck,由Lk两两合并,得到不重复的Ck 0,1,2 (0,1) (0,2 ) (1,2)
def aprioriGen(Lk, k): #creates Ck
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
return retList
为了避免不必要的集合重复操作比较两个项集前K-2个元素,如果相同则进行合并。如果相同,前k-2个元素相同,合并之后新项集变为k长度。
由数据集产生一定支持度的频繁项集:
def apriori(dataSet, minSupport = 0.5):
C1 = createC1(dataSet)
D = list(map(set, dataSet))
L1, supportData = scanD(D, C1, minSupport)
L = [L1]
k = 2
while (len(L[k-2]) > 0):
Ck = aprioriGen(L[k-2], k)
Lk, supK = scanD(D, Ck, minSupport)#scan DB to get Lk
supportData.update(supK)
L.append(Lk)
k += 1
return L, supportData
数据集--C1---L1---...Ck----Lk 返回最终的频繁项集。
4.频繁项集挖掘关联规则
关联规则可信度的定义 规则P--->H可信度: support(P|H)/support(P)
根据频繁项集先生成一个可能的关联规则集合,然后逐一测试可信度,把不满足可信度的规则去掉
当某一条规则不满足可信度时,那么所有子集也都不满足可信度要求。
由频繁项集以及频繁项集的项与支持度来产生关联规则
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
for freqSet in L[i]:
H1 = [frozenset([item]) for item in freqSet]
if (i > 1):
rulesFromConseq(freqSet, H1, supportData, bigRuleList, minConf)
else:
calcConf(freqSet, H1, supportData, bigRuleList, minConf)
return bigRuleList
例如频繁项集L:
[[frozenset({5}), frozenset({2}), frozenset({3}), frozenset({1})], [frozenset({2, 3}), frozenset({3, 5}), frozenset({2, 5}), frozenset({1, 3})], [frozenset({2, 3, 5})], []]
对应的支持度:
{frozenset({1}): 0.5, frozenset({3}): 0.75, frozenset({4}): 0.25, frozenset({2}): 0.75, frozenset({5}): 0.75, frozenset({1, 3}): 0.5, frozenset({2, 5}): 0.75, frozenset({3, 5}): 0.5, frozenset({2, 3}): 0.5, frozenset({1, 5}): 0.25, frozenset({1, 2}): 0.25, frozenset({2, 3, 5}): 0.5}
初始i=1 首先计算长度为1的项集的可信度,直接计算即可,可信度大于0.7 记录下来输出。
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
一条规则对应左边--右边 ,H对应右边项
freqSet频繁项集 H可以出现在元素右侧的元素列表
计算H的长度,如果频繁项集长度大于len(H)+1,说明H应该继续合并以产生长度更长的集合,计算新集合与频繁项集的可信度,如果新集合中长度大于1,则继续合并。
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
rulesFromConseq(freqSet, Hmp1, supportData, brl, minConf)
观察了另一位大神的代码,思路清晰多了:
https://blog.csdn.net/hanghangaidoudou/article/details/79306220
规则形式 左边---右边
左边由频繁项集产生 右边首先是长度为1的可能选项,然后通过合并长度来产生更长的长度。例如:
{1} {2} {3} {1,2} {1,3} {123} {1234}
当频繁项的长度l==1时,此时是无法推导出关联规则
l==2时 以{1,2} 可能的规则 12---1 12---2 分别检查每一种的可信度 右边元素记录在H
l>2时,123 首先测试 123-1 123-2 123-3 然后测试123--12 123-13 123-23
1234 1234-1 1234-2 1234-3 1234-4 1234-12 1234-13 1234-14 1234-23 1234-24 1234-34 1234-123 1234-134 1234-234
def getBigRule(freq,support,minConf=0.5):
'''
input:
freq : the frequent k-itemset,k=1,2,...n
support: corresponding support
outpur:
bigRuleList: a list of all the rule that satisfy min confidence
'''
bigRuleList=[]
m=len(freq)
for i in range(1,m):
genRules(freq[i],support,bigRuleList,minConf)
return bigRuleList
def genRules(freq,support,brl,minConf=0.5):
'''
extract rules that satisfy min confidence from a list of k-itemset(k>1)
put the eligible rules in the brl
'''
#如果频繁项集为空,则直接返回
if len(freq)==0:return
#如果频繁项集每一项长度2 1,2 则规则是1,2---1 1,2---2
if len(freq[0])==2: #handle 2-itemset
for itemset in freq:
for conseq in itemset:
conseq=frozenset([conseq])
#集合做差
conf=support[itemset]/support[itemset-conseq]
if conf>=minConf:
print (itemset-conseq, '-->',conseq,'conf:',conf)
brl.append((itemset-conseq,conseq,conf))
elif len(freq[0])>2:
H=[]
# 1,2,3 ---1 2 3
for itemset in freq:
# first generate 1-consequence list
#123--1 123--2 123--3
for conseq in itemset:
conseq=frozenset([conseq])
conf=support[itemset]/support[itemset-conseq]
if conf>=minConf:
print (itemset-conseq, '-->',conseq,'conf:',conf)
brl.append((itemset-conseq,conseq,conf))
H.append(conseq)
m=2
# generate 2,...,k-1 consequence
# 123--12 123--13 123--23
while m<len(freq[0]):
H=generateLk(H,m)
for conseq in H:
conf=support[itemset]/support[itemset-conseq]
if conf>=minConf:
print (itemset-conseq, '-->',conseq,'conf:',conf)
brl.append((itemset-conseq,conseq,conf))
m+=1
def generateLk(freq,k):
'''
input:
freq: the itemset in freq is k-1 itemset
k: create k-itemset from k-1_itemset
output:
Lk:a list of k-itemset,frequent and infrequent
'''
Lk=[]
for i in range(0,len(freq)-1):
for j in range(i+1,len(freq)):
if list(freq[i])[0:k-2]==list(freq[j])[0:k-2]:#fore k-1 item is identity
Lk.append(frozenset(freq[i]|freq[j]))
return Lk