本文基于机器学习实战这本书记录一下学习路程,就当是笔记了,我是机器实战的搬运工,各位大爷不喜勿喷~~~
首先引入一个实例
交易号码 | 商品 |
---|---|
0 | 豆奶,莴苣 |
1 | 莴苣,尿布,葡萄酒,甜菜 |
2 | 豆奶,尿布,葡萄酒,橙汁 |
3 | 莴苣,豆奶,尿布,葡萄酒 |
从大规模数据集中寻找物品间的隐含关系被称作关联分析(association analysis)或者关联规则学习(association rule learning)
一个项集的支持度(support)被定义数据集中包含该项集的记录所占的比例。如上图中,{豆奶}的支持度为4/5,{豆奶,尿布}的支持度为3/5。支持度是针对项集来说的,因此可以定义一个最小支持度,而只保留满足最小值尺度的项集。
可信度或置信度(confidence)是针对关联规则来定义的。规则{尿布}➞{啤酒}的可信度被定义为”支持度({尿布,啤酒})/支持度({尿布})”,由于{尿布,啤酒}的支持度为3/5,尿布的支持度为4/5,所以”尿布➞啤酒”的可信度为3/4。这意味着对于包含”尿布”的所有记录,我们的规则对其中75%的记录都适用。
包含0个或多个项的集合
一个包含k个数据的项集
一个项集的支持度大于或等于某个阀值
。Apriori原理是说如果某个项集是频繁的,那么它的所有子集也是频繁的。更常用的是它的逆否命题,如果一个项集是非频繁的,那么它的所有超集也是非频繁的,我们利用这个性质可以减少大量的计算
在这假设项集{2,3}是非频繁的,那么利用Apriori原理我们可以知道{0,2,3},{1,2,3},{0,1,2,3}也是非繁的。也就是说假若我们一旦计算{2,3}的支持度,知道他是非频繁的了就不需要计算{0,2,3},{1,2,3},{0,1,2,3}他们的支持度了,使用该原理就可以避免项集数目的指数增长,从而在合理的时间内计算出频繁集
关联分析的目标包括两项:发现频繁项集和发现关联规则。首先需要找到频繁项集,然后才能获得关联规则
Apriori算法是发现频繁项集的一种方法。Apriori算法的两个输入参数分别是最小支持度和数据集。该算法首先会生成所有单个元素的项集列表。接着扫描数据集来查看哪些项集满足最小支持度要求,那些不满足最小支持度的集合会被去掉。然后,对剩下来的集合进行组合以生成包含两个元素的项集。接下来,再重新扫描交易记录,去掉不满足最小支持度的项集。该过程重复进行直到所有项集都被去掉。
对数据集中的每条交易记录tran:
对每个候选项集can:
检查can是否是tran的子集
如果是,则增加can的计数
对每个候选项集:
如果其支持度不低于最小值,则保留该项集
返回所有频繁项集列表
当集合中项的个数大于0时:
构建一个由k个项组成的候选项集的列表(k从1开始)
计算候选项集的支持度,删除非频繁项集
构建由k+1项组成的候选项集的列表
优点:易编码实现
缺点:在大数据集上可能较慢
适用数据类型:数值型或对称型
关联分析是用于发现大数据集中元素间有趣关系的一个工具集,可以采用两种方式来量化这些有趣的关系。第一种方式是使用频繁项集,它会给出经常在一起出现的元素项。第二种方式是关联规则,每条关联规则意味着元素项之间的“如果……那么”关系。
发现元素项间不同的组合是个十分耗时的任务,不可避免需要大量昂贵的计算资源,这就需要一些更智能的方法在合理的时间范围内找到频繁项集。能够实现这一目标的一个方法是Apriori算法,它使用Apriori原理来减少在数据库上进行检查的集合的数目。Apriori原理是说如果一个元素项是不频繁的,那么那些包含该元素的超集也是不频繁的。Apriori算法从单元素项集开始,通过组合满足最小支持度要求的项集来形成更大的集合。支持度用来度量一个集合在原始数据中出现的频率。
关联分析可以用在许多不同物品上。商店中的商品以及网站的访问页面是其中比较常见的例子。
每次增加频繁项集的大小,Apriori算法都会重新扫描整个数据集。当数据集很大时,这会显著降低频繁项集发现的速度。下面会介绍FP-growth算法,和Apriori算法相比,该算法只需要对数据库进行两次遍历,能够显著加快发现频繁项集的速度。
数据集想要的私我吧
#encoding:utf-8
import numpy as np
from numpy import *
def loadDataSet():
return [[1,3,4],[2,3,5],[1,2,3,5],[2,5]]
#产生c1序列,生成只含一个元素的的集合的列表
def creatC1(dataSet):
C1 = []
for data in dataSet:
for item in data:
if [item] not in C1:
C1.append([item])#这里一个元素变成列表插入到列表中是因为set集合不能创建只有一个整数的集合 比如set(1) 这是错误的
C1.sort()
return map(frozenset, C1)#强制转换成forzenset既可以去重又能当做词典的键值,set是不能当做词典的键值的
#筛选Ck产生Lk
def scanD(D, Ck, minSupport):#
sscnt = {}#对产生的集合元素 进行计数
for tid in D:
for can in Ck:
if can.issubset(tid):#如果can集合属于tid集合
if not sscnt.has_key(can): sscnt[can] = 1
else:
sscnt[can] += 1
m = len(D)
retList=[]
supportData = {}
for key in sscnt:
support = 1.0*sscnt[key]/m
if support >= minSupport:
retList.insert(0, key)
supportData[key] = support
return retList, supportData#返回筛选后的集合元素表和各个集合的支持度
#合并Lk,由原本集合的k项合并成k+1
def aprioriGen(Lk, k):#将原本列表中的的各个集合,从k-1项合并成k项
retList=[]
lenLk = len(Lk)
for i in range(lenLk):
for j in range( i + 1, lenLk):
'''这里的k-2有必要说一下,现在如果想利用{0,1},{0,2},{1,2}创建三元素,如果两两合并就会的
到三个{0,1,2},为了减少不必要的重复所以就利用前k-2项的元素相同的进行合并'''
l1 = list(Lk[i])[:k-2];l2 =list(Lk[j])[:k-2]
if l1 == l2:
retList.append(Lk[i]|Lk[j])
return retList
'''循环创建C1->L1->C2->L2....Ck->Lk 由低级Ci-1合并成更高级的Ci,通过Li和minSupport来过滤'''
def apriori(dataSet, minSupport = 0.5):
C1 = creatC1(dataSet)
D = map(set, dataSet)
L1,supportData = scanD(D, C1, minSupport)
k = 2
L=[L1]
while(len(L[k-2]) > 0):
Ck = aprioriGen(L[k-2], k)
Lk, suppK = scanD(D, Ck, minSupport)
L.append(Lk)
supportData.update(suppK)
k += 1
return L,supportData
def rulesFromConseq(freqSet, H, supportData, br1, minConf = 0.7):
m = len(H[0])
if len(freqSet) > (m + 1):#看freqSet能否移除频繁集里面含m+1项个元素,如果能就合并成m+1项的频繁集
Hmp1 = aprioriGen(H, m+1)
Hmp1 = calConf(freqSet, Hmp1, supportData, br1, minConf)
if len(Hmp1) > 1:
rulesFromConseq(freqSet, Hmp1, supportData, br1, minConf)#如果还能合并递归调用
def calConf(freqSet, H, supportData, br1, minConf = 0.7):
prunedH=[]
for conseq in H:
conf = supportData[freqSet]*1.0/supportData[freqSet - conseq]#freqSet - conseq意思代表freqSet集合里面有而conseq没有
# print freqSet - conseq,"--->",conseq,'conf',conf
if conf >= minConf:#判断计算的可信度是否是大于预期的 相当于一个剪枝把
print freqSet - conseq,"--->",conseq,'conf',conf
br1.append((freqSet-conseq, conseq, conf))
prunedH.append(conseq)
#
# conf = supportData[freqSet]*1.0/supportData[conseq]
# if conf >= minConf:
#
# print conseq,"-+++-->",freqSet -conseq,'conf',conf
# br1.append((freqSet-conseq, conseq, conf))
# prunedH.append(conseq)
return prunedH
'''从最初的项集生成关联规则'''
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)]
if i > 1:#如果频繁项中元素的个数大于2
rulesFromConseq(freqSet, H1, supportData, bigRuleList, minConf)
else:
calConf(freqSet, H1, supportData, bigRuleList, minConf)
return bigRuleList
if __name__ == '__main__':
# dataSet = loadDataSet()
# # c1 = creatC1(dataSet)
# # D = map(set, dataSet)
# # a,b = scanD(D, c1, 0.5)
# # print aprioriGen(a, 2)
# L, supportData= apriori(dataSet, 0.5)
# # print '-----------',supportData
# rules = generateRules(L, supportData, 0.7)
# print rules
###------------毒蘑菇----------------------
mushDataSet = [line.split() for line in open(r'mushroom.dat').readlines()]
L,supportData = apriori(mushDataSet, minSupport = 0.3)
for item in L[1]:#观察含有毒蘑菇(特征值为2, 以为不是毒蘑菇)的频繁集 当然可以在更大的频繁集观看
if item.intersection('2'): print item