Apriori | 挖掘关联规则

01 啤酒与尿布

好久没写代码了,脑子快生锈了,今天我们来实操一个比较有意思的算法——Apriori算法。

Apriori算法是一种用于挖掘数据集内部关联规则的算法,“apriori”在拉丁语中翻译为“来自以前”,听意思你应该就能猜到了,这个算法是用先验知识来预测数据的关联规则的。

说到关联规则,有一个很有名的案例——啤酒与尿布。说,美国一家连锁店发现很多男性会在周四购买尿布和啤酒,这两种看似不相干的商品之间显现出强相关性,于是商家可以将啤酒货架放在尿布货架旁边以增加收益。

那么,啤酒与尿布的关系是如何被发现的呢?当然是通过关联算法,我们从Apriori算法开始吧,利用Apriori进行关联分析。


02 Apriori原理

先介绍两个概念,

  1. 支持度support:数据集中包含该项集的数据所占数据集的比例,度量一个集合在原始数据中出现的频率
  2. 置信度confidence:是针对一条关联规则来定义的,a->b的置信度=支持度{a|b}/支持度{a},a|b表示ab的并集

关联分析有两个目标:

  1. 发现频繁项集(频繁项集是满足最小支持度要求的项集,它给出经常在一起出现的元素项)
  2. 发现关联规则(关联规则意味着元素项之间“如果…那么…”的关系)

Apriori原理,

  1. 如果某个项集是频繁的,那么它的所有子集也是频繁的
  2. 如果某个项集是非频繁的,那么它的所有超集也是非频繁的
  3. 基于此,Apriori算法从单元素项集开始,通过组合满足最小支持度的项集来形成更大的集合

其实Apriori就是通过排除法来选择频繁项集和关联规则,下面我们根据这样的原理用python实现算法。


03 Apriori代码实操

3.1 挖掘频繁项集

挖掘频繁项集的逻辑如下图

#加载数据集
def loadDataSet():
    return [[1,3,4],[2,3,5],[1,2,3,5],[2,5]]

#选取数据集的非重复元素组成候选集的集合C1
def createC1(dataSet):
    C1=[]
    for transaction in dataSet: #对数据集中的每条购买记录
        for item in transaction: #对购买记录中的每个元素
            if [item] not in C1: #注意,item外要加上[],便于与C1中的[item]对比
                C1.append([item])
    C1.sort()
    return list(map(frozenset,C1)) #将C1各元素转换为frozenset格式,注意frozenset作用对象为可迭代对象

#由Ck产生Lk:扫描数据集D,计算候选集Ck各元素在D中的支持度,选取支持度大于设定值的元素进入Lk
def scanD(D,Ck,minSupport):
    ssCnt={}
    for tid in D: #对数据集中的每条购买记录
        for can in Ck: #遍历Ck所有候选集
            if can.issubset(tid): #如果候选集包含在购买记录中,计数+1
                ssCnt[can]=ssCnt.get(can,0)+1
    numItems=float(len(D)) #购买记录数
    retList=[] #用于存放支持度大于设定值的项集
    supportData={} #用于记录各项集对应的支持度
    for key in ssCnt.keys():
        support=ssCnt[key]/numItems
        if support>=minSupport:
            retList.insert(0,key)
        supportData[key]=support
    return retList,supportData

#由Lk产生Ck+1
def aprioriGen(Lk,k): #Lk的k和参数k不是同一个概念,Lk的k比参数k小1
    retList=[]
    lenLk=len(Lk)
    for i in range(lenLk):
        for j in range(i+1,lenLk): #比较Lk中的每一个元素与其他元素
            L1=list(Lk[i])[:k-2];L2=list(Lk[j])[:k-2]
            L1.sort();L2.sort()
            if L1==L2: #若前k-2项相同,则合并这两项
                retList.append(Lk[i]|Lk[j])
    return retList

#Apriori算法主函数
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: #当L[k]为空时,停止迭代
        Ck=aprioriGen(L[k-2],k) #L[k-2]对应的值是Lk-1
        Lk,supK=scanD(D,Ck,minSupport)
        supportData.update(supK)
        L.append(Lk)
        k+=1
    return L,supportData

我们来测试一下,

dataset=loadDataSet()
C1=createC1(dataset)
D=list(map(set,dataset))
L1,supportData0=scanD(D,C1,0.5)
L,supportData=apriori(dataset,minSupport=0.5)

可以看到,频繁项集如上图,{1,2,3,5,{2,3},{3,5},{2,5},{1,3},{2,3,5}}都是频繁项集。得到了频繁项集,接下来我们看看频繁项集之间的关联规则。

3.2 从频繁项集挖掘关联规则

挖掘关联规则原理如下:若某条规则不满足最小置信度要求,则该规则的所有子集也不满足最小置信度要求

# 主函数,由频繁项集以及对应的支持度,得到各条规则的置信度,选择置信度满足要求的规则为关联规则
# 为了避免将所有数据都对比一遍,采用与上述相同的逻辑减少计算量——一层一层计算筛选
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] # H1是频繁项集单元素列表,是关联规则中a->b的b项
            if i>1:
                rulesFromConseq(freqSet,H1,supportData,bigRuleList,minConf)
            else:
                calConf(freqSet,H1,supportData,bigRuleList,minConf)
    return bigRuleList

# 置信度计算函数
def calConf(freqSet,H,supportData,brl,minConf=0.7):
    prunedH=[] # 用于存放置信度满足要求的关联规则的b项,即“提纯后的H”
    for conseq in H:
        conf=supportData[freqSet]/supportData[freqSet-conseq]
        if conf>=minConf:
            print (freqSet-conseq,'-->',conseq,'conf:',conf)
            brl.append([freqSet-conseq,conseq,conf])
            prunedH.append(conseq)
    return prunedH

# 关联规则合并函数
def rulesFromConseq(freqSet,H,supportData,brl,minConf=0.7):
    m=len(H[0])
    if len(freqSet)>(m+1): #查看频繁项集freqSet是否大到可以移除大小为m的子集
        Hmp1=aprioriGen(H,m+1) # 从Hm合并Hm+1
        Hmp1=calConf(freqSet,Hmp1,supportData,brl,minConf)
        if len(Hmp1)>1: #若合并后的Hm+1的元素大于1个,则继续合并
            rulesFromConseq(freqSet,Hmp1,supportData,brl,minConf)

测试一下,

L,supportData=apriori(dataset,minSupport=0.5)
rules=generateRules(L,supportData,minConf=0.5)

可以看到,如果有5那么必定有2,如果有3,那么66.7%的可能性有2,5……


04 总结

本文简述关联分析算法Apriori算法的原理,然后用python3进行了实操,需要注意的是,Apriori算法的缺点——每次增加频繁项集大小时(即Ck->Lk时),算法需要重新扫描整个数据集,当数据集很大时,算法效率很低。

解决方法是FP-Growth算法,这个算法我们下一次讲解。


05 参考

《机器学习实战》 Peter Harrington Chapter11

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • 定义   关联分析是一种简单、实用的分析技术,就是发现存在于大量数据集中的关联性或相关性,从而描述了一个事物中某些...
    老羊_肖恩阅读 3,316评论 0 1
  • 前言 之前看了很多关于MySQL索引的文章也看了《高性能MySQL》这本书,自以为熟悉了MySQL索引使用原理,入...
    PHP菜鸡阅读 3,431评论 0 1
  • 最近很闲,闲到一天抱着一本书也没人来打搅……在图书馆觅得不少好书,很开心,我读书很慢,但是一见到想看的书刚好摆在书...
    木棉晴阅读 467评论 0 0