Apriori算法的前世今生

作者:

wuliong,OpenFEA分析师。海归硕士,毕业于美国Rensselaer Polytechnic Institute数学专业。

————————————————————————————————————————————————

Apriori算法是一种寻找频繁项集并在此基础上生成关联规则的算法。其本质是逐层搜索的迭代方法,且每次搜索分为生成候选集与检验支持度两个阶段。这种算法简单易懂、易于实现,是数据挖掘领域的经典算法之一。

Apriori算法应用广泛,可在产品目录设计、向上销售、商品陈列布局、根据消费行为对顾客细分等典型商业问题上为决策提供支持(本文不讨论如何产生关联规则,仅对寻找频繁项集的基本概念和计算步骤做介绍)。

为方便解释名词,我们先引入一个应用场景:

一、应用场景及基本概念

假设某个淘宝店一上午有八个订单,交易明细如下:

订单号 订单内容

001 (1,2,5)

002 (2,4)

003 (2,3)

004 (1,2,4)

005 (1,3)

006 (2,3)

007 (1,2,3,5)

008 (1,2,3)

我们把这个包括全部交易细节的表格称为数据集(简称D),每一行对应一条交易记录(transaction,简称T)。交易记录里的数字是商品代码,由若干商品代码组成的集合称为项集(itemset),比如{1,3},包含k项商品代码的项集称为k项集,项集不可以为空(即k>0)。

随意选择一个项集,例如{1,3},通过查看数据集,我们发现这个项集出现在三条交易记录中,即

{1,3},

{1,2,3,5}

{1,2,3}

除以交易记录总数8,我们说这个项集的支持度(support)为37.5%。

如果设定最小支持度阈值为25%,凡支持度大于25%的项集都可以称为频繁项集(large itemset,简称L)。

算法的目的就是寻找所有符合条件(即大于支持度阈值)的频繁项集。写成数学表达式的话,算法的最终计算结果应是

U_{k}Lk

其中,Lk指所有包含k项的频繁项集所组成的集合, U_{k}指对所有Lk的并集。

二、算法基本步骤

寻找L1非常容易,只需扫描数据集并计算每个商品代码出现的次数,选择那些支持度高于阈值的即可得到L1。

但是如何找出L2,L3,...呢?

提出Apriori算法的两位作者用一句简短明了的话描述了算法的核心思想, "The basic intuition is that any subset of a larget itemset must be large"(一个频繁项集的任意一个子集必然也是频繁项集)。

举例来说,如果{1,3}是频繁项集,则它的所有子集(即{1}和{3})必然都是频繁项集。这句话暗示了自下至上搜索频繁项集的可能性,因为我们知道,任何一个集合,必然与它的部分子集的并集相同。举例来说,即便我们事先不知道{1,3}属于频繁项集,但是由于{1}和{3}都属于频繁项集,如果计算L1中任意两个频繁项集的并集,则结果中必然包括{1,3}。这种通过对任意两个(k-1)项频繁项集求并集所得到的结果,我们称之为k项候选集(Candidate,简称Ck)。候选集Ck包含了所有k项频繁项集,以及许多非频繁项集。对候选集Ck去粗取精,方能得到Lk。

从候选集中删除非频繁项集的方法有两种,第一种方法简单粗暴,即机械地计算每个项集的支持度,再删除那些支持度低于阈值的项集。另一种方法则是基于前面提到过的算法作者的话,一个频繁项集的子集必然也是频繁项集,反之,如果一个项集的某个子集不是频繁项集,则它本身也不可能是频繁项集。显而易见,后一种方法计算量小,因而会优先使用,而前一种方法虽然计算量大但是可以准确的找出所有非频繁项集,故而也会使用。

此外,值得注意的是,在构建候选集Ck的过程中,如果只是机械地对L(k-1)中的集合两两求并集,则任何一个k项频繁项集都可能会在Ck中出现多次(准确说是k*(k-1)/2次,当k>2时,该表达式大于1)。

举例来说,{1,2,3}会在C3中出现3次,因为它既是{1,2}和{2,3}的并集,也是{1,2}和{1,3},{1,3}和{2,3}的并集。如果我们在构建Ck的过程中增加一些限制条件,就可以避免重复减少计算量。

比如考虑下面这种特殊情况:假定A是一个k项频繁项集,则恰好有一个k-1项子集B1包括A的1...k-1项,又恰好有另一个子集B2包含A的1...k-2项和第k项,B1和B2都属于L(k-1)并且它们的前k-2项相同。如果在构建Ck的过程中,要求仅对前k-2项相同的两个集合求并集,则任何一个k项频繁项集在候选集中出现的次数正好是一次。当然,只有当k大于2时,我们才需要用到这个限制条件。

上述方法构成了Apriori算法的骨干,下面就结合前文提到的淘宝订单例子详细介绍算法的基本步骤。

步骤1:

寻找只含1项的频繁项集L1。如前所述,需扫描数据集并计算各个商品代码出现次数,得到支持度(为方便讨论,此处支持度采用次数而非百分比):

{1},支持度=5

{2},支持度=7

{3},支持度=5

{4},支持度=2

{5},支持度=2

步骤2:

删除支持度不高于阈值(2次)的,得到L1={{1},{2},{3}}

步骤3: 

已知L(k-1),寻找k项频繁项集Lk (k>=2)。

当k=2时,由于L1={{1},{2},{3}},很容易得到候选集C2={{1,2},{2,3},{1,3}}。

步骤4: 

进一步计算C2中每个项集的支持度分别为4,4和3,都高于阈值,所以L2={{1,2},{2,3},{1,3}}

当k=3时,已知L2={{1,2},{2,3},{1,3}},并且注意到只有{1,2}和{1,3}有相似的前k-2项(即第一项都为1),所以C3只需包括它们俩的并集即{1,2,3},并且考虑到{1,2,3}的所有子集都在L2中,所以它可以成为候选集,也就是说,C3={{1,2,3}}。计算这个唯一的候选项集的支持度,得到2,没有超过阈值,所以L3为空集。

因为L3为空,自然无法计算候选集C4甚至L4,所以计算过程到这里就结束了。而我们要找的频繁项集为L={{1},{2},{3},{1,2},{2,3},{1,3}}

这样的计算,虽然不难,但操作起来比较繁琐。所幸FEA已经实现了这个算法,我们只需对数据进行简单的处理,剩下的工作FEA会替您完成!

三、FEA寻找频繁项集的步骤

结合上文这个例子,下面手把手教您如何使用FEA寻找频繁项集,读者可在茶余饭后亲自尝试。

首先,做好数据导入的基础工作

导入数据,既可以通过导入csv文件,也可以手动创建:

a = @udf df0@sys by udf0.df_append with (1,1:2:5)

a = @udf a by udf0.df_append2 with (1,2:4)

a = @udf a by udf0.df_append2 with (8,1:2:3)

并且重命名列

rename a as (0:’tid’,1:’items’)

接着,将列类型转换为list:

a.items = str items by (split(‘:’))

然后,使用现成的函数寻找频繁项集:

a = @udf a by ML.fp_growth with (items,3)

这里参数取3,则所有支持度大于等于3的项集都会包含在结果中。

一步就查找完频繁项集

最后,dump a 查看查找结果

items support

1  5

2,1  4

3 5

1,3 3

2,3 4

2 7

第一列显示每个频繁项集所包含的项,第二列显示该项集的支持度即它在数据集中出现次数。对于这个结果,我们可以做进一步挖掘分析、寻找关联规律,限于篇幅有限此处不做展开。

读完此篇,你有没有感觉到利用FEA寻找出频繁项集,简单很多?

转载于:https://my.oschina.net/u/3115904/blog/824324

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值