#coding=utf-8
def load_data():
return [[1,3,4],[2,3,5],[1,2,3,5],[2,5]]
def create_c1(data):
#把数据中单个元素转成列表格式,且不重复。
c1=[]
for transaction in data:
for item in transaction:
if not [item] in c1:
c1.append([item])
c1.sort()
return map(frozenset,c1)
def prob(set_data,c1,min_frequency):
#计算各种组合在数据中出现的概率并选出大于最小概率的组合
ss_cnt={}
for tid in set_data:
for can in c1:
if can.issubset(tid):
#判断can是否在tid中
if not ss_cnt.has_key(can):ss_cnt[can]=1
#如果字典中不含can,则加进去并初始值为1
else:ss_cnt[can]+=1
#如果已经存在了,则对其出现次数进行统计
num_items=float(len(set_data))
#就是集合的数量
ret_list=[]
element_frequency={}
for key in ss_cnt:
frequency=ss_cnt[key]/num_items
#也就单个元素出现的频率
if frequency>=min_frequency:
#判断成立的话就在ret_list中首位插入key
ret_list.insert(0,key)
element_frequency[key]=frequency
return ret_list,element_frequency
def p_and_c(lk,k):
#进行排列组合
#步骤:根据最初的到的C1 [1,2,3,5] 俩俩组合 成k=2时的ck 即c2
#再根据c2 [[1,2],[1,3],[1,5],[2,3],[2,5],[3,5]] 三三组合成 k=3时的ck 即 c3
#c4即[1,2,3,5]
ret_list=[]
len_lk=len(lk)
for i in range(len_lk):
for j in range(i+1,len_lk):
l1=list(lk[i])[:k-2]
l2=list(lk[j])[:k-2]
print l1,l2
l1.sort();l2.sort()
if l1==l2:
#这里用并集进行组合,而不用itertools.combinations
#是因为,每次组合都是在前者已经筛选过概率的基础上进行的
#这样可以减少计算量
ret_list.append(lk[i]|lk[j])
#并集
return ret_list
def apriori(data,min_frequency=0.5):
c1=create_c1(data)
d=map(set,data)
l1,element_frequency=prob(d,c1,min_frequency)
l=[l1]
k=2
#k即单个组合中元素数量
while len(l[k-2]) >0:
pc=p_and_c(l[k-2],k)
#获取组合
lk,supk=prob(d,pc,min_frequency)
#计算组合概率并返回大于最小概率的
element_frequency.update(supk)
#更新并添加新的组合
l.append(lk)
print l
k+=1
return l,element_frequency
def test():
data=load_data()
l,s=apriori(data)
print '\n',l,'\n',s
test()
def generate_rules(group,element_frequency,min_conf=0.7):
'''筛选出出现条件概率在min_conf以上的组合'''
#即1出现的情况下3出现的概率,选出这种概率在min_conf上的
result=[]
#大规则列表
for i in range(1,len(group)):
#之所以从1开始是因为group[0]是单个元素,这也是由数据样本定的。
#数据量足够大,也可以从0开始
for freqset in group[i]:
#遍历上面函数计算出的大于某一概率的组合
#分开组合中各元素,打包成列表
h1= [frozenset([item]) for item in freqset]
# print h1
if i > 1:
#i>1是因为组合内元素数超过2了
rules_from_conseq(freqset,h1,element_frequency,result,min_conf)
else:
calculate_probability(freqset,h1,element_frequency,result,min_conf)
return result
def calculate_probability(freqset,h,element_frequency,result,min_conf=0.7):
'''计算条件概率'''
pruned_h=[]
#修剪
for conseq in h:
#遍历组合计算以组合中非conseq为条件的概率
#即组合[2,3],conseq=2,则计算以3为前提下出现组合[2,3]的概率
probability=element_frequency[freqset]/element_frequency[freqset-conseq]
if probability>=min_conf:
#若条件概率大于阈值,则取这个组合并附加到结果里
#并把conseq附加修剪列表,说明该元素不适合做前提条件
print freqset-conseq,'--->',conseq,'probability:',probability
result.append((freqset-conseq,conseq,probability))
pruned_h.append(conseq)
return pruned_h
def rules_from_conseq(freqset,h,element_frequency,result,min_conf=0.7):
'''计算上面函数筛除的元素间是否存在大于指定概率的组合'''
m=len(h[0])
#这里m=1
if len(freqset)>(m+1):
#当组合中元素总数大于2时,将组合内所有元素两两组合
#然后再计算条件概率
hmp1=p_and_c(h,m+1)
hmp1=calculate_probability(freqset,hmp1,element_frequency,result,min_conf)
#返回的hmp1是不适合做前提条件的元素
if len(hmp1)>1:
#若hmp1大于1,则计算这一集合元素间是否存在大于阈值的组合
rules_from_conseq(freqset,hmp1,element_frequency,result,min_conf)