最近接触到一点机器学习的知识,总结一下加深印象
实验目的:
使用Apriori算法解决从大规模数据集中寻找物品间的隐含关系即关联分析或关联规则学习,寻找物品间的不同组合。在合理的时间范围内找到频繁项集。
实验环境:
1、win10 系统
2、PyCharm Community Edition 2020.1.3 x64
实验原理:
Apriori算法的一般过程:
① 收集数据:使用任意方法
② 准备数据:任何数据类型都可以,因为我们只保留集合
③ 分析数据:使用任意方法
④ 训练算法:使用Apriori算法来找到频繁项集
⑤ 测试算法:不需要测试过程
⑥ 使用算法:用于发现频繁项集以及物品之间的关联规则
实验代码程序:
def loadDataSet():
return ([ 1,3,4 ],[2,3,5],[1,2,3,5],[2,5])
# C1是大小为1的所有候选项集的集合
def createC1(dataSet):
C1=[] # 创建一个空列表C1,存储所有不重复的项值,每个项值都是一个集合
for transaction in dataSet:
for item in transaction:
if not [item] in C1:
C1.append([item]) # store all the item unrepeatly
C1.sort()
return list(map(frozenset,C1)) # frozenset()返回一个冻结的集合,冻结后集合不能再添加或删除任何元素
def scanD(D,Ck,minSupport): # 数据集Ck,包含候选集合的列表,最小支持度计算支持数
ssCnt = {}
for tid in D: # 扫描数据库
for can in Ck: # 计算支持数
if can.issubset(tid):
# if not ssCnt.has_key(can):
if not can in ssCnt:
ssCnt[can] = 1
else: ssCnt[can] += 1
numItems = float(len(D))
retList = []
supportData = {}
for key in ssCnt:
support=ssCnt[key]/numItems # compute support支持度
if support>=minSupport:
retList.insert(0,key) # 在列表的首部插入任意新的集合
supportData[key]=support
return retList,supportData
# total apriori
def aprioriGen(Lk,k): # 组合,向上合并 #计算Ck,候选频繁项集
# creates Ck参数:频繁项集列表Lk与项集元素个数k
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] # [k-2]:向后组合k-2个元素
L1.sort();L2.sort()
if L1 == L2: # 若两个集合的前k-2个项相同时,则将两个集合合并
retList.append(Lk[i]|Lk[j]) # set union
return retList
# apriori调用aprioriGen()来创建候选项集Ck
def apriori(dataSet,minSupport = 0.5):
C1 = createC1(dataSet)
D = list(map(set,dataSet)) # python3
L1,supportData = scanD(D,C1,minSupport) # 单项最小支持度判断0.5,生成L1
L = [L1]
k=2
while (len(L[k-2])>0): # 创建包含更大项集的更大列表,直到下一个大的项集为空
Ck = aprioriGen(L[k-2],k) # 两两合并,生成Ck
Lk,supK = scanD(D,Ck,minSupport) # supk是过滤之前的数据集,Lk是过滤之后的候选项集
supportData.update(supK)
L.append(Lk) # 依次生成L[1],L[2],l[3]...
k+=1 # 继续向上合并,生成项集个数更多的
return L,supportData
# 生成关联规则
def generateRules(L,supportData,minConf=0.7):
# 频繁项集列表,包含那些频繁项集支持数据的字典、最小可信度阈值
bigRuleList = [] # 存储所有的关联规则
for i in range(1,len(L)): # 只获取有两个或者更多集合的项目,从1,即第二个元素开始,L[0]是单个元素的
# 两个及以上的才可能有关联一说,单个元素的项集不存在关联问题
for freqSet in L[i]:
H1 = [frozenset([item]) for item in freqSet]
print("H1:%s"%H1)
# 该函数遍历L中的每一个频繁项集并对每个频繁项集创建只包含单个元素集合的列表H1
if(i>1):
# 如果频繁项集元素数目超过2,那么会考虑对它做进一步的合并
calcConf(freqSet,H1,supportData,bigRuleList,minConf)
rulesFromConseq(freqSet,H1,supportData,bigRuleList,minConf)
else: # 第一层时,后件数为1
calcConf(freqSet,H1,supportData,bigRuleList,minConf) #调用函数2
return bigRuleList
# 生成候选规则集合,计算规则的可信度以及找到满足最小可信度要求的规则
def calcConf(freqSet,H,supportData,brl,minConf=0.7):
# 针对项集中只有两个元素时,计算可信度
prunedH = [] # 返回一个满足最小可信度要求的规则
for conseq in H: # 后件,遍历H中的所有项集并计算它们的可信度值
conf = supportData[freqSet]/supportData[freqSet-conseq] # 可信度计算,结合支持度数据
print('-----',freqSet-conseq,'-->',conseq,'conf',conf)
if conf >= minConf:
print(freqSet-conseq,'-->',conseq,'conf',conf)
# 如果某条规则满足最小可信度值,那么将这些规则输出到屏幕显示
brl.append((freqSet-conseq,conseq,conf)) # 添加到规则里,brl是前面通过检查的bigRuleList
prunedH.append(conseq) # 同样需要放入列表到后面检查
return prunedH
# 合并
def rulesFromConseq(freqSet,H,supportData,brl,minConf=0.7):
# 参数:一个是频繁项集,另一个是可以出现在规则右部的元素列表H
m = len(H[0])
print("m=%d,freqSet=%s,H=%s"%(m,freqSet,H))
if(len(freqSet)>(m+1)): # 频繁项集元素数目大于单个集合的元素数
Hmp1 = aprioriGen(H,m+1) # 存在不同顺序、元素相同的集合,合并具有相同部分的集合,后件的无重复组合:[[a],b,c]->[ab,ac,bc]
print("Hmp1:"+str(Hmp1))
Hmp1 = calcConf(freqSet,Hmp1,supportData,brl,minConf) # 计算可信度
if(len(Hmp1)>1): # 满足最小可信度要求的规则列表多于1,则递归
rulesFromConseq(freqSet,Hmp1,supportData,brl,minConf)
# 输出结果
# import apriori
if __name__=='__main__':
dataSet = loadDataSet()
# print(dataSet)
# C1=apriori.createC1(dataSet)
# print(C1)
# D=list(map(set,dataSet))
# # print(D)
# L1,suppData0=apriori.scanD(D,C1,0.5)
# print(L1)
# print(suppData0)
L,SupportData = apriori(dataSet,0.5)
print(L)
print(SupportData)
rules = generateRules(L,SupportData,0.7)
print(rules)
实验结果:
D:\pycharm\pycharm\apriori\venv\Scripts\python.exe D:/pycharm/pycharm/apriori/apriori.py
[[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}
H1:[frozenset({2}), frozenset({3})]
----- frozenset({3}) --> frozenset({2}) conf 0.6666666666666666
----- frozenset({2}) --> frozenset({3}) conf 0.6666666666666666
H1:[frozenset({3}), frozenset({5})]
----- frozenset({5}) --> frozenset({3}) conf 0.6666666666666666
----- frozenset({3}) --> frozenset({5}) conf 0.6666666666666666
H1:[frozenset({2}), frozenset({5})]
----- frozenset({5}) --> frozenset({2}) conf 1.0
frozenset({5}) --> frozenset({2}) conf 1.0
----- frozenset({2}) --> frozenset({5}) conf 1.0
frozenset({2}) --> frozenset({5}) conf 1.0
H1:[frozenset({1}), frozenset({3})]
----- frozenset({3}) --> frozenset({1}) conf 0.6666666666666666
----- frozenset({1}) --> frozenset({3}) conf 1.0
frozenset({1}) --> frozenset({3}) conf 1.0
H1:[frozenset({2}), frozenset({3}), frozenset({5})]
----- frozenset({3, 5}) --> frozenset({2}) conf 1.0
frozenset({3, 5}) --> frozenset({2}) conf 1.0
----- frozenset({2, 5}) --> frozenset({3}) conf 0.6666666666666666
----- frozenset({2, 3}) --> frozenset({5}) conf 1.0
frozenset({2, 3}) --> frozenset({5}) conf 1.0
m=1,freqSet=frozenset({2, 3, 5}),H=[frozenset({2}), frozenset({3}), frozenset({5})]
Hmp1:[frozenset({2, 3}), frozenset({2, 5}), frozenset({3, 5})]
----- frozenset({5}) --> frozenset({2, 3}) conf 0.6666666666666666
----- frozenset({3}) --> frozenset({2, 5}) conf 0.6666666666666666
----- frozenset({2}) --> frozenset({3, 5}) conf 0.6666666666666666
[(frozenset({5}), frozenset({2}), 1.0), (frozenset({2}), frozenset({5}), 1.0), (frozenset({1}), frozenset({3}), 1.0), (frozenset({3, 5}), frozenset({2}), 1.0), (frozenset({2, 3}), frozenset({5}), 1.0)]
Process finished with exit code 0
实验分析:
该程序的执行可以分为五部分:
(1) 创建数据集:定义一个loadDataSet函数创建一个用于测试的简单数据集C1
(2) 过滤数据集:定义一个createC1函数用于筛选不重复的项值,每个项值都是一个集合;定义一个scanDh函数计算支持度,大于最小支持度的保存到数据集L1
(3) 组织完整的Apriori算法:定义一个aprioriGen函数用于向上合并并将合并后的数据集保存在Ck中;定义一个apriori函数用于调用aprioriGen函数奖Ck中的数据集逐步进行过滤得到候选集Lk(L[1]、L[2]…),并继续向上合并直到下一个大的项集为空停止。
(4) 生成关联规则:generateRules是主函数,用于调用函数calcConf()和函数rulesFromConseq(),其中,函数calcConf()用于对规则评估,函数rulesFromConseq()生成候选规则集合
(5) 调用主函数main()执行整个程序,最终完成Apriori关联分析算法的实现。
补充:本实验参考的是《机器学习实战》这本书,关于书的pdf和一些实验的代码可以到https://pan.baidu.com/s/1TtljufGTkgRhEQGLI7oZhg 下载,提取码: n53h