Apriori关联分析
关联分析同样是无监督学习中的算法,个人理解,k-means算法是计算无类别连续量之间的关系,而Apriori算法则是计算无类别离散量之间的关系。
对于联系量来说,样本之间的关系可以用距离来表示,但对于离散量,我们要定义新的关系:
-
频繁项集:是经常出现在一块的属性的集合,比如对于西瓜{色泽=浅绿,触感=硬滑}
-
支持度:是对于一个集合来说的,是数据集中包含该项集的比例,比如一共有10个西瓜,其中有7个西瓜满足{色泽=浅绿,触感=硬滑},则该频繁项集的支持度为0.7
频繁项集就是支持度大于一定值的集合
-
置信度:是对于一种关联关系来说,比如色泽=浅绿 → \rightarrow → 触感=硬滑,这个关系的置信度为0.7,意义是如果一个西瓜色泽是浅绿,则有百分之70的概率其触感是硬滑,置信度的计算方式
C o n f ( P → H ) = s u p p o r t ( P ∪ H ) s u p p r o t ( P ) , 其 中 C o n f 为 置 信 度 函 数 , s u p p o r t 为 支 持 度 函 数 Conf(P\rightarrow H)=\frac{support(P\cup H)}{supprot(P)},\\ 其中Conf为置信度函数,support为支持度函数 Conf(P→H)=supprot(P)support(P∪H),其中Conf为置信度函数,support为支持度函数
含义很好理解,就是出现 P P P和 H H H的概率除以出现 P P P的概率,找出置信度高的关系很有必要。
如果想要找出所有频繁项集,一个方法是遍历数据暴力搜索所有可能的集合,这样搜索非常慢,但是Apriori原理会帮助到我们,Apriori原理是如果某个项集是频繁的,那么它所有子集也是频繁的,如果一个项集是非频繁的,那么任何包含这个项集的集合也是非频繁的
那么我们只需要遍历搜索的时候只需要从最小的频繁项集出发,这样大大减少了计算时间
而对于找出置信度高的关系,也要从频繁项集出发
python实现
- 找出频繁项集:
- 首先得到多个只含一个属性的集合,比如{色泽=浅绿},{色泽=乌黑},{触感=硬滑}等
- 对于上述每个集合,求出其是否出现在每一个样本中,便可得到支持度
- 筛选出支持度大于阈值的集合 C C C,其中每个元素为支持度大于阈值的项集
- 对于项集 C C C中的每个元素生成组合项集
- 对于组合项集同样看其是否出现则每个样本中,算出支持度
- 重复步骤3,直至集合 C C C为空
def createC1(dataSet):#步骤1
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(D,Ck,minSupport):#遍历样本计算项集的支持度
ssCnt = {}
for tid in D:#D为数据集 则tid为每个样本
for can in Ck:#集合C中的元素,即要求支持度的项集
if can.issubset(tid):
if can not in ssCnt.keys():
ssCnt[can]=0
ssCnt[can] += 1
#ssCnt这个集合记录了C中每个集合的出现次数
numItems = float(len(D))
retList = []
supportData = {}
for key in ssCnt:
support = ssCnt[key]/numItems
if support >= minSupport:
retList.append(key)
supportData[key] = support
retList.sort()
return retList,supportData #返回支持度大于阈值的项集及其对应的支持度
def aprioriGen(Lk,k): #对于频繁项集的集合生成其组合,如{1},{2}生成{1,2}
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=0.5):#Apriori算法主函数
C1 = createC1(dataSet) #步骤1
D = list(map(set,dataSet))
L1,supportData = scanD(D,C1,minSupport) #步骤2和步骤3
L = [L1] #记录频繁项集,L=[[包含一个元素的频繁项集],[包含两个元素的频繁项集]]
k = 2
while (len(L[k-2]) > 0):
Ck = aprioriGen(L[k-2],k) #步骤4
Lk,supK = scanD(D,Ck,minSupport) #步骤5
supportData.update(supK)
L.append(Lk)
k += 1
return L,supportData
-
计算关联度:
既然是关联关系,则从包含两个元素的频繁项集开始,并且还由一个原理就是
如果A → \rightarrow →B的置信度较低,则任意左部为A的子集的关系的置信度也会较低
- 若频繁项集只有两个元素如{1,2}:
- 输入为{1,2}和[{1},{2}]
- 算出{2} → \rightarrow →{1}(实际是算{1,2}/{1} → \rightarrow →{1})的置信度和{1} → \rightarrow →{2}的置信度(实际是算{1,2}/{2} → \rightarrow →{2})
- 若频繁项集有大于两个元素如{1,2,3,4}:
- 输入为S={1,2,3,4}和H=[{1},{2},{3},{4}]
- 首先对于H生成组合[{1,2},{1,3},{1,4},{2,3},{2,4},{3,4}]
- 算出{3,4} → \rightarrow →{1,2}(实际是算{1,2,3,4}/{1,2} → \rightarrow →{1,2}),以此类推,并记录符合置信度阈值的左部项集
- 对于符合置信度的项集,例如[{1,2},{1,3}],同样生成组合[{1,2,3}],更新H
- 算出{4} → \rightarrow →{1,2,3}(实际是算{1,2,3,4}/{1,2,3} → \rightarrow →{1,2,3})的置信度,同样返回置信度高的关系的左部,并生产组合更新H
- 如果H为空了则可以停止
可以看出第2,3步和第4,5步是一样的,则可以采用递归,
有点绕是不是def generateRules(L,supportData,minConf=0.7): bigRuleList = [] for i in range(1,len(L)): for freqSet in L[i]: H1 = [frozenset([item]) for item in freqSet]#步骤1 if i>1 : rulesFromConseq(freqSet,H1,supportData,bigRuleList,minConf) #步骤1.1和1.2 else: calcConf(freqSet,H1,supportData,bigRuleList,minConf) #步骤2 return bigRuleList def calcConf(freqSet,H,supportData,br1,minConf=0.7):#计算置信度 prunedH = [] for conseq in H: conf = supportData[freqSet]/supportData[freqSet-conseq] if conf >= minConf: # print(freqSet-conseq,'--->',conseq,'conf:',conf) br1.append((freqSet-conseq,conseq,conf)) prunedH.append(conseq) return prunedH #返回置信度较高的项集 def rulesFromConseq(freqSet,H,supportData,br1,minConf=0.7): m = len(H[0]) print(H) if (len(freqSet) > (m+1)): Hmp1 = aprioriGen(H,m+1) #步骤2.2 Hmp1 = calcConf(freqSet,Hmp1,supportData,br1,minConf)#步骤2.3 if len(Hmp1) > 1: rulesFromConseq(freqSet,Hmp1,supportData,br1,minConf)
测试
对于一个蘑菇数据(部分)
1 3 9 13 23 25 34 36 38 40 52 54 59 63 67 76 85 86 90 93 98 107 113
2 3 9 14 23 26 34 36 39 40 52 55 59 63 67 76 85 86 90 93 99 108 114
2 4 9 15 23 27 34 36 39 41 52 55 59 63 67 76 85 86 90 93 99 108 115
1 3 10 15 23 25 34 36 38 41 52 54 59 63 67 76 85 86 90 93 98 107 113
2 3 9 16 24 28 34 37 39 40 53 54 59 63 67 76 85 86 90 94 99 109 114
第一项为蘑菇毒性(2为有毒,1为无毒)
第二项为蘑菇形状(有六种可能取值3~8),第三项第4项以此类推
为了探究毒蘑菇的共同特征,可以使用Apriori算法,设置minSupport=0.3
可以得到包含2个属性的频繁项集
{2, 23}
{34, 2}
{2, 36}
{2, 59}
{2, 63}
{2, 67}
{2, 76}
{2, 85}
{2, 86}
{90, 2}
{2, 93}
{2, 39}
{2, 28}
{2, 53}
可以查23代表什么,34代表什么,从而得到毒蘑菇的特征