机器学习 (十五) 关联分析之Apriori算法

版权声明:本文为博主原创文章,未经博主允许不得转载,谢谢尊重每个人的权利。 https://blog.csdn.net/lilongsheng1125/article/details/80664243

前言

       目前随着数据量迅速增多,从海量数据中寻找有价值的信息带来的成本也在不断增加,传统的搜索数据方式已经不能满足我们的需要,我们先来通过一个算法看一下算法时间复杂度快慢带来的影响,通过计算耗时我们会有个感性的认识,冒泡排序与快速排序想必大家都知道,复杂度分别为n方和n*logn,复杂度随着规模n变大时间如下;

n方 n*lgn n规模 时间
100 10 10 10倍
10000 200 100 500倍
1000000 3000 1000 1000倍 (省略)
1000000000000 6000000 1000000 100000倍

       上图中有的值是约等于只为对比效果,大家可以清晰的看出来随着规模n增长,两个算法所用时间对比,随着数据量变大所面临的挑战越大,当数据规模到10的10次方时,耗时会差很多,如果快速排序执行30秒,那么冒泡要运行5天以上,无疑中间增加耗费了很多台服务器成本速度增加电费也急剧上升,可见好的数据挖掘算法至关重要,下面我们来一起看Apriori算法如何高效运行。

原理

基本概念

       apriori 英 [‘eɪprɑɪ’ɔ:rɪ] 先验知识、演绎推演,言外之意是挖掘数据中的已有的信息、先验知识信息,该词在贝叶斯BA里面代表先验概率,最初的先验经验判断。
        下面是一个数据集矩阵,可以理解为数据库里面的记录,每条记录里面有不同的数值。

tid
1 [[1,3,4]
2 [2,3,5]
3 [1,2,3,5]
4 [2,5]]
  • itemset 项集
    包含0个或者多个项的集合称为项集,如上面的第一条记录[1,3,4] ,可以有六个项集,如[1,3]、[1]、[1,4]、[3,4]等。

  • support 支持度
    即某个项集出现的次数即支持度,有的书籍也说是次数除以总记录数,如[2]出现了3次即支持度为3,支持度可以作为过滤条件过滤项集。

  • frequery itemset 频繁项集
    满足最小支持度的项集叫频繁项集,如[1]出现了2次、[2]出现了3次,假如最小支持度为3,那么[2]是频繁集,[1]不是频繁集。

  • confident 可信度或置信度
    它是两个频繁集的商,如A、B两个频繁集,关联规则为A–>B ,那么这条关联规则的置信度为support(AUB) / support(A)

  • association analysis 关联分析
    关联分析是一个过程即从数据集中发现哪个项集与哪个项集有关系的分析过程。

    Apriori思想

           思想:如果一个项集是频繁项集,那么它的所有子集也是频繁项集,反过来说如果一个集合不是频繁项集,那么它的所有超集都不是频繁的,根据这一条思想可以过滤掉很多项,减小了大量计算,想在想想这一思想似乎也很好理解,这有点像古代的连坐惩罚制度,只要组人中有一个人被触发了,会连带它的家族,包含这个人的家族都会受到牵连,株连九族的意思。
           实现思路:令k为频繁项集的层数,为了不丢掉任何一个频繁集,从k=1开始 逐层+1 ,第k层的候选集是由k-1层的频繁集而来,然后由k层的候选集生成频繁集,依次类推直到不能够生成频繁集为止。

实战

代码

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import numpy as np

def loadDataSet():
    '''
    获取数据集
    :return: 数据集
    '''
    return [[1,3,4],[2,3,5],[1,2,3,5],[2,5]]


def createC1(dataSet):
    '''
    生成候选项集 k=1时
    :param dataSet:
    :return:
    '''
    C1 = []
    # 循环每条记录或事务
    for transaction in dataSet:
        # 循环每条记录中的每项
        for item in transaction:
            if  not [item] in C1:
                C1.append([item])

    C1.sort()
    # 返回frozenset类型 ,用来做键值
    return map(frozenset,C1)


def scanD(D,Ck,minSupport):
    '''

    :param D:
    :param Ck:
    :param minSupport:
    :return:符合条件的项集和项集支持度
    '''
    # 统计候选元素出现的次数
    ssCnt = {}
    for tid in D:
        for can in Ck:
            if can.issubset(tid):
                if  not ssCnt.has_key(can):
                    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

def aprioriGen(Lk ,k):
    '''
    生成频繁集合
    :param Lk:
    :param k:
    :return:
    '''
    retList = []
    lenLk = len(Lk)
    for i in range(lenLk):
        for j in range(i+1,lenLk):
            print "i== %s" % i
            print "j== %s" % j

            print "Lk[i]== %s" % Lk[i]
            print "list(Lk[i])== %s" % list(Lk[i])

            print "Lk[j]== %s" % Lk[j]
            print "list(Lk[j])== %s" % list(Lk[j])

            L1 = list(Lk[i])[:k-2]
            L2 = list(Lk[j])[:k-2]
            print "L1== %s" % L1
            print "L2== %s" % L2

            L1.sort()
            L2.sort()
            if L1 == L2:
                retList.append(Lk[i] | Lk[j] )
    return retList






def apriori(dataSet,minSupport = 0.5):
    '''
    求频繁项集以及对应的支持度
    :param dataSet:
    :param minSupport:
    :return:
    '''
    # 创建候选集合
    C1 = createC1(dataSet)
    print "C1 = %s" % C1
    D = map(set,dataSet)
    print "D = %s" % D
    L1,supportData = scanD(D,C1,minSupport)
    print "L1 = %s" % L1
    print "supportData = %s" % supportData
    L = [L1]
    k = 2
    while (len(L[k-2]) > 0):
        Ck = aprioriGen(L[k-2],k)
        Lk ,supK = scanD(D,Ck,minSupport)
        supportData.update(supK)
        L.append(Lk)
        k += 1
    return L,supportData

if  __name__ == '__main__':
    dataSet = loadDataSet()
    L,s = apriori(dataSet)

    print L
    print s

问题

  • 效率问题
    该算法每次都需要频繁访问数据集或者数据库,无疑给DB带来了很大压力,是否有办法优化呢?FP-growth只需要两次访问数据集,有兴趣的可以查查资料
  • 数据挖掘和数据分析关系
    主要在如下散点方面区分
    计算机编程能力的要求
    在对行业的理解的能力
    专业知识面的要求

总之一句话来概括的话,数据分析师更关注于业务层面,数据挖掘工程师更关注于

总结

        该算法是数据挖掘领域重要算法,对于认识和学习挖掘方面都有益处,后面将继续学习其他算法。

题外思考

从链霉素、DDT、海洛因的发明思考?
       链霉素是美国瓦克斯曼教授发明了,从链霉菌培养液中提取的抗生素,因此命名为链霉素,它的发现治愈了困扰人类上千年的结核病,具有重大意义,从瓦克斯曼发明链霉素的过程来看是曲折、坚信、幸运等各种因素所致。
       瓦克斯曼开始在莫克公司支持在带领团队研制药品,可惜由于多次的失败莫克公司中途放弃,但瓦克斯曼认为值的去做一直坚持下去继续研究,在孤身一人时突然他的学生沙茨回到身边同老师一起研究,造化弄人,沙茨刚加入不久就发现了链霉素,然后就是一段因为谁发明链霉素的恩怨情仇…………

       阿司匹林、海洛因由美国化学教授霍夫曼所发明,现在想想同一个人发明了两种影响极端的药品,一种誉为极品,一种誉为魔鬼,均对后世产生了深远影响,这种结论是经历了长时间的验证才有了这样的认识,刚开始发明出来时由于各种原因人们并没有发现,海洛因刚问世时含量很低 不容易上瘾,随着含量在人体内累计,最终被人们发现了副作用。
       说道阿司匹林让我想到了一首经常背诵的诗词
                                   《送元二使安西》
                            渭城朝雨浥轻尘,客舍青青柳色新。
                            劝君更尽一杯酒,西出阳关无故人。
       柳树千百年来一直存在,组成阿司匹林的水杨酸也一直有,其实我们需要的是发现的眼睛和质疑的思考。
       发明新药或做事情一样,不能有副作用把事情办不好可以但不可以搞砸了,另外在世界上还有很多真理本来存在的事物等着我们去发现,你看不到并不代表没有,像阿司匹林一样它在那里不管你看见还不不见,记得有几句词这样写的:

你见,或者不见我
我就在那里
不悲不喜
你念,或者不念我
情就在那里
不来不去

参考资料

1.https://blog.csdn.net/rongyongfeikai2/article/details/40457827
2.https://blog.csdn.net/kevinelstri/article/details/53487186
3.https://www.cnblogs.com/qwertWZ/p/4510857.html
2.http://baijiahao.baidu.com/s?id=1566792535800841&wfr=spider&for=pc

猜你喜欢

转载自blog.csdn.net/lilongsheng1125/article/details/80664243