机器学习实战学习笔记(十)使用Apriori算法进行关联分析

PS:该系列数据都可以在图灵社区(点击此链接)中随书下载中下载(如下)
在这里插入图片描述
  从大规模数据集中寻找物品间的隐含关系被称作关联分析(association analysis) 或者关联规则学习(association rule learning)

1 关联分析

                                               Apriori算法
优点:易编码实现。
缺点:在大数据集上可能较慢。
使用数据类型:数值型或者标称型数据。

  关联分析是一种在大规模数据集中寻找有趣关系的任务。这些关系可以由两种形式:频繁项集或者关联关系。频繁项集(frequent item sets) 是经常出现在一块的物品的集合,关联规则(association rules) 暗示两种物品之间可能存在很强的关系。

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

一个项集的支持度(support) 被定义为数据集中包含该项集的记录所占的比例。如,{豆奶}的支持度为4/5,{豆奶,尿布}的支持度为3/5。
  可信度或置信度(confidence) 是针对一条诸如{尿布}→{葡萄酒}的关联关系定义的。这条规则的可信度被定义为 支 持 度 ( { 尿 布 , 葡 萄 酒 } ) 支 持 度 ( { 尿 布 } ) = 3 / 5 4 / 5 = 3 4 = 0.75 \frac{支持度(\{尿布,葡萄酒\})}{支持度(\{尿布\})}=\frac{3/5}{4/5}=\frac{3}{4}=0.75 ({尿})({尿})=4/53/5=43=0.75
  这意味着对于包含“尿布”的所有记录,我们的规则对其中75%的记录都适用。

2 Apriori原理

  使用编号来代表物品,一共有四种商品。
机器学习实战学习笔记(十)使用Apriori算法进行关联分析_第1张图片
  四种商品需要遍历15次,N中商品需要遍历 2 N − 1 2^N-1 2N1次,随着N的增加遍历次数急剧增长。
  Aprior原理: 如果某个项集是频繁的,那么它的所有自己也是频繁的。例如,如果{0, 1}是频繁项,那么{0}、{1}也一定是频繁的。反过来也就是说,如果一个项集是非频繁集,那么它的所有超集也是非频繁的。
机器学习实战学习笔记(十)使用Apriori算法进行关联分析_第2张图片
  图中非频繁项集用灰色表示,由于集合{2, 3}是非频繁的,因此{0, 2, 3}、{1, 2, 3}、{0, 1, 2, 3}也是非频繁的,它们的支持度根本不需要计算。

3 使用Apriori算法来发现频繁项

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

3.1 生成候选项集

创建一个用于构建初始集合的函数,也会创建一个通过扫描数据集以寻找交易记录子集的函数。伪代码:

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

  创建一个apriori.py文件,编写代码并在python命令行进行测试:

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

def createC1(dataSet):
    #构建一个大小为1的所有候选项集的集合
    C1 = []
    for transaction in dataSet:
        for item in transaction:
            if not [item] in C1:
                C1.append([item])
    C1.sort()
    #对C1中的每个项构建一个不变的集合
    return list(map(frozenset, C1))

def scanD(D, Ck, minSupport):
    '''选出符合要求的项集合L1并返回包含支持度值得字典'''
    ssCnt = {}
    for tid in D:
        for can in Ck:
            if can.issubset(tid):
                if can not in ssCnt:
                    ssCnt[can] = 1
                else:
                    ssCnt[can] += 1
    numItems = float(len(D))
    retList = []
    supportData = {}
    for key in ssCnt:
        support = ssCnt[key] / numItems
        if support >= minSupport:
            retList.insert(0, key)
        supportData[key] = support
    return retList, supportData

机器学习实战学习笔记(十)使用Apriori算法进行关联分析_第3张图片
  C1包含了每个frozenset的单个物品项,L1列表中的每个物品项集至少出现在50%以上的记录中。由于物品4并没有达到最小支持度,所以没有包含在L1中。通过去掉这件物品,减少了查找两物品项集的工作量。

3.2 组织完整的Apriori算法

  伪代码:

当集合中项的个数大于0时:
	构建一个k个项组成的候选项集的列表
	检查数据以确定每个项集都是频繁的
	保留频繁项集并构建k+1项组成的候选项集的列表
def aprioriGen(Lk, k):
    '''输入频繁项集列表Lk与项集元素个数k,输出Ck'''
    retList = []
    lenLk = len(Lk)
    for i in range(lenLk):
        for j in range(i+1, lenLk):
            #前k-2个项相同时,将两个集合合并得到长度为k的项,且不会重复
            L1 = list(Lk[i])[:k - 2]; L2 = list(Lk[j])[:k - 2] #list切片取值顾头不顾尾
            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, dataSet))
    L1, supportData = scanD(D, C1, minSupport)
    L = [L1]
    k = 2
    while len(L[k-2]) > 0:
        #从Ck得到Lk
        Ck = aprioriGen(L[k-2], k)
        Lk, supK = scanD(D, Ck, minSupport)
        supportData.update(supK)
        L.append(Lk)
        k += 1
    return L, supportData

机器学习实战学习笔记(十)使用Apriori算法进行关联分析_第4张图片
  第一个L包含满足最小支持度为0.5的频繁项集列表。

4 从频繁项集中挖掘关联关系

  可信度:一条规则P→H的可信度定义为 s u p p o r t ( P ∣ H ) / s u p p o r t ( P ) support(P|H)/support(P) support(PH)/support(P),其中P称为前件,H称为后件,操作符 | 表示集合的并操作。
机器学习实战学习笔记(十)使用Apriori算法进行关联分析_第5张图片
  从上图可以观察到,如果某条规则并不满足最小可信度要求,那么该规则的所有子集也不会满足最小可信度要求。

def generateRules(L, supportData, minConf=0.7):
    ''''
    生成一个包含可信度的规则列表
    L:频繁项集列表 
    supportData:包含频繁项集支持数据的字典
    minConf:最小可信度阈值
    '''
    bigRuleList = []
    for i in range(1, len(L)):
        #单元素项集无法构建关联规则,只获取有两个或更多元素的集合
        for freqSet in L[i]:
            H1 = [frozenset([item]) for item in freqSet]
            if (i > 1):
                #后件长度为1,返回大于最小可信度的Hmp1
                #运用大于最小可信度的后件,再进行组合,生成更长的后件,分级判断
                #书中应该缺少判断前件长度>1且后件长度=1的情况
                Hmp1 = calcConf(freqSet, H1, supportData, bigRuleList, minConf)
                if len(Hmp1) > 1:
                    rulesFromConseq(freqSet, Hmp1, supportData, bigRuleList, minConf)
            else:
                calcConf(freqSet, H1, supportData, bigRuleList, minConf)
    return bigRuleList

def calcConf(freqSet, H, supportData, br1, minConf=0.7):
    '''计算以H中的一个为前件一个为后件的可信度'''
    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):
    '''分级计算长度大于2的项集的规则'''
    m = len(H[0])
    if len(freqSet) > (m+1):
        # 原先长度为m,生成长度为m+1的
        # H:[frozenset({2}), frozenset({3}), frozenset({5})]
        # hmp1: [frozenset({2, 3}, frozenset({2, 5}), frozenset({3, 5}))]
        Hmp1 = aprioriGen(H, m+1)
        # 将Hmp1中的每一个作为后件,计算可信度
        # 返回大于最小可信度的后件,用作下一次调用此函数时,组合成新的后件
        Hmp1 = calcConf(freqSet, Hmp1, supportData, br1, minConf)
        if len(Hmp1) > 1:
            rulesFromConseq(freqSet, Hmp1, supportData, br1, minConf)

机器学习实战学习笔记(十)使用Apriori算法进行关联分析_第6张图片
  注意: 这里我的结果与书中不同,显然就结果而言我是正确的,书上应该漏掉了后件为1,前件>1的情况。

5 发现毒蘑菇的相似特征

  有时我们并不想寻找所有频繁项集,而只对包含某个特定元素项的项集感兴趣。我们会寻找毒蘑菇中的一些公共特征,利用这些特征就能避免吃到那些有毒的蘑菇。文件mushroom.dat是转换好后的毒蘑菇数据集:
在这里插入图片描述
  第一个特征表示有毒或者可食用。如果样本有毒,则值为2;如果可食用,则值为1。下一个特征是蘑菇伞的形状,有六种可能的值,分别用整数3-8来表示。
  为了找到毒蘑菇中存在的公共特征,可以运行Apriori算法来寻找包含特征值为2的频繁项集。
机器学习实战学习笔记(十)使用Apriori算法进行关联分析_第7张图片
  在数据集上运行apriori算法之后,可以在结果中搜索包含毒特征值2的频繁项集。

6 小结

  关联分析是用于发现大数据集中元素间有趣关系的一个工具集,可以采用两种方式来量化这些有趣的关系。第一种方式是使用频繁项集,它会给出经常在一起出现的元素项。第二种方式是关联规则,每条关联规则意味着元素项之间的“如果……那么”关系。
  发现元素项间不同的组合的一个方法是Apriori算法,它使用Apriori原理来减少在数据库上进行检查的集合的数目。Apriori原理是说如果一个元素项是不频繁的,那么那些包含该元素的超集也是不频繁的。Apriori算法从单元素项集开始,通过组合满足最小支持度要求的项集来形成更大的集合。支持度用来度量一个集合在原始数据中出现的频率。
  每次增加频繁项集的大小,Apriori算法都会重新扫描整个数据集。当数据集很大时,这会显著降低频繁项集的发现速度。FPgrowth算法(下一篇博客介绍)只需要对数据库进行两次遍历,能够显著加快发现频繁项集的速度。

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