如何从购物数据中挖掘出啤酒与尿布的关联关系?
首先说一个关联分析的经典案例,零售业巨头沃尔玛对消费者的购物行为进行分析时发现,男性顾客在购买婴儿尿布时,通常会顺带购买几瓶啤酒来犒劳自己,于是推出了尿布和啤酒摆在一起销售的促销手段。而这个举措真的获得了巨大成功,尿布与啤酒的销量都大幅增加了。大型超市的商品超过万种,每日有过千的交易量,如何从顾客的购买行为中发现哪几种是经常在一起购买的呢,这就要用到关联分析了。
关联分析(association snalysis)可以从大规模数据集中寻找物品间的隐含关系,上述的尿布与啤酒就是在商业领域应用中的一个经典案例。通过提取出反映顾客偏好的有用的规则,可以制定出有效的营销策略来促进销量。关联分析不仅在商业领域被广泛应用,在医疗,保险,电信和证券等领域也得到了有效的应用。在介绍实现原理之前,先讲解一下关联分析涉及的几个基本概念。
基本概念
项(item)
在购物篮事务中,一种商品就是一个项。比如,顾客购物单中的商品,啤酒和尿布都是一个项。
项集(item sets)
包含0个或多个项的集合,如果包含k个项,称为k-项集。比如,{啤酒}为1-项集,{啤酒,尿布}为2-项集。
支持度(support)
包含项集的记录在所有记录中所占的比例。我们用σ\sigmaσ(啤酒)表示包含啤酒的记录数,用N表示所有的记录数,sss(啤酒)表示支持度,那么{啤酒}这个项集的支持度就是:
s(啤酒)=σ(啤酒)Ns(啤酒)=\frac{\sigma(啤酒)}{N}s(啤酒)=Nσ(啤酒)
频繁项集(frequent item sets)
如果我们对项集的支持度设定一个最小阈值,那么所有支持度大于这个阈值的项集就是频繁项集。
关联规则(association rules)
其实是两个项集之间的蕴涵表达式。如果我们有两个不相交的项集P和H,就可以有规则P→YP\rightarrow YP→Y, 例如{尿布}→\rightarrow→{啤酒}。项集和项集之间组合可以产生很多规则,但不是每个规则都是有用的,我们需要一些限定条件来帮助我们找到强度高的规则。
可信度(confidence)
关联规则的可信度定义为:H在包含P的记录中出现的频繁程度。还是{尿布}→\rightarrow→{啤酒}这个例子,包含{尿布}的记录出现了4次,包含{尿布,啤酒}的记录也出现了3次,那么这个规则的可信度就是0.75。
发现频繁项集
下表是一个杂货店的交易记录,包含5种商品:面包、牛奶、尿布、啤酒、可乐。
交易编号 | 商品 |
---|---|
1 | 啤酒 |
2 | 面包,啤酒 |
3 | 尿布,啤酒 |
4 | 尿布,啤酒,可乐 |
5 | 牛奶,尿布,啤酒 |
6 | 面包,牛奶,可乐 |
用A-E这5个字母代表上述5种商品,商品间的组合可以产生多少项集呢?如下图所示,包含空集在内一共32个项集。
推及到N种商品,产生的项集数为2N2^N2N个。即使有100种商品,也会有超过103010^{30}1030种可能的项集。大型超市有万种以上的商品,机器要遍历所有的项集的代价会非常高。
如何解决上述问题呢,这就引出了Apriori算法,它开创性的使用了基于支持度的剪枝技术来控制候选项集的指数级增长。该算法的原理是说如果某个项集是频繁的,那么它的所有子集也是频繁的。如上图给出的例子,如果{A,B}是频繁的,那么{A}与{B}也一定是频繁的。直观上看没什么帮助,但如果反过来看就有用了,如果一个项集是非频繁项集,那么它的所有超集也是非频繁的。还是上图的例子,如果{A}是非频繁项集,那么所有包含A的项集,比如{AB}、{AC}等,都是非频繁项集,也就不需要计算了。
Apriori算法的过程是这样的,初始时,每种商品作为一个项集组成项长度为1的候选项集(1-项集)的集合;第2步,遍历候选项集(k-项集),通过计算支持度,过滤得到频繁项集(k-项集)的集合;第3步,基于上一步得到的频繁项集(k-项集),合并生成项长度+1的候选项集(k+1项集)集合;重复上述2-3 步,直到没有新的候选集可以产生。Apriori算法的伪代码为:
输入: 样本集 DDD = {x1,x2,...,xnx_1,x_2,...,x_nx1,x2,...,xn};
最小支持度 minSupportminSupportminSupport
过程:
- 统计DDD中总记录数,记为n
- 遍历DDD中所有记录,每种物品生成一个项集,例如c1c_1c1={A},组成1-项的候选项集C1C_1C1={c1,c2,...,cmc_1,c_2,...,c_mc1,c2,...,cm}
- repeat
- 令k-项频繁项集:Lk=∅L_k= \emptysetLk=∅
- 令支持度计数:SC=∅SC= \emptysetSC=∅
- for i=1,2,...,ni = 1,2,...,ni=1,2,...,n do
- for j=1,2,..∣Ck∣j = 1,2,..|C_k|j=1,2,..∣Ck∣ do
- if cj⊂xic_j \subset x_icj⊂xi then
- 支持度计数SCcjSC_{c_j}SCcj加1:SCcj=SCcj+1SC_{c_j}=SC_{c_j}+1SCcj=SCcj+1
- end if
- end for
- end for
- for i=1,2,...,∣SC∣i = 1,2,...,|SC|i=1,2,...,∣SC∣ do
- 计算项集的支持度:si=SCins_i = \frac{SC_i}{n}si=nSCi
- if si>minSupports_i > minSupportsi>minSupport then
- 将项集SCiSC_iSCi并入频繁项集LkL_kLk:Lk⋃{SCi}L_k \bigcup \{SC_i\}Lk⋃{SCi}
- 将支持度sis_isi并入支持度结果集SkS_kSk:Sk⋃{si}S_k \bigcup \{s_i\}Sk⋃{si}
- end if
- end for
- for i=1,2,...,∣Lk∣i = 1,2,...,|L_k|i=1,2,...,∣Lk∣ do
- for j=i+1,i+2,...,∣Lk∣j = i+1,i+2,...,|L_k|j=i+1,i+2,...,∣Lk∣ do
- 对第iii个项集LkiL_{ki}Lki与第jjj个项集LkjL_{kj}Lkj排序,如果前k-1个项相同,那么将这两个项集的并集,合入到候选项集Ck+1C_{k+1}Ck+1:Ck+1⋃{Lki⋃Lkj}C_{k+1}\bigcup\{L_{ki}\bigcup L_{kj}\}Ck+1⋃{Lki⋃Lkj}
- end for
- end for
- until 频繁项集LkL_kLk为空
输出: 频繁项集列表L={L1,L2,...,Lk}L = \{L_1,L_2,...,L_k\}L={L1,L2,...,Lk}
频繁项集对应的支持度S={S1,S2,...Sk}S=\{S_1,S_2,...S_k\}S={S1,S2,...Sk}
挖掘关联规则
上面介绍如何使用Apriori算法来发现频繁项集,那如何从中挖掘出关联关系呢?比如频繁项集{啤酒,尿布},那么可能有一条关联规则“尿布→\rightarrow→啤酒”。这意味着如果有人购买了尿布,那么有很大概率会同时购买啤酒,但反过来并不一定成立。
频繁项集的量化指标是支持度,同样地,关联规则也有量化指标可信度(confidence)。一条规则P→\rightarrow→ H,规则前件为P,规则后件为H,它的可信度计算公式为:
conf(P→H)=support(P⋃H)support(P)conf(P\rightarrow H)=\frac{support(P\bigcup H)}{support(P)}conf(P→H)=support(P)support(P⋃H)即项集P和H合并组成的项集的支持度,除以项集P的支持度。
类似频繁项集是基于支持度剪枝生成的,关联规则也可以基于可信度的剪枝来生成。首先,一个频繁项集中的每个项作为规则后件H,生成一个H长度为1的候选规则集;第2步,计算候选规则集的可信度,过滤得到剪枝后的规则后件H;第3步,合并剪枝后的规则后件H,生成H长度+1的新的候选规则集,重复上述第2-3步,直到不能再合并为止。举例来讲,频繁项集{‘A’,‘B’,‘C’},首先创建一个规则后件H长度为1的候选规则集[{‘A’,‘B’}→\rightarrow→{‘C’},{‘A’,‘C’}→\rightarrow→{‘B’},{‘B’,‘C’}→\rightarrow→{‘A’}],然后计算可信度,满足要求的规则集为[{‘A’,‘B’}→\rightarrow→{‘C’},{‘A’,‘C’}→\rightarrow→{‘B’}];那么就可以合并规则后件{‘C’}和{‘B’},得到新的候选规则集[{‘A’}→\rightarrow→{‘B’,‘C’}],再计算可信度,得到规则集。具体过程的伪代码如下:
输入: 频繁项集 LLL = {L1,L2,...,LkL_1,L_2,...,L_kL1,L2,...,Lk}
频繁项集对应的支持度S={S1,S2,...Sk}S=\{S_1,S_2,...S_k\}S={S1,S2,...Sk}
最小可信度 minConfminConfminConf
过程:
- 初始化规则集:R=∅R=\emptysetR=∅
- for i=2,3,...,ki = 2,3,...,ki=2,3,...,k do
- for j=1,2,..∣Li∣j = 1,2,..|L_i|j=1,2,..∣Li∣ do
- 生成由频繁项集LijL_{ij}Lij中元素组成的1-项候选集:HLHLHL
- 令剪枝的规则后件H的集合:prunedHL=∅prunedHL=\emptysetprunedHL=∅
- for HHH ininin HLHLHL do
- 计算可信度:conf(P→H)=support(Lij)/support(Lij−H)conf(P\rightarrow H)=support(L_{ij})/support(L_{ij}-H)conf(P→H)=support(Lij)/support(Lij−H)
- if conf(P→H)≥minConfconf(P\rightarrow H) \geq minConfconf(P→H)≥minConf then
- P→HP\rightarrow HP→H规则并入规则集:R⋃{(P,H,conf(P→H))}R\bigcup \{(P,H,conf(P\rightarrow H))\}R⋃{(P,H,conf(P→H))}
- 规则后件H并入剪枝的集合:prunedHL⋃{H}prunedHL\bigcup \{H\}prunedHL⋃{H}
- end if
- end for
- repeat
- 利用apriori中生成候选项集的方法,合并剪枝了的k-1-项(k为项的长度)集合prunedHL,得到合并后的k-项集合HL
- 执行步骤5-12,计算合并后的HL的可信度,并生成新的剪枝后的k项集合prunedHL
- until ∣Lij∣≤k+1|L_{ij}| \leq k+1∣Lij∣≤k+1 或者 ∣prunedHL∣≤1|prunedHL|\leq 1∣prunedHL∣≤1
- end for
- end for
- 输出: 规则集RRR
编程实现
数据集使用的上述杂货店的交易记录,发现频繁项集和挖掘关联规则的具体实现代码如下:
#创建数据集
def loadDataSet():return [['啤酒'],['面包','啤酒'],['尿布','啤酒'],['尿布','啤酒','可乐'],['牛奶','尿布','啤酒'],['面包','牛奶','可乐']]#创建候选项集列表C1
def createC1(dataSet):C1=[]for transaction in dataSet: for item in transaction:if not [item] in C1:C1.append([item]) #遍历数据集,生成只有单个商品的候选项集列表C1.sort()return list(map(frozenset,C1)) #对C1中每个项设置为一个不变的集合#生成频繁项集,频繁项集对应的支持度
def scanDataSet(dataSet, Ck, minSupport): # 输入数据集,候选项集列表,最小支持度supportCnt = {} #支持度计数for transaction in dataSet:for can in Ck:if can.issubset(transaction): # 候选项集是否都包含于一条交易记录中if not can in supportCnt: supportCnt[can]=1else: supportCnt[can]+=1N = float(len(dataSet)) # 总记录数frqL = [] #频繁项集列表supportData = {} #支持度字典for key in supportCnt:support = supportCnt[key]/N #计算所有项集的支持度if support >= minSupport:frqL.insert(0,key)supportData[key] = supportreturn frqL, supportData
#根据k-1项的频繁项集列表与项集元素个数k,生成候选项集Ck
def aprioriGen(lastLk, k): Ck = []lenLastLk = len(lastLk)for i in range(lenLastLk):for j in range(i+1, lenLastLk):L1 = list(lastLk[i]); L2 = list(lastLk[j])L1.sort();L2.sort();if L1[:k-2] == L2[:k-2]: # 如果前k-2个项相同,将两个集合合并Ck.append(lastLk[i] | lastLk[j]) # |为集合的并集return Ck#apriori算法
def apriori(dataSet, minSupport = 0.5):C1 = createC1(dataSet) #项数为1的候选集dataList = list(map(set, dataSet)) #对每条交易记录里的商品去重frqL1, supportData = scanDataSet(dataList, C1, minSupport) #项数为1的频繁项集及其支持度frqL = [frqL1] #项数为1的频繁项集添加到频繁项集列表k = 2 #项数k为2while (len(frqL[k - 2]) > 0):Ck = aprioriGen(frqL[k-2], k) #基于上一频繁集列表生成新候选项集CkfrqLk, supportK = scanDataSet(dataList, Ck, minSupport) #项数为k的频繁项集及其支持度supportData.update(supportK) #把k项频繁项集的支持度更新到支持度字典里frqL.append(frqLk) #添加k项频繁项集k += 1return frqL, supportData#从频繁集中挖掘规则
def generateRules(frqL, supportData, minConf):ruleList = [] #包含可信度的规则列表for i in range(1, len(frqL)): #频繁项集中至少两个元素for freqSet in frqL[i]:HL1 = [frozenset([item]) for item in freqSet] #频繁项集的元素列表NHL1 = calcConf(freqSet, HL1, supportData, ruleList, minConf) # 计算H为单个元素时的规则P->H可信度mergeH(freqSet, NHL1, supportData, ruleList, minConf) # P->H1与P->H2都可信,那么尝试计算P->{H1,H2}可信度return ruleList#计算可信度:P->H,返回满足可信度的H集合
def calcConf(freqSet, HL, supportData, ruleList, minConf):prunedH = [] #基于可信度剪枝的集合for H in HL:conf = supportData[freqSet]/supportData[freqSet-H] # 可信度(P->H)=支持度(频繁集)/支持度(频繁集-子集H)if conf >= minConf:print(freqSet-H,'-->',H,'conf:',conf)ruleList.append((freqSet-H, H, conf)) # P->H可信度加入规则列表prunedH.append(H)return prunedH#递归的合并H,计算新规则的可信度
def mergeH(freqSet, HL, supportData, ruleList, minConf):m = len(HL[0]) # H的元素个数if (len(freqSet) > (m+1)): #频繁项集比规则后件H的元素数多1个以上,就可以进一步合并MHL = aprioriGen(HL, m+1) #合并后H列表,H元素数+1 newHL = calcConf(freqSet, MHL, supportData, ruleList, minConf) #计算可信度,生成满足可信度的H列表if (len(newHL) > 1): #有多于1个H,就尝试进一步合并mergeH(freqSet, newHL, supportData, ruleList, minConf)
#创建数据集
dataSet = loadDataSet()
#生成频繁项集及其对应的支持度
frqL,suppData=apriori(dataSet,0.3)
#生成关联规则
rules = generateRules(frqL, suppData, 0.7)
程序执行的结果如下,只得到了一条{尿布}→\rightarrow→{啤酒}的强关联规则。
小结
关联分析可以在大规模数据集中发现物品间有趣的关系,可以采用两种方式量化这种关系。第一种方式是使用频繁项集,它给出了一些经常在一起出现的物品;第二种方式是关联规则,它表示一种物品出现后,另一种物品极有可能也会出现。
发现物品间不同的组合是个十分耗时的任务,不可避免的需要大量的计算资源,这就需要更加智能的方法在合理的时间范围内找到频繁项集。能够实现这一目标的一个方法是Apriori算法,它开创性的使用了基于支持度的剪枝技术,可以极大的减少检索集合的数目。Apriori原理是说如果一个元素项是不频繁的,那么包含该元素的超集也是不频繁的。Apriori算法从单元素项集开始,通过组合满足最小支持度要求的项集来形成更大的集合。
关联分析中用到的两个度量是很有意义的。支持度可以过滤掉没有分析意义的项集,因为支持度低,意味着顾客同时购买这些商品的次数少,从商家的角度来看,并不具有分析的价值。而可信度代表着规则的强度,可信度越高,就表示一个物品在包含另一个物品的记录中出现的可能性越大,规则就越可靠,商家基于此规则制定策略,可以产出更大价值。
如何从购物数据中挖掘出啤酒与尿布的关联关系?相关推荐
- 风控建模十二:数据淘金——如何从APP数据中挖掘出有效变量
风控建模十二:数据淘金--如何从APP数据中挖掘出有效变量 1.常识知识 2.个例分析 3.分布排查 智能手机的诞生改变了人类的生活方式,智能手机所承载的功能日臻完善.强大,人们在衣.食.住.行.工作 ...
- 论文浅尝 - WWW2020 | 通过对抗学习从用户—项目交互数据中挖掘隐含的实体偏好来用于知识图谱补全任务...
笔记整理 | 陈湘楠,浙江大学在读硕士. 现有的知识图谱补全方法都在试图设计全新的学习算法,来使用已知的事实信息去推理知识图谱中的潜在语义.但随着知识图谱的广泛使用,知识图谱中的许多实体对应着应用程序 ...
- Excel如何从混合数据中提取出手机号码
今天跟大家分享一下Excel如何从混合数据中提取出手机号码 1.打开要处理的Excel文件 2.选中数据文本单元格区域 3.点击下图选项(Excel工具箱,百度即可了解详细下载安装信息,本文这里就不做 ...
- 如何从省级地图数据中裁剪出州级地图数据
如何从省级地图数据中裁剪出州级地图数据 开发工具与关键技术:SuperMap iDesktop 9D 作者:蒙伟志 撰写时间: 先从省级地图裁剪出你所需要的地图,比如说我裁剪的是从化区,如图下粉红色区 ...
- PTA在一大堆数据中找出重复的是一件经常要做的事情。现在,我们要处理许多整数,在这些整数中,可能存在重复的数据。
在一大堆数据中找出重复的是一件经常要做的事情.现在,我们要处理许多整数,在这些整数中,可能存在重复的数据. 你要写一个程序来做这件事情,读入数据,检查是否有重复的数据.如果有,输出"YES& ...
- 【问答集锦】从数据中挖掘宝藏,深度学习赋予机器更多“思想”
2020腾讯广告算法大赛专题直播周是由腾讯广告打造的一档大咖直播活动,特邀2020腾讯广告算法大赛的专家评委,针对联邦学习.机器学习.大数据等前沿领域的核心话题进行分享,并为算法爱好者们答疑解惑.我们 ...
- JUST技术:从GPS数据中挖掘用户行为习惯
智能设备(如智能手机.互联可穿戴设备)的使用呈指数级的增长.据统计,80%的互联网用户拥有智能手机[1],而移动应用程序的使用每年以6%的速度增长,这创造了大量的信息,并带来了大量的研究和商业机会,如 ...
- 如何从海量用户发布的内容中挖掘出各城市时下的最热话题
一. 目的: 想知道在最近几个小时内各大城市不同分类栏目下,所有用户所发布的帖子中被讨论最热的话题是什么. 二. 方法: 热点话题逻辑依据: 由于挖掘热点话题的最终目标是活跃用户的评论,所以使用高评论 ...
- 李德仁院士:在夜光遥感数据中挖掘民生相关的信息
我今天的演讲主题是<夜光遥感的数据挖掘>.大家做遥感做了那么多年,主要做自然的,地球的变化,能不能利用我们的遥感,来研究以人类以及人类活动为中心的,来做社会经济学的一个应用?因此今天 ...
最新文章
- string与数值之间的转换
- windows系统下的FTP命令
- OSChina 周日乱弹 ——身价上亿,然而找不到女朋友 你信么?
- Nginx的配置文件nginx.conf详解
- 一天1个机器学习知识点(四)
- vue是什么_什么是VUE?vue有什么作用?
- java 安装后找不到文件_(已解决)jdk安装 系统找不到文件C:\ProgramData\Oracle\Java\javapath\java.exe...
- linux主机操作性日志恢复测试,Linux主机操作系统加固规范标准[详].doc
- redis 值字符串前面部分乱码_StringBoot 整合Redis解决存储乱码(通过StringRedisSerializer来进行序列化)...
- Educational Codeforces Round 24 E. Card Game Again(双指针)
- MySQL 之 视图、触发器、存储过程、函数、事物与数据库锁
- python基础教程电子版-Python基础教程(第2版 修订版) pdf
- 看代码学知识之(1) 获取当前线程状态
- ES6-模块导入导出
- 可计算代数数论(2012-12-09 20:56、2013-03-23 21:39、2013-06-23 20:27、2013-06-23 20:32、2014-05-16 17:49)
- python 异步定时任务
- matlab时域采样理论得验证,基于matlab时域采样和频域采样验证毕业设计
- 关于时间轴发展历程等PPT模板展现方式的探讨
- Dart语言详解(一)——详细介绍
- matlab snapnow,任意倾斜椭圆方程的画法.pdf
热门文章
- unity build报错Type has an extra field of type in the and thus can‘t be serialized error
- ValueError: Cannot have number of splits n_splits=10 greater than the number of samples: n_samples=0
- 长城服务器装双系统,苹果双系统怎么装win7系统,教你苹果windows7双系统教程
- 有趣的手机壁纸——水印壁纸
- 旧弹簧(Old spring )
- Android 实现短信接收监听--(短信动态权限添加)
- 分词并去停用词自定义函数:seg_word(sentence)
- 【Node.js】论一个低配版Web实时通信库是如何实现的1( WebSocket篇)
- 在格式化字符串的边缘试探
- Numpy报错解决办法