Apriori算法

Apriori

本文基于机器学习实战这本书记录一下学习路程,就当是笔记了,我是机器实战的搬运工,各位大爷不喜勿喷~~~
首先引入一个实例

交易号码 商品
0 豆奶,莴苣
1 莴苣,尿布,葡萄酒,甜菜
2 豆奶,尿布,葡萄酒,橙汁
3 莴苣,豆奶,尿布,葡萄酒

1、基本概念

1.1关联分析

从大规模数据集中寻找物品间的隐含关系被称作关联分析(association analysis)或者关联规则学习(association rule learning)

1.2支持度

一个项集的支持度(support)被定义数据集中包含该项集的记录所占的比例。如上图中,{豆奶}的支持度为4/5,{豆奶,尿布}的支持度为3/5。支持度是针对项集来说的,因此可以定义一个最小支持度,而只保留满足最小值尺度的项集。

1.3可信度或置信度

可信度或置信度(confidence)是针对关联规则来定义的。规则{尿布}➞{啤酒}的可信度被定义为”支持度({尿布,啤酒})/支持度({尿布})”,由于{尿布,啤酒}的支持度为3/5,尿布的支持度为4/5,所以”尿布➞啤酒”的可信度为3/4。这意味着对于包含”尿布”的所有记录,我们的规则对其中75%的记录都适用。

1.4项集

包含0个或多个项的集合

1.5k_项集

一个包含k个数据的项集

1.6频繁集

一个项集的支持度大于或等于某个阀值

2、Apriori原理

。Apriori原理是说如果某个项集是频繁的,那么它的所有子集也是频繁的。更常用的是它的逆否命题,如果一个项集是非频繁的,那么它的所有超集也是非频繁的,我们利用这个性质可以减少大量的计算
Apriori算法_第1张图片
在这假设项集{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}他们的支持度了,使用该原理就可以避免项集数目的指数增长,从而在合理的时间内计算出频繁集

3、使用Apriori发现频繁集

关联分析的目标包括两项:发现频繁项集和发现关联规则。首先需要找到频繁项集,然后才能获得关联规则
Apriori算法是发现频繁项集的一种方法。Apriori算法的两个输入参数分别是最小支持度和数据集。该算法首先会生成所有单个元素的项集列表。接着扫描数据集来查看哪些项集满足最小支持度要求,那些不满足最小支持度的集合会被去掉。然后,对剩下来的集合进行组合以生成包含两个元素的项集。接下来,再重新扫描交易记录,去掉不满足最小支持度的项集。该过程重复进行直到所有项集都被去掉。

4、Apriori伪代码

4.1生成候选项集

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

4.2完整的Apriori算法

当集合中项的个数大于0时:
    构建一个由k个项组成的候选项集的列表(k从1开始)
    计算候选项集的支持度,删除非频繁项集
    构建由k+1项组成的候选项集的列表

5、Apriori优缺点及总结

优点:易编码实现
缺点:在大数据集上可能较慢
适用数据类型:数值型或对称型
关联分析是用于发现大数据集中元素间有趣关系的一个工具集,可以采用两种方式来量化这些有趣的关系。第一种方式是使用频繁项集,它会给出经常在一起出现的元素项。第二种方式是关联规则,每条关联规则意味着元素项之间的“如果……那么”关系。

发现元素项间不同的组合是个十分耗时的任务,不可避免需要大量昂贵的计算资源,这就需要一些更智能的方法在合理的时间范围内找到频繁项集。能够实现这一目标的一个方法是Apriori算法,它使用Apriori原理来减少在数据库上进行检查的集合的数目。Apriori原理是说如果一个元素项是不频繁的,那么那些包含该元素的超集也是不频繁的。Apriori算法从单元素项集开始,通过组合满足最小支持度要求的项集来形成更大的集合。支持度用来度量一个集合在原始数据中出现的频率。

关联分析可以用在许多不同物品上。商店中的商品以及网站的访问页面是其中比较常见的例子。

每次增加频繁项集的大小,Apriori算法都会重新扫描整个数据集。当数据集很大时,这会显著降低频繁项集发现的速度。下面会介绍FP-growth算法,和Apriori算法相比,该算法只需要对数据库进行两次遍历,能够显著加快发现频繁项集的速度。

7、发现毒蘑菇的相似特征

数据集想要的私我吧

#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



你可能感兴趣的:(机器学习)