0
点赞
收藏
分享

微信扫一扫

机器学习实战 -- 使用Apriori 算法进行关联分析


  1. Apriori 算法
  2. 频繁项集生成
  3. 关联规则生成

关联分析

关联分析是在一种在大数据集中寻找有趣关系的任务。这种任务有两种形式: 频繁项集或者关联规则。

频繁项集是经常出现在一块的物品构成的集合。

关联规则是暗示两种物品之间可能存在很强的关系。

支持度:一个项集的支持度被定义为数据集中包含该项集的记录所占的比例。 
可信度或置信度:是针对诸如{尿布}—>{葡萄酒}的关联规则来定义的,这条规则的可信度被定义为:支持度({尿布,葡萄酒})/支持度({尿布})。

支持度和可信度是用来量化关联分析是否成功的方法。

Apriori 原理

Apriori 原理是说如果某个项集是频繁的,那么它所有的子集也是频繁的。如果{0,1} 是频繁项集, 那么 {0} ,{1} 也是频繁的。

但是我们一般反过来用,即如果一个项集是非频繁的,那么它的所有超集也是非频繁的。比如 : {2,3} 是非频繁的,那么 {0,2,3},{1,2,3},{0,1,2,3} 都是非频繁的。使用该原理就可以避免项集数目的指数增长,从而在合理的时间内计算出频繁项集。

使用Apriori算法来发现频繁集 

关联分析的目标包括两项:发现频繁项集和发现关联规则,首先需要先找到频繁项集,然后才能获得关联规则。

Apriori算法的两个输入参数分别是最小支持度和数据集,该算法首先会生成所有单个物品的项集列表,接着扫描交易记录来查看哪些项集满足最小支持度要求,那些不满足最小支持度的集合会被去掉。然后,对生下来的集合进行组合以生成包含两个元素的项集,接下来,再重新扫描交易记录,去掉不满足最小支持度的项集。该过程重复进行,知道所有项集都被去掉。
 

生成候选项集 

伪代码: 

对数据集中的每条交易记录 
对每个候选项集: 
检查一下候选项集是否是记录条的子集: 
如果是,则增加候选集的计数值 
对每个候选项集: 
如果其支持度不低于最小值,则保留该项集 
返回所有频繁项集列表
 

Apriori算法的辅助函数 

import numpy as np


def loadDataSet():
return [[1,3,4],[2,3,5],[1,2,3,5],[2,5]]

def createC1(dataSet) :
# 定义候选项集列表 C1
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) :
'''
:param D: 数据集
:param Ck: 后选项集列表
:param minSupport: 最小支持度
:return: 包含支持度的字典
'''
# 定义存储每个项集在消费记录中出现的次数的字典
ssCnt = {}
# 遍历这个数据集,遍历候选项集合,
# 判断候选项是否是一条记录的子集
D = map(set,dataSet)
for tid in D:
for can in Ck :
# 如果候选项集 是tid 的子集
if can <=tid :
if can.issubset(tid) :
if can in ssCnt.keys():
ssCnt[can] += 1 # 算是初始化
else:
ssCnt[can] = 1
numItems = len(list(dataSet))
# 定义满足最小支持度的候选项集列表
retList = []
# 用于所有项集的支持度
supporData = {}
for key in ssCnt :
# 计算当前项集的支持度
support = ssCnt[key]/numItems
if support >=minSupport :
retList.insert(0,key)
# 记录每个项集的支持度
supporData[key] = support
return retList , supporData

测试 :  

dataSet = loadDataSet()
print(dataSet)
C1 = createC1(dataSet)
print(C1)

L1,suppData = scanD(dataSet,C1,0.5)
print(L1)
print(suppData)

[[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]
[frozenset({1}), frozenset({2}), frozenset({3}), frozenset({4}), frozenset({5})]
[frozenset({5}), frozenset({2}), frozenset({3}), frozenset({1})]
{frozenset({1}): 0.5, frozenset({3}): 0.75, frozenset({4}): 0.25, frozenset({2}): 0.75, frozenset({5}): 0.75}

loadDataSet : 生成测试数据集 。

createC1 : 构建第一个候选项集的列表C1 。

scanD : 筛选出满足最小支持度的项集。返回频繁集列表 和 包含 频繁集支持度的字典 。

测试 : scanD 最后一个参数 是 0.5 ,即筛选出支持度大于等于0.5 的所有项集 ,也可理解为 项集出现在50%以上的记录。

 

Apriori 算法 : 

整个Apriori算法的伪代码如下: 
当集合项中的个数大于0时 
构建一个k个项组成的候选项集的列表 
检查数据以确认每个项集都是频繁的 
保留频繁项集并构建k+1项组成的候选项集列表

# Apriori 算法
def aprioriGen(Lk,k) :
'''
:param Lk: 频繁项集列表 Lk
:param k: 项集元素个数
:return: ck
:example : {0},{1},{2} -> {0,1},{0,2},{1,2}
'''
# 存储Ck的列表
retList = []
lenLk = len(Lk)
for i in range(lenLk) :
for j in range(i+1,lenLk) :
# 选择集合中前k - 2个元素进行比较,如果相等,则对两个集合进行并操作
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) :
C1 = createC1(dataSet)
D = list(map(set,C1) )
L1 ,supportData = scanD(dataSet,C1,minSupport)
L = [L1]
k = 2
# 先生成含两个元素的项集
while(len(L[k-2])>0) :
CK = aprioriGen(L[k-2],k)
Lk,supk = scanD(dataSet,CK,minSupport)
supportData.update(supk)
L.append(Lk)
k+=1
return L,supportData

aprioriGen : 生成 含 k 个元素的所有项集 。 {0},{1},{2} -> {0,1},{0,2},{1,2}

Apriori : 生成所有的满足最小支持度的频繁项集,包含 1 和元素的频繁项集, 含2个元素的频繁项集...等等 。

 测试: 

dataSet = loadDataSet()
L,supp = apriori(dataSet)
print(L)
print(L[0])
print(L[1])
print(L[2])
print(L[3])
print(aprioriGen(L[0],2))

L2 ,s = apriori(dataSet,minSupport=0.7)
print(L2)
print(s)

[[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({5}), frozenset({2}), frozenset({3}), frozenset({1})]
[frozenset({2, 3}), frozenset({3, 5}), frozenset({2, 5}), frozenset({1, 3})]
[frozenset({2, 3, 5})]
[]
[frozenset({2, 5}), frozenset({3, 5}), frozenset({1, 5}), frozenset({2, 3}), frozenset({1, 2}), frozenset({1, 3})]
[[frozenset({5}), frozenset({2}), frozenset({3})], [frozenset({2, 5})], []]
{frozenset({1}): 0.5, frozenset({3}): 0.75, frozenset({4}): 0.25, frozenset({2}): 0.75, frozenset({5}): 0.75, frozenset({2, 5}): 0.75, frozenset({3, 5}): 0.5, frozenset({2, 3}): 0.5}

从频繁项集中挖掘关联规则

对于关联规则,其量化指标为可信度,可信度的计算公式再前面已经提过,这里不再赘述,为找到感兴趣的规则,我们先生成一个可能的规则列表,然后测试每条规则的可信度,如果该规则的可信度不满足最小可信度要求,则去掉该规则。

关联分析的两个重要目标是发现频繁项集与关联规则。要找到关联规则,首先从一个频繁项集开始,集合中的元素是不重复的,但我们想知道基于这些元素能否获得其他内容。某个元素或者某个元素集合可能会推导出另一个元素。例如,一个频繁项集{豆奶, 莴苣},可能有一条关联规则“豆奶→莴苣”,箭头的左边集合称作前件,箭头右边的集合称为后件。

每个频繁项集可产生许多关联规则,如果能够减少规则数目来确保问题的可解性,那么计算起来会好很多。如果某条规则并不满足最小可信度要求,那么该规则的所有子集也不会满足最小可信度要求。利用此性质来减少测试的规则数目,可以先从一个频繁项集开始,接着创建一个规则列表,其中规则右部只包含一个元素,然后对这些规则测试。接下来合并所有剩余规则来创建一个新的规则列表,其中右部包含两个元素 。

机器学习实战 -- 使用Apriori 算法进行关联分析_关联规则

假设 012 -> 3 不满足最小可信度,那么它任何左部为{0,1,2}子集的规则也不会满足最小可信度的要求。

# 关联规则生成函数
#生成关联规则列表[(前件,后件,可信度)]
def generateRules(L,supportData,minConf=0.7):
bigRuleList = []
#遍历整个频繁集列表
for i in range(len(L)):
#遍历每个频繁集
for freqSet in L[i]:
#将频繁集转换为包含频繁集中单个元素的列表,单个整数不能用frozenset()函数,所以这里使用frozenset([item])
#此处保存规后件元素
H1 = [frozenset([item]) for item in freqSet]
#如果频繁集元素个数大于2,则将H1合并
if i>1:
#此函数对规则后件进行合并,创建出多条候选规则,在此函数中计算规则可信度,并将满足可信度的规则加入列表中
#递归创建可能出现的规则
rulesFromConseq(freqSet,H1,supportData,bigRuleList,minConf)
else:
#如果频繁集元素只有两个则直接计算可信度
calcConf(freqSet,H1,supportData,bigRuleList,minConf)
return bigRuleList

def calcConf(freqSet,H,supportData,br1,minConf):
#用于存储满足可信度要求的规则后件集合列表
prunedH = []
#H表示规则后件的元素集合列表,遍历后件集合列表
for conseq in H:
#计算可信度,对于每一个频繁集对应一组规则,对于每一个规则的每一个后件conseq来说,其前件故为freqSet-conseq
#所以此可能规则的可信度为以下计算公式
if(freqSet-conseq)!= frozenset():
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):
#获取后件元素的个数
m = len(H[0])
#如果频繁集元素个数大于规则后件个数
if(len(freqSet) > (m+1)):
#先将后件元素合并为元素大于当前元素数1
Hmp1 = aprioriGen(H,m+1)
#通过calcConf()获得满足可信度要求的后件元素列表
Hmp1 = calcConf(freqSet,Hmp1,supportData,br1,minConf)
#判断合并后是否还会有后件元素,如果有,则继续合并,并计算新生成规则
if(len(Hmp1)>1):
rulesFromConseq(freqSet,Hmp1,supportData,br1,minConf)

测试

L,suppData = apriori(dataSet,minSupport=0.5)
rules = generateRules(L,suppData,minConf=0.7)
print(rules)

frozenset({5}) --> frozenset({2}) conf: 1.0
frozenset({2}) --> frozenset({5}) conf: 1.0
frozenset({1}) --> frozenset({3}) conf: 1.0
[(frozenset({5}), frozenset({2}), 1.0), (frozenset({2}), frozenset({5}), 1.0), (frozenset({1}), frozenset({3}), 1.0)]

 

 

举报

相关推荐

0 条评论