使用Apriori进行关联分析
使用Apriori进行关联分析
最典型的关联分析的案例就是沃尔玛的“啤酒与尿布”的故事,这个看起来完全不搭嘎的商品在经过对过去一年的数据分析后发现周四晚上奶爸们会来超市采购尿布同时顺手买走自己喜欢的啤酒,于是超市保证当天的备货充足并显眼的摆在一起,就可以创造销量奇迹。
大规模数据集中寻找物品间的隐含关系被称作关联分析(association analysis)或者关联规则学习(association rule learning)。
在开始算法之前,需要先理解几个概念和量化规则。
项集:元素的组合,例如上面例子中{啤酒}、{尿布}、{啤酒+尿布}这就是3个项集。单元素的项集对数据分析意义不大,我们真正关心的是多元素的项集。
频繁项集:在记录中某项集超过一定概率出现,被称为频繁项集,这个概率是我们人为设定的。同上,我们关心的是多元素的项集,它们一起抱团出现才是我们该兴趣的。
频繁项集的意义在于,我们不可能对所有元素的各种组合都去进行数据分析,因为那个计算量是指数级增长的,我们只选取大概率的我们关系的项量做分析,于是我们要找出频繁项集来减少数据分析中的计算消耗。
支持度:数据集中包含该项集的记录所占的比例,我们给数据集输入一个“最小支持度”便可以求得频繁项集。
可信度:用X1àX2来标识,计算公式是
X1àX2 = 支持度{X1+X2}|支持度{X1}
X1àX2并不代表X2àX1,还是上面的案例买尿布的男士很可能会去买啤酒,但是买啤酒的男士还会买尿布的概率就微乎其微了。所以可信度是单向的。
概念掌握了,再回头看下Apriori原理,前面也说过随着元素的增加项量是指数级增长的,我们必须除了频繁项集之外的原理来支持我们削减数据才能满足更多元素的数据分析。
我开了一个烧烤摊,我只卖4种烤串“羊肉串”、“牛肉串”、“骨肉相连”、“烤土豆”,对它们编号后是0、1、2、3,那么一个顾客购买的订单就有如下组合:
已经很恐怖了,多卖几种组合会更复杂。
Apriori原理:
如果某个项集是频繁的,那么它的所有子集也是频繁的。
这句很好理解吧,{X1+X2}是频繁的,那么{X1}和{X2}都是频繁的,听起来是个废话,对我们没什么鸟用,但是这句话反过来理解就精髓了:
如果某个项集不是频繁的,那么带有该项集的所有超集都不是频繁的。
如上,在低元素层判断出某个非频繁项集后,跟它相关的高元素层我们就可以直接忽略了。可能你觉得虽然可以帮我们减少计算量,但是并没有很逆天的表现嘛。好吧,上图假如只有0是频繁的,我们只需要计算完第一元素层,就可以结束了!
纸上谈兵这么久,开始给我的烧烤摊搞代码:
辅助函数1,造假账:
def loadDataSet() :return [[1,3,4],[2,3,5],[1,2,3,5],[2,5]]
辅助函数2,筛选账单中的单元素:
def createC1(dataSet) :C1 = []for transaction in dataSet :for item in transaction :if not [item] in C1 :C1.append([item])C1.sort()#frozenset是指被“冰冻”的集合,就是说它们是不可改变的,即用户不能修改它们return map(frozenset,C1)
辅助函数3,基于数据集D,计算Ck里项集的支持度,并过滤出频繁项集:
#D:数据集
#Ck:候选项集
#minSupport: 最小支持度
def scanD(D, Ck, minSupport):ssCnt = {}for tid in D:for can in Ck :#筛选出数据条数并给相应的候选项集加一if can.issubset(tid) :if not ssCnt.__contains__(can): ssCnt[can]=1else : ssCnt[can] += 1numItems = float(len(D))retList = []supportData = {}for key in ssCnt:#每个支持度support = ssCnt[key]/numItemsif support>=minSupport :#retList里保存的就是满足支持度的内容retList.insert(0,key)supportData[key] = supportreturn retList, supportData
先简单测试下单元素这一层的支持度,加深一下前面概念的理解:
dataSet = loadDataSet()
#此处被坑很久,python3的map函数做了变动
#这里的Ck很简单,是单元素那一层
Ck = list(createC1(dataSet))
D = list(map(set,dataSet))
#大于0.7的才是频繁项集
retList, supportData = scanD(D,Ck,0.7)
print(retList)
print(supportData)
测试结果是:
[frozenset({5}), frozenset({2}), frozenset({3})]
{frozenset({1}): 0.5, frozenset({3}): 0.75, frozenset({4}): 0.25, frozenset({2}): 0.75, frozenset({5}): 0.75}
目前为止只是万里长征第一步,只涉及到单元素层,补齐完整版的Apriori算法:
再添加一个辅助函数4,项集的合并:
#该函数,把1k的元素合并成k个元素的任意组合
def aprioriGen(lk, k) :retList = []lenLk = len(lk)for i in range(lenLk) :for j in range(i+1,lenLk) :#这块不好理解,初始的k-2个元素相同就进行合并,组成一个更高一层的项集#例如[2,3]、[2,5] L1=L2=2,合并后组成[2,3,5]#[:k-2]看似bug,如果是[2,3][3,5]就无法组成[2,3,5]了,其实如果[2,5]进不来说明已经被淘汰了,[2,3,5]也就不满足L1 = list(lk[i])[:k-2]L2 = list(lk[j])[:k-2]L1.sort()L2.sort()if L1==L2 :retList.append(lk[i] | lk[j])return retList
Apriori主函数:
#支持分层的求dataSet数据集中满足支持度minSupport的频繁项集
def apriori(dataSet, minSupport=0.5) :C1 = list(createC1(dataSet))#D = map(set, dataSet)D = dataSet#获得满足支持度的单元素以及所有相关的支持度的值L1, supportData = scanD(D,C1,minSupport)#新建一个高维数组L,每层保存在一个list里L = [L1]k = 2#如果上一层有值,证明其可合并。#书中是>0,把0换成1,效果会更好while len(L[k-2])>1:#要将L[k-2]这一层的数据合并成k个元素的数据#第k层的数据是由k个元素构成的ck = aprioriGen(L[k-2],k)#求ck在数据集D中的支持度lk,supK = scanD(D,ck,minSupport)supportData.update(supK)L.append(lk)k +=1return L, supportData
测试下:
D = loadDataSet()
L, supportData = apriori(D,minSupport=0.5)
print(L)
print(supportData)
测试结果:
[[frozenset({5}), frozenset({2}), frozenset({3}), frozenset({1})], [frozenset({2, 3}), frozenset({3, 5}), frozenset({2, 5}), frozenset({1, 3})], [frozenset({2, 3, 5})]]
{frozenset({1}): 0.5, frozenset({3}): 0.75, frozenset({4}): 0.25, frozenset({2}): 0.75, frozenset({5}): 0.75, frozenset({1, 3}): 0.5, frozenset({2, 5}): 0.75, frozenset({3, 5}): 0.5, frozenset({2, 3}): 0.5, frozenset({1, 5}): 0.25, frozenset({1, 2}): 0.25, frozenset({2, 3, 5}): 0.5}
到目前为止经过原理学习和代码训练,已经掌握了频繁项集和支持度,有没有发现supportData变量我们还没有利用到,下面开始在频繁项集中挖掘关联规则。
从一个频繁项集中可以产生多少条关联规则?如图:
与前面单元素可以组成多少项集一样,又是个指数及的增长,甚至更复杂,我们得想个办法减少计算量。
如果某条规则并不满足最小可信度要求,那么该规则的所有子集也不会满足最小可信度要求。
例如上图黑色部分:只要012à3不成立,任何{012}组成的项集也不能满足。推理如下:
012à3 =Support{0,1,2,3}|Support{0,1,2}
其中Support{0,1,2,3}为常量,我们设为P,现在012à3 = P|Support{0,1,2}
01à23= Support{0,1,2,3}|Support{0,1}=P|Support{0,1}
由于Support{0,1}一定>= Support{0,1,2}
所以01à23一定<=012à3
同理所有子集都小于012à3
计算可信度的python代码如下:
#L:频繁项集合,元素数和元素组合的2维数组
#supportData:包含那些频繁项集支持数据的字典
#minConf:最小可信度
def generateRule(L, supportData, minConf=0.7) :#存储满足最小可信度的部分bigRuleList = []#分层处理,第0层是单元素层,直接跳过for i in range(1 ,len(L)) :for freqSet in L[i] :#遍历freqSet中的元素组成一个list H1H1 = [frozenset([item]) for item in freqSet]#i>1说明至少是L的第2层,该层包含了至少3个元素,进行进一步合并if i>1 :# 源码有个bug,25-->3这样的情况推算不到,这一行要加下calcConf(freqSet, H1, supportData, bigRuleList, minConf)rulesFromConseq(freqSet, H1,supportData,bigRuleList,minConf)else :#i=1是双元元素那一层calcConf(freqSet, H1,supportData,bigRuleList,minConf)return bigRuleList#对可信度进行评估和筛选
#该函数比较简单
def calcConf(freqSet, H,supportData,bigRuleList,minConf=0.7) :pruneH = []for conseq in H :conf = supportData[freqSet]/supportData[freqSet-conseq]if conf>minConf :bigRuleList.append((freqSet-conseq,conseq,conf))pruneH.append(conseq)print(freqSet-conseq,'--->',conseq, '可信度:',conf)return pruneH#生成候选规则
def rulesFromConseq(freqSet, H,supportData,bigRuleList,minConf=0.7) :m = len(H[0])if len(freqSet) > m + 1:#生成更高一层元素Hmpl = aprioriGen(H, m + 1)Hmpl = calcConf(freqSet, Hmpl, supportData, bigRuleList, minConf)#如果结果可合并,继续迭代if len(Hmpl) > 1 :rulesFromConseq(freqSet, Hmpl, supportData, bigRuleList, minConf)
最后给了一个鉴定毒蘑菇的案例,将Apriopri应用于真实生活。将采集到的蘑菇的属性定义成很多种特性。例如第一列蘑菇是否有毒,有毒则为2,无毒则为1.第二个特性是蘑菇伞的形状,有园顶、塔顶、伞状等6种特性,分别用整数3-8表示。后续还很多属性,属性与属性之间标称的定义需要区分开,因为我们上面Apriori代码需要做并集的处理。
案例数据在git(https://github.com/yejingtao/forblog/blob/master/MachineLearning/trainingSet/mushroom.dat)上,样式如下:
1 3 9 13 23 25 34 36 38 40 52 54 59 63 67 76 85 86 90 93 98 107 113
2 3 9 14 23 26 34 36 39 40 52 55 59 63 67 76 85 86 90 93 99 108 114
2 4 9 15 23 27 34 36 39 41 52 55 59 63 67 76 85 86 90 93 99 108 115
1 3 10 15 23 25 34 36 38 41 52 54 59 63 67 76 85 86 90 93 98 107 113
2 3 9 16 24 28 34 37 39 40 53 54 59 63 67 76 85 86 90 94 99 109 114
2 3 10 14 23 26 34 36 39 41 52 55 59 63 67 76 85 86 90 93 98 108 114
2 4 9 15 23 26 34 36 39 42 52 55 59 63 67 76 85 86 90 93 98 108 115
2 4 10 15 23 27 34 36 39 41 52 55 59 63 67 76 85 86 90 93 99 107 115
1 3 10 15 23 25 34 36 38 43 52 54 59 63 67 76 85 86 90 93 98 110 114
找到哪些特性的蘑菇是有毒的,代码如下:
mushData = [line.split() for line in open('C:\\2017\\提高\\机器学习\\训练样本\\mushroom.dat').readlines()]
L, supportData = apriori(mushData,minSupport=0.3)
#这些里面有毒的部分才是我们关心的部分,过滤出来
m = len(L)
newL = []
for i in range(1,m) :array = []for item in L[i] :# 交集if item.intersection('2'):array.append(item)if len(array)>0 :newL.append(array)
#求可信度
bigRuleList = generateRule(newL,supportData,minConf=0.9)
#我不关心所有的可信度,我只关心哪些可以推断出有毒,
for line in bigRuleList:if line[1].intersection('2'):print(line)
运行结果很庞大,选中其中一些有代表性的,例如
#(frozenset({'59', '28', '90'}), frozenset({'2'}), 0.9967741935483871)
#(frozenset({'53', '28'}), frozenset({'2'}), 1.0)
像这样的数据已经很明显了,特别是28这个属性,从数据集推算出吃了28的蘑菇必死无疑了。这就是数据之间关系的奥秘,它们之间有千丝万缕的联系等待我们去挖掘分析。
使用Apriori进行关联分析相关推荐
- apriori算法c++_使用Apriori进行关联分析
目录 1.名词概念 2.频繁项集发现 3.Apriori算法关联分析 4.代码实现 5.参考文章 通过组合交叉变量制定风控策略时有两种方法:一是通过决策树分箱进行变量交叉,可以见文章一个函数实现自 ...
- 使用Apriori进行关联分析(二)
使用Apriori进行关联分析(二) 书接上文(使用Apriori进行关联分析(一)),介绍如何挖掘关联规则. 发现关联规则 我们的目标是通过频繁项集挖掘到隐藏的关联规则. 所谓关联规则,指通过某个元 ...
- 使用Apriori进行关联分析(一)
使用Apriori进行关联分析(一) 大型超市有海量交易数据,我们可以通过聚类算法寻找购买相似物品的人群,从而为特定人群提供更具个性化的服务.但是对于超市来讲,更有价值的是如何找出商品的隐藏关联,从而 ...
- Apriori进行关联分析
一.术语解释 关联分析:从大规模数据集中挖掘物品之间的隐含关系 频繁项集:经常出现在一块的物品集合 关联规则:暗示两种物品之间可能存在很强的关联关系 项集支持度:数据集中包含该项集的记录比例(这里可以 ...
- 机器学习实战(十)Apriori(关联分析)
目录 0. 前言 1. Apriori 算法寻找频繁项集 2. 从频繁项集中挖掘关联规则 3. 实战案例 3.1. apriori算法发现频繁项集和关联规则 学习完机器学习实战的Apriori,简单的 ...
- 使用Apriori算法进行关联分析
目录 1.名词概念 2.频繁项集发现 3.Apriori算法关联分析 4.代码实现 5.参考文章 通过组合交叉变量制定风控策略时有两种方法:一是通过决策树分箱进行变量交叉,可以见文章一个函数实现自 ...
- 关联分析(一)--Apriori算法
关联分析分为非时序关联分析和时序关联分析,其中非时序关联分析采用Apriori算法,利用先验知识产生频繁项集以及关联规则,而时序关联分析采用GSP算法. Apriori算法 其名字是因为算法基于先验知 ...
- python apriori算法 sklearn_使用Apriori算法进行关联分析
目录 1.名词概念 2.频繁项集发现 3.Apriori算法关联分析 4.代码实现 5.参考文章 通过组合交叉变量制定风控策略时有两种方法:一是通过决策树分箱进行变量交叉,可以见文章 假设一个简单的交 ...
- 订单,用户,商品关联分析记录
最近有做采购平台 订单,用户,商品关联分析 的任务 目的在于希望能产出 商品推荐商品或者 商品 推荐给用户 的数据 主要采用python的apriori 进行关联分析 样例代码如下 大概如下: ...
最新文章
- 文科生也能当工程师?我用了一年半
- LoadRunner学习笔记(一)
- java与众包的联系_众包、众筹和众创是什么 三者区别与联系
- RHEL5.8安装Oracle10g
- AtCoder Grand Contest 021 D - Reversed LCS(区间dp)
- Intel 64/x86_64/IA-32/x86处理器 - SIMD指令集 - SSE扩展(5) - 算术指令
- uva 714 Copying Books
- python︱matplotlib使用(读入、显示、写出、opencv混用、格式转换...)
- c++ 退出函数_UCOSIII源码分析之——bsp_os.c文件分析
- 4.7 Spark SQL 数据分析流程
- Lua 可变参数之arg与select
- 服务器状态码502什么意思,Http状态码502问题复盘
- nbu mysql_mysql数据备份之NBU
- 阿里矢量图标引入方法
- Android 8.0 安装Google服务
- 华为网络设备查看设备温度状态检查命令方法
- sqli-labs(32-37)
- 组策略学习-统一部署软件
- 人工神经网络原理及应用,神经网络的数学原理
- java无法访问网络_java-IOException:网络适配器无法建立连接
热门文章
- 苹果画画软件_水彩飞扬手把手教你在SketchBook画画(一)
- TDA2030的功率放大电路详细教程
- Perceiver_General Perception with Iterative Attention稿
- Reasoning about Quantities in Natural Language
- 【python和机器学习入门2】决策树3——使用决策树预测隐形眼镜类型
- 美国一广播电视台遭网络攻击,网站、电话、应用程序离线
- 成交量及10大应用奥妙
- 调度算法的介绍及优缺点
- DES算法加密C语言实现
- 嵌入式linux电子设计,基于嵌入式Linux的PMP系统设计与实现