关联规则(Association Rules)是海量数据挖掘(Mining Massive Datasets,MMDs)非常经典的任务,其主要目标是试图从一系列事务集中挖掘出频繁项以及对应的关联规则。关联规则来自于一个家喻户晓的“啤酒与尿布”的故事,本文通过故事来引出关联规则的方法。
啤酒与尿布的故事
在一家超市里,有一个有趣的现象:尿布和啤酒赫然摆在一起出售。但是这个奇怪的举措却使尿布和啤酒的销量双双增加了。这不是一个笑话,而是发生在美国沃尔玛连锁店超市的真实案例,并一直为商家所津津乐道。沃尔玛拥有世界上最大的数据仓库系统,为了能够准确了解顾客在其门店的购买习惯,沃尔玛对其顾客的购物行为进行购物篮分析,想知道顾客经常一起购买的商品有哪些。沃尔玛数据仓库里集中了其各门店的详细原始交易数据。在这些原始交易数据的基础上,沃尔玛利用数据挖掘方法对这些数据进行分析和挖掘。一个意外的发现是:"跟尿布一起购买最多的商品竟是啤酒!经过大量实际调查和分析,揭示了一个隐藏在"尿布与啤酒"背后的美国人的一种行为模式:在美国,一些年轻的父亲下班后经常要到超市去买婴儿尿布,而他们中有30%~40%的人同时也为自己买一些啤酒。产生这一现象的原因是:美国的太太们常叮嘱她们的丈夫下班后为小孩买尿布,而丈夫们在买尿布后又随手带回了他们喜欢的啤酒。
关联规则是一种大数据挖掘的任务,最初的动机是针对购物篮分析(Market Basket Analysis)问题提出的,例如上述的“啤酒与尿布”的故事,如果超市能够发现一些具有相关联的商品购物行为,通过对商品的适当调整可以提高顾客的购物体验,提升超市的销售额,因此如何发现这些潜在的规律呢?
本文首先介绍关联规则的任务,以及相关概念,其次介绍相关算法,目录索引如下:
设 I = { I 1 , I 2 , . . . , I m } I=\{I_1,I_2,...,I_m\} I={I1,I2,...,Im}是一个项集(Item Set), m m m为项的个数,其中 I i I_i Ii表示第 i i i个项,对应于一个个商品。事务(Transaction) t i t_i ti表示 I I I的一个子集,对应于一个个订单。事务组成的集合记做 D = { t 1 , t 2 , . . . , t n } D=\{t_1,t_2,...,t_n\} D={t1,t2,...,tn},通常也称作事务数据库。通常描述中,每一个事务都有唯一的编号,记做TID,每个事务中都包含若干个项Items。
关联规则是形如 X → Y X→Y X→Y的蕴涵式,其中, X X X和 Y Y Y分别称为关联规则的先导(antecedent或left-hand-side, LHS)和后继(consequent或right-hand-side, RHS) 。其中,关联规则 X Y XY XY,存在支持度和置信度,定义如下:
例题1:分别计算3-项集“面包,牛奶,尿布”和“面包→牛奶,尿布”对应支持度和置信度。
1.可统计“面包,牛奶,尿布”同时出现的TID有4和5,所以支持度是2/5;
2.面包出现的TID有1,2,4,5,因此支持度为2/4。
因此关联规则实际上包含两个子任务:
Apriori算法是经典的关联规则算法,其主要思路如下图所示:
算法流程:
其中如果项集中包含k个不同的项,称之为k-项集。候选k-项集记做 C k C_k Ck,频繁k-项集记做 L k L_k Lk。
频繁模式挖掘的基本前提是:
例题2:使用Apriori算法对事务集 D D D进行频繁项挖掘,其中minsupport.count=2.
首先对事务数据库 D D D进行扫描,统计各个1-项的计数。由于最小计数阈值minsupport.count=2,因此可以筛选出频繁1-项集“ l 1 , l 2 , l 3 , l 4 , l 5 l_1,l_2,l_3,l_4,l_5 l1,l2,l3,l4,l5”。其次两两组合,形成 5 × 4 ÷ 2 = 10 5\times4\div2=10 5×4÷2=10个候选2-项集 C 2 C_2 C2,并进行第二次扫描数据库进行计数,发现 ( l 1 , l 4 ) , ( l 3 , l 4 ) , ( l 3 , l 5 ) , ( l 4 , l 5 ) (l_1,l_4),(l_3,l_4),(l_3,l_5),(l_4,l_5) (l1,l4),(l3,l4),(l3,l5),(l4,l5)低于阈值,所以剔除掉。对剩余的频繁2-项集 L 2 L_2 L2进行两两组合,去除重复的组合后形成候选3-项集 C 3 C_3 C3,以此类推,最终得到频繁3-项集为 ( l 1 , l 2 , l 3 ) , ( l 1 , l 2 , l 5 ) (l_1,l_2,l_3),(l_1,l_2,l_5) (l1,l2,l3),(l1,l2,l5)。
Apriori算法的特点:
为了改进Apriori算法,PCY由Park,Chen和Yu等提出,其目标是为了降低Apriori算法频繁的扫描数据库,其次降低候选项集所占用的内存。其主要创新点有:
如上图,左边两个图表示Apriori算法的前两次扫描过程,可知第一次扫描内存空闲很大,而第二次扫描占用空间很多;右侧两个图则表示PCY算法的两次扫描,第一次扫描除了对1-项集进行计数外,额外利用一个2-项哈希表存储每个2-项的计数,再第二次扫描时则利用该哈希表对应的位图来判断是否保留该2-项,从而减少候选2-项集大小。
PCY主要思想可总结如下:
例题3:使用PCY算法生成频繁2-项集,其中minsupport.count=2,哈希函数为:
事务及集合 D D D:
1.首先对1-项集进行计数,筛选出频繁1-项集 L 1 L_1 L1为{A},{B},{C},{E};
2.其次根据事务集中每个事务的项两两组合,并通过哈希函数映射到7个桶中。例如 { A , C } \{A,C\} {A,C}哈希值为 ( 1 × 10 + 3 ) m o d 7 = 6 (1\times 10+3 )mod 7=6 (1×10+3)mod7=6,所以其映射到下标为6的桶中;最终形成的桶如下图所示,如果桶的计数超过不小于2,则为频繁桶,位图对应为1。所有桶的计数分别为3,1,2,0,3,1,3,位图对应为1,0,1,0,1,0,1。
3.频繁1-项集 L 1 L_1 L1,中两两组合,并将每一个组合通过哈希函数得到对应的桶编号,如果对于的位图为1,则保留为候选2-项。最终从6个项中筛选出 { A , C } , { B , C } , { B , E } , { C , E } \{A,C\},\{B,C\},\{B,E\},\{C,E\} {A,C},{B,C},{B,E},{C,E}共4个作为候选项集 C 2 C_2 C2;
4.最后第二次扫描计数,得到对应的频繁2-项集 L 2 L_2 L2为 { A , C } , { B , C } , { B , E } , { C , E } \{A,C\},\{B,C\},\{B,E\},\{C,E\} {A,C},{B,C},{B,E},{C,E}
因此总的来说,PCY算法的关键在于在第一次和第二次扫描之间通过哈希计数提前过滤掉一部分2-项集,使得候选2-项集规模变小,而这种筛选的规则则是根据频繁桶来确定。
PCY算法特点:
事实上,PCY算法面临一个问题,即由于哈希函数的原因,有些非频繁项被映射到了频繁桶中,导致这部分非频繁项很难被过滤掉,因此多阶段算法旨在解决这个问题。其主要思路是:
多阶段算法特点:
多哈希算法与PCY算法基本一致,不同在于PCY算法只使用一个哈希表,而多哈希算法则是使用了多个哈希表,其算法思想与PCY一致,只是在判断是否是候选2-项集时,需要同时判断多个对应位图是否均为1,如下图所示:
多哈希算法特点:
先前的方法均存在一个问题,即频繁的对数据库进行扫描,而每次扫描的目的则是为了计数,因此如何只对数据库进行两次扫描便可以对所有可能的频繁项进行计数呢?FP-Tree算法巧妙的解决了这个问题。
FP-Tree算法主要分为两个步骤:构建FP树和频繁模式挖掘。
一、构建FP树算法:
二、频繁模式挖掘
例题4:已知最小支持度阈值为3,使用FP-Tree算法进行频繁项挖掘,事务数据库如图所示:
如图可知,事务数据库中共有9个事务,6个项。此时可知a,b,c,d,e,f的计数分别为7,6,5,5,3,1。首先第一次扫描后可过滤掉“f”,其次根据各自计数在每个事务记录内降序排列。
根据计数生成Head Table;
其次构建FP树,例如事务记录TID=1开始,向根结点依次插入结点(a:1),(b:1),(d:1),此时Head Table中的a,b,d指针分别指向新增的结点。当TID=2时,从根结点插入(b:1),(c:1),(d:1),需要注意的是,虽然当前也插入了b和c,但由于其层数与TID1不同,所以是在新的分支上。而对于TID=3时,第一个项是a,所以直接在(a:1)上计数,变为(a:2)。
以此类推,即可生成如下图所示的FP-树:
其次进行频繁项挖掘,先以e开始,可知所有路径以e结尾的有(a:7,b:5,c:3,e:1)、(a:7,c:1,d:1,e:1),(a:7,d:1,e:1)。根据条件模式基,需要将每个结点的计数变为最小的值,即变为(a:1,b:1,c:1,e:1)、(a:1,c:1,d:1,e:1),(a:1,d:1,e:1)。此时可以发现每个项的计数有(a:3),(b:1),(c:2),(d:2),(e:3),由于阈值为3,则只保留(a:3)和(e:3)。因此可以得到频繁项有(ae:3)和(e:3)。需要注意的是,当前的基底是e,因此必须包含e,例如(a:3)不是e的条件模式基,则不能包含该项。
FP-Tree算法特点:
FP-Tree算法有许多可改进之处,例如如果当事务的数量非常庞大时,构建FP树会占用大量的时间,XFP-Tree算法旨在并行的构建FP树来提升效率。
XFP-Tree算法需要创建两个数据结构,分别是XFP-Tree和位图矢量:
有相关工作对Apriori进行了改进,除了先前介绍的PCY,多阶段、多哈希外,使用GPU进行频繁模式挖掘也是一种改进之处。 GPApriori算法则使用GPU进行频繁项挖掘。
GPApriori算法主要创新点为:(1)使用字典树来保存候选项,(2)使用纵向事务列表,(3)可并行实现支持度计算;
一、字典树
由于许多的候选项可能有相同的前缀,例如候选3-项“1,2,4”和“1,2,5”都有相同的前缀“1,2”,因此可以使用字典树保存。
二、事务的纵向表示
存储一个对应于每个候选集的事务id列表(tidset),每个列表也可以被表示为一个位掩码(bitset)。例如下图,左侧为传统的事务表示,右侧为纵向表示,Candidate表示候选的项集,tidset则表示对应项集包含的事务记录,其可以使用bit码表示。例如1-项集只有第1和第4个事务存在,所以bit码可以写成1001。
之所以可以使用纵向表示,是因为:
(1)当判断两个项的组合是否是频繁项时,直接将二者对应的bit码按位求与计算,结果中1的个数即为支持度计数值。例如判断2-项集(1,3)的计数,则直接求1001和1111的按位与,结果为1001,则说明有两个事务满足这个20项集,再例如3-项集(1,3,5),则可以表示为(1,3)的1001和(5) 的1101按位与,结果为1001,说明也有两个事务同时包含项1、3、5。
(2)使用纵向表示法,可以并行的对支持度进行计数,这也是第三个贡献。
三、并行支持度计算
当使用纵向表示时,可以将纵向事务表划分为多个分块,每个分块置于GPU计算节点上,最后使用并行归约法获得总计数。
参考文献
【4】Zhang F, Zhang Y, Bakos J. Gpapriori: Gpu-accelerated frequent itemset mining[C]//Cluster Computing (CLUSTER), 2011 IEEE International Conference on. IEEE, 2011: 590-594.
博客记录着学习的脚步,分享着最新的技术,非常感谢您的阅读,本博客将不断进行更新,希望能够给您在技术上带来帮助。