1 Apriori 算法
学习博客:http://blog.csdn.net/qq675927952/article/details/6707704
Apriori 算法是一关联规则算法,很多数据挖掘算法是在Apriori算法基础上改进的,比如散列、基于数据分隔的方法。
关联规则的目的在于在一个数据集中找出项之间的关系,也称之为购物蓝分析 (market basketanalysis)。例如,购买鞋的顾客,有10%的可能也会买袜子,60%的买面包的顾客,也会买牛奶。这其中最有名的例子就是"尿布和啤酒"的故事了。
关联规则的应用场合。在商业销售上,关联规则可用于交叉销售,以得到更大的收入;在保险业务方面,如果出现了不常见的索赔要求组合,则可能为欺诈,需要作进一步的调查。在医疗方面,可找出可能的治疗组合;在银行方面,对顾客进行分析,可以推荐感兴趣的服务等等。
首先我们来看,什么是规则?规则形如"如果…那么…(If…Then…)",前者为条件,后者为结果。例如一个顾客,如果买了可乐,那么他也会购买果汁。
如何来度量一个规则是否够好?有两个量,置信度(Confidence)和支持度(Support)。假设有如下表的购买记录。
顾客 |
项目 |
1 |
orangejuice, coke |
2 |
milk,orange juice, window cleaner |
3 |
Orange juice, detergent |
4 |
Orange juice, detergent, coke |
5 |
Window cleaner |
将上表整理一下,得到如下的一个2维表
|
Orange |
WinCl |
Milk |
Coke |
Detergent |
Orange |
4 |
1 |
1 |
2 |
2 |
WinCl |
1 |
2 |
1 |
0 |
0 |
Milk |
1 |
1 |
1 |
0 |
0 |
Coke |
2 |
0 |
0 |
2 |
1 |
Detergent |
1 |
0 |
0 |
0 |
2 |
上表中横栏和纵栏的数字表示同时购买这两种商品的交易条数。如购买有Orange的交易数为4,而同时购买Orange和Coke的交易数为2。
置信度表示了这条规则有多大程度上值得可信。设条件的项的集合为A,结果的集合为B。置信度计算在A中,同时也含有B的概率。即Confidence(A==>B)=P(B|A)。例如计算"如果Orange则Coke"的置信度。由于在含有Orange的4条交易中,仅有2条交易含有Coke.其置信度为0.5。
支持度计算在所有的交易集中,既有A又有B的概率。例如在5条记录中,既有Orange又有Coke的记录有2条。则此条规则的支持度为2/5=0.4。现在这条规则可表述为,如果一个顾客购买了Orange,则有50%的可能购买Coke。而这样的情况(即买了Orange会再买Coke)会有40%的可能发生。
再来考虑下述情况。
项 |
支持度 |
A |
0.45 |
B |
0.42 |
C |
0.4 |
A andB |
0.25 |
A andC |
0.2 |
B andC |
0.15 |
A,B,andC |
0.05 |
可得到下述规则
规则 |
置信度 |
If B and C thenA |
0.05/0.15*100%=33.33% |
If A and C thenB |
0.05/0.20*100%=25% |
If A and B thenC |
0.05/0.25*100%=20% |
上述的三条规则,哪一条规则有用呢?
对于规则" If B and CthenA",同时购买B和C的人中,有33.33%会购买A。而单项A的支持度有0.45,也就是说在所有交易中,会有45%的人购买A.看来使用这条规则来进行推荐,还不如不推荐,随机对顾客进荐好了。
为此引入另外一个量,即提升度(Lift),以度量此规则是否可用。描述的是相对于不用规则,使用规则可以提高多少。有用的规则的提升度大于1。计算方式为Lift(A==>B)=Confidence(A==>B)/Support(B)=Support(A==>B)/(Support(A)*Support(B))。在上例中,Lift(IfB and C The A)=0.05/(0.15*0.45)=0.74。而Lift(If A thenB)=0.25/(0.45*0.42)=1.32。也就是说对买了A的人进行推荐B,购买概率是随机推荐B的1.32倍。lift(A->B) = P(AB)/(P(A)P(B))
如何产生规则呢。可以分两步走。
首先找出频繁集(frequentitemset)。所谓频繁集指满足最小支持度或置信度的集合。其次从频繁集中找出强规则(strongrules)。强规则指既满足最小支持度又满足最小置信度的规则。
我们来看如何产生频繁集。
这其中有一个定理。即频繁集的子集也一定是频繁集。比如,如果{A,B,C}是一个3项的频繁集,则其子集{A,B},{B,C},{A,C}也一定是2项的频繁集。为方便,可以把含有k项的集合称之为k-itemsets.
下面以迭代的方式找出频繁集。首先找出1-itemsets的频繁集,然后使用这个1-itemsets,进行组合,找出2-itemsets的频繁集。如此下去,直到不再满足最小支持度或置信度的条件为止。这其中重要的两步骤分别是连接(join)和剪枝(prune).即从(k-1)-itemsets中的项进行组合,产生备选集(Candidateitemsets)。再从备选集中,将不符合最小支持度或置信度的项删去。例如
产生被备选集的方法,分为两步,第一步join,第二步prue,描述如下
算法描述如下
之后再从备选集中选出支持度大于最小minsup的作为LK
Frequent2-itemsets |
|
Candidate3-itemsets |
|
Frqquent3-itemsets |
I1,I2 |
==> |
I1,I2,I4 |
==> |
I1,I2,I4 |
I1,I4 |
|
I2,I3,I4 |
|
|
I2,I3 |
|
|
|
|
I2,I4 |
|
|
|
|
下面我们再来看一个详细的例子。
设最小支持度为2,以Ck表示k-itemsets备选集,以Lk表示k-itemsets频繁集。
ID |
Items |
|
Itemset |
Sup.count |
|
Itemset |
|
Itemset |
100 |
I1,I2,I5 |
|
I1 |
6 |
|
I1 |
|
I1,I2 |
200 |
I2,I4 |
==>C1: |
I2 |
7 |
==>L1: |
I2 |
==>C2 |
I1,I3 |
300 |
I2,I3 |
|
I3 |
6 |
|
I3 |
|
I1,I4 |
400 |
I1,I2,I4 |
|
I4 |
2 |
|
I4 |
|
I1,I5 |
500 |
I1,I3 |
|
I5 |
2 |
|
I5 |
|
I2,I3 |
600 |
I2,I3 |
|
|
|
|
|
|
I2,I4 |
700 |
I1,I3 |
|
|
|
|
|
|
I2,I5 |
800 |
I1,I2,I3,I5 |
|
|
|
|
|
|
I3,I4 |
900 |
I1,I2,I3 |
|
|
|
|
|
|
I3,I5 |
|
|
|
|
|
|
|
|
I4,I5 |
对C2进行扫描,计算支持度。
Itemset |
Sup.count |
|
Itemset |
|
Itemset |
Sup.count |
|
Itemset |
|
I1,I2 |
4 |
==>L2: |
I1,I2 |
==>C3 |
I1,I2,I3 |
2 |
==>L3: |
I1,I2,I3 |
|
I1,I3 |
4 |
|
I1,I3 |
|
I1,I2,I5 |
2 |
|
I1,I2,I5 |
|
I1,I4 |
1 |
|
I1,I5 |
|
|
|
|
|
|
I1,I5 |
2 |
|
I2,I3 |
|
|
|
|
|
|
I2,I3 |
4 |
|
I2,I4 |
|
|
|
|
|
|
I2,I4 |
2 |
|
I2,I5 |
|
|
|
|
|
|
I2,I5 |
2 |
|
|
|
|
|
|
|
|
I3,I4 |
0 |
|
|
|
|
|
|
|
|
I3,I5 |
1 |
|
|
|
|
|
|
|
|
I4,I5 |
0 |
|
|
|
|
|
Python代码求 出所有的频繁项目集
# -*- coding: UTF8 -*-
import sys
import copy
# 采用字典的方式,记录元素的同时,也实现了计算元素个数
def init_pass(T):
C = {}
for t in T:
for i in t:
if i in C.keys():
C[i] += 1
else:
C[i] = 1
return C
#利用F[k-1],经过合并和剪枝实现
#代码的实现,是考虑比较理想的模型,比如每一个子集都是完全排好序,且是数字或者字符比较大小的方法
def candidate_gen(F):
C = []
k = len(F[0]) + 1 #当前F为K项集,则传入参数F为K-1项频繁集
for f1 in F: #
for f2 in F: # 已经默f1\f2已经排好序了
if f1[k-2] < f2[k-2]: # 如果对于不是数字型,如中文内容的应该如何比较呢,还得设置函数了么
c = copy.copy(f1)
c.append(f2[k-2])
flag = True
for i in range(0,k-1): #K-1项集,去掉第K-1项,实时上就是上述的f1,无须验证,所以到k-2即可
s = copy.copy(c) #拷贝
s.pop(i) #去掉一个,重新生成k-1维度的
if s not in F:
flag = False #如果新城的k维项目集有子集不属于k-1维度的项目,那么舍弃
break
if flag and c not in C:
C.append(c)
return C
# 判断两个序列是否有包含关系
def compare_list(A,B):
if len(A) <= len(B):
for a in A:
if a not in B:
return False
else:
for b in B:
if b not in A:
return False
return True
# 求出满足最小支持度的项目集合
def apriori(T, minsup):
C = []
init = init_pass(T) #
keys = init.keys()
keys.sort() #排序,事实上,如果这里排好序了,那么后续的已经都是有序的了
C.append(keys) #1-项目集 可能的元素
print C
n = len(T) #求出事物集的个数
F = [[]]
for f in C[0]:
if init[f]*1.0/n >= minsup:
F[0].append([f])
k = 1 # 此时获得1项目集
while F[k-1] != []:
C.append(candidate_gen(F[k-1]))
F.append([]) # 这个很重要,每次先加入一个空集合
for c in C[k]:
count = 0;
for t in T: # 一次加载一个事物集合
if compare_list(c,t): #判断两个集合是否相互包含
count += 1
if count*1.0/n >= minsup:
F[k].append(c)
k += 1
U = []
for f in F:
for x in f:
U.append(x)
return U
def printlist(T):
for i in range(len(T)):
for j in range(len(T[i])):
print T[i][j],
T = [['A','B','C','D'],['B','C','E'],['A','B','C','E'],['B','D','E'],['A','B','C','D']]
F = apriori(T, 0.3)
print F
print len(F)