推荐系统 - 召回 - 关联规则挖掘 (association rule)

1. 关联规则


考察一些涉及许多物品(item)的商品筐(basket):basket1 中出现了物品甲,basket2 中出现了物品乙,basket3 中则同时出现了物品甲和乙。那么,物品甲和乙在商品筐中的出现相互之间是否有规律可循呢?在数据库的知识发现中,关联规则就是描述这种在一个商品筐中物品之间同时出现的规律的知识模式。更确切的说,关联规则通过量化的数字描述物品甲的出现对物品乙的出现有多大的影响
 
现实中这样的例子很多。例如超级市场利用前端收款机收集存储了大量的售货数据,这些数据是一条条的购买事务记录,每条记录存储了事务处理时间,顾客购买的物品、物品的数量及金额等。这些数据中常常隐含形式如下的关联规则:例如发现了规则{onions, potatoes} ⇒ {burger}, 可能指示如果一个顾客同时购买了onions和potatoes,那么他很可能也会购买burger,这些信息可以用于指导市场活动,如商品定价、商品摆放位置。

  • X和Y都可以放在同一个架子上,这样一个物品的买家会被提示购买另一个。
  • 促销折扣只适用于两个项目中的一个。
  • 对于X的广告可以针对购买Y的买家投放。
  • X和Y可以组合成一个新产品(比如套餐),比如X的套餐中包含有Y。

虽然我们可能知道某些物品经常会一起购买,但问题是,我们如何去发现这些关联关系?(很典型的就是啤酒和尿布的问题)除了增加销售利润外,关联规则还可以用于其他领域。例如,在医学诊断中,了解哪些症状容易并存,有助于提高患者的护理水平和药物处方。

2. 关联规则定义

关联规则分析是一种揭示项商品之间如何相互关联的技术,有三个常用的指数来衡量关联关系。

2.1 指数一:支持度(Support)

支持度表示一个项集的流行程度,用一个项集出现的事务的比例来衡量。在下面的表1中,apple的支持率是8个中的4个,即50%。项集还可以包含多个项,例如,苹果、啤酒、大米的支持率是8个中的2个,即25%。support(X,Y,Z)就是商品X,Y,Z同时出现的概率。

设置一个支持度阈值,将支持度的值高于此阈值的项集标识为频繁项集

2.2 指数二:置信度(Confidence)

置信度表示在X被购买的前提下,Y被购买的概率。表示为confidence{X -> Y},就是P(Y|X)。在表1中,{苹果->啤酒} 的置信度为3/4,即75%。

但是置信度指数的一个缺点是它可能会误导关联的重要性,因为有的时候P(Y|X)很高,但是并不能说明X的购买会导致Y的购买。例如P(啤酒|苹果)很高,但是啤酒在一般情况下也很受欢迎,那么包含了苹果的订单中同时包含啤酒的可能性将更高,从而提高了置信度指数。但这样高的置信度并没有任何意义!

为了说明X的购买对于Y的购买究竟有什么样的影响,我们使用了第三个措施,称为提升度(Lift)

2.3 指数三:提升度(Lift)

提升度就是\frac{P(X|Y)}{P(X)},分子表示购买Y的情况下购买X的概率;分母表示购买X的概率。如果购买Y之后购买X的概率比购买X的概率要大,说明购买Y这个行为对于购买X有一个明显的提升。如果提升度为1,表明X和Y之间时完全独立的。提升度的值大于1意味着,购买X的情况下很有可能购买Y;反之,提升度的值小于1,表示用户购买X的时候更不可能购买Y。

回想一下,置信度指数的一个缺点是它倾向于歪曲关联的重要性。为了证明这一点,我们返回主数据集,选择3个包含啤酒的关联规则:

所有交易:

{canned beer->soda} 规则的置信度(confidence)最高,为20%。然而,soda本来就经常出现在所有交易中 (support 为 20%)。如果大家都很喜欢购买soda,那么购买canned beer的人当然有很大概率会购买soda。这不是因为他们购买了canned beer得缘故,而是因为他们就是喜欢购买soda。{canned beer->soda}的提升值为1,表示canned beer和soda之间没有关联。

另一方面,由于male cosmetics的购买量很少,{canned beer -> male cosmetics} 规则的置信度很低,但是,从比较高的提升度指数2.6推断,当有人购买canned beer时,他很可能也会购买male cosmetics。反过来说,{beer -> berries} 提升值低于1, 说明如果有人购买浆果,他可能会厌恶啤酒。

3. Apriori 算法

大多数关联规则挖掘算法通常采用的一种策略是,将关联规则挖掘任务分解为如下两个主要的子任务:

  1. 频繁项集产生:其目标是发现满足最小支持度阈值(频繁出现的)的所有项集,这些项集称作频繁项集。
  2. 规则的产生:其目标是从上一步发现的频繁项集中提取所有高置信度的规则,这些规则称作强规则

但是频繁项集得产生需要非常高的复杂度。在一个只有10个商品的商店中,要检查的可能搭配总数将达到2^10 -1 = 1023个,这个数字在一个有数百个商品的商店中呈指数增长。而一般的情况下,商店里有上千万个商品,如果枚举所有的子集,这是相当可怕的!所以,有没有办法降低这个复杂度呢?

3.1 先验定理

  • 如果一个项集是频繁的,则它的所有子集一定也是频繁的。

先验定理

在这个例子中,{c,d,e}是频繁项集,所以它的全部子集都是频繁项集。

  • 非频繁项集的所有超集一定是非频繁的。

反单调性

由于{a,b}是非频繁的,所以它的所有超集都是非频繁的,可以直接把这一枝剪掉。

3.2 Apriori算法

首先,得到1-频繁项集 L_1 (单个商品出现次数>支持度阈值)。然后,对于每个k-频繁项集L_k, 都计算(k+1)-频繁项集的候选集C_{k+1},C_{k+1}其实就是L_k中项集的两两组合。之后,遍历候选集C_{k+1}中的每个元素,计算它的支持度,如果小于支持度阈值,就直接剪枝;如果大于等于支持度阈值,就保留下来。

可以看下面这个动图:

可以从动画中看到,apple的支持度较低,因此它被删除了,不需要考虑包含apple的所有其他项集,这个操作可以减少一半以上的项集数量。

4. FP-growth 算法

作为一个挖掘频繁项集的算法,Apriori算法需要多次扫描数据,I/O是很大的瓶颈。为了解决这个问题,FP Tree算法(也称FP Growth算法)采用了一些技巧,无论多少数据,只需要扫描两次数据集,因此提高了算法运行的效率。

4.1 FP Tree 数据结构

为了减少I/O次数,FP Tree算法引入了一些数据结构来临时存储数据。这个数据结构包括三部分,如下图所示:

  • 第一部分是一个项头表。里面记录了所有的1-频繁项集出现的次数,按照次数降序排列。比如上图中B在所有10组数据中出现了8次,因此排在第一位。
  • 第二部分是FP Tree,它将我们的原始数据集映射到了内存中的一颗FP树,这个FP树比较难理解,它是怎么建立的呢?这个我们后面再讲。
  • 第三部分是节点链表。所有项头表里的1-频繁项集都是一个节点链表的头,它依次指向FP树中该1-频繁项集出现的位置。这样做主要是方便项头表和FP Tree之间的联系查找和更新。

4.2 项头表的建立

项头表的建立需要我们扫描两次数据集:

  • 第一次扫描数据,得到所有1 - 频繁项集的计数。然后删除支持度低于阈值的项,将1-频繁项集放入项头表,并按照支持度降序排列。
  • 第二次扫描数据,将读到的原始数据剔除非频繁1项集,并按照支持度降序排列。

举个栗子:

我们有10条数据,首先第一次扫描数据并对1项集计数,我们发现O,I,L,J,P,M, N都只出现一次,支持度低于20%的阈值,因此他们不会出现在下面的项头表中。剩下的A,C,E,G,B,D,F按照支持度的大小降序排列,组成了我们的项头表。

接着我们第二次扫描数据,对于每条数据剔除非1-频繁项集,并按照支持度降序排列。比如数据项ABCEFO,里面O是非频繁1项集,因此被剔除,只剩下了ABCEF。按照支持度的顺序排序,它变成了ACEBF。其他的数据项以此类推。为什么要将原始数据集里的1-频繁项集数据项进行排序呢?这是为了我们后面的FP树的建立时,可以尽可能的共用祖先节点。

通过两次扫描,项头表已经建立,排序后的数据集也已经得到了,下面我们再看看怎么建立FP树。

4.3 FP-tree的建立

有了项头表和排序后的数据集,我们就可以开始FP树的建立了。开始时FP树没有数据,建立FP树时我们一条条的读入排序后的数据集,插入FP树,插入时按照排序后的顺序,插入FP树中,排序靠前的节点是祖先节点,而靠后的是子孙节点。如果有共用的祖先,则对应的公用祖先节点计数加1。插入后,如果有新节点出现,则项头表对应的节点会通过节点链表链接上新节点。直到所有的数据都插入到FP树后,FP树的建立完成。

举栗子:

step1. 首先,我们插入第一条数据ACEBF,如下图所示。此时FP树没有节点,因此ACEBF是一个独立的路径,所有节点计数为1, 项头表通过节点链表链接上对应的新增节点。

step2. 接着我们插入数据ACG,如下图所示。由于ACG和现有的FP树可以有共有的祖先节点序列AC,因此只需要增加一个新节点G,将新节点G的计数记为1。同时A和C的计数加1成为2。当然,对应的G节点的节点链表要更新.

同样的办法可以更新后面8条数据,如下8张图。由于原理类似,这里就不多文字讲解了.

4.4 FP-tree的挖掘

我们辛辛苦苦,终于把FP树建立起来了,那么怎么去挖掘频繁项集呢?

得到了FP树和项头表以及节点链表,我们首先要从项头表的底部项依次向上挖掘。对于项头表对应于FP树的每一项,我们要找到它的条件模式基。所谓条件模式基是以我们要挖掘的节点作为叶子节点所对应的FP子树。得到这个FP子树,我们将子树中每个节点的的计数设置为叶子节点的计数,并删除计数低于支持度的节点。从这个条件模式基,我们就可以递归挖掘得到频繁项集了。

实在是太抽象了....还是以上面的例子来讲解。

我们看看先从最底下的F节点开始,我们先来寻找F节点的条件模式基,由于F在FP树中只有一个节点,因此候选就只有下图左所示的一条路径,对应{A:8,C:8,E:6,B:2, F:2}。我们接着将所有的祖先节点计数设置为叶子节点的计数,即FP子树变成{A:2,C:2,E:2,B:2, F:2}。一般我们的条件模式基可以不写叶子节点,因此最终的F的条件模式基如下图右所示。

通过它,我们很容易得到F的频繁2项集为{A:2,F:2}, {C:2,F:2}, {E:2,F:2}, {B:2,F:2}。递归合并二项集,得到频繁三项集为{A:2,C:2,F:2},{A:2,E:2,F:2},...还有一些频繁三项集,就不写了。当然一直递归下去,最大的频繁项集为频繁5项集,为{A:2,C:2,E:2,B:2,F:2}

F挖掘完了,我们开始挖掘D节点。D节点比F节点复杂一些,因为它有两个叶子节点,因此首先得到的FP子树如下图左。我们接着将所有的祖先节点计数设置为叶子节点的计数,即变成{A:2, C:2,E:1 G:1,D:1, D:1}此时E节点和G节点由于在条件模式基里面的支持度低于阈值,被我们删除,最终在去除低支持度节点并不包括叶子节点后D的条件模式基为{A:2, C:2}。通过它,我们很容易得到D的频繁2项集为{A:2,D:2}, {C:2,D:2}。递归合并二项集,得到频繁三项集为{A:2,C:2,D:2}。D对应的最大的频繁项集为频繁3项集。

同样的方法可以得到B的条件模式基如下图右边,递归挖掘到B的最大频繁项集为频繁4项集{A:2, C:2, E:2,B:2}。

继续挖掘G的频繁项集,挖掘到的G的条件模式基如下图右边,递归挖掘到G的最大频繁项集为频繁4项集{A:5, C:5, E:4,G:4}。

 E的条件模式基如下图右边,递归挖掘到E的最大频繁项集为频繁3项集{A:6, C:6, E:6}。

C的条件模式基如下图右边,递归挖掘到C的最大频繁项集为频繁2项集{A:8, C:8}。

至于A,由于它的条件模式基为空,因此可以不用去挖掘了。

至此我们得到了所有的频繁项集,如果我们只是要最大的频繁K项集,从上面的分析可以看到,最大的频繁项集为5项集。包括{A:2, C:2, E:2,B:2,F:2}。

4.5 FP-tree算法归纳

这里我们对FP Tree算法流程做一个归纳。FP Tree算法包括五步:

1)扫描数据,得到所有1-频繁项集的的计数。然后删除支持度低于阈值的项,将1项频繁集放入项头表,并按照支持度降序排列。

2)扫描数据,将读到的原始数据剔除非频繁1项集,并按照支持度降序排列。

3)读入排序后的数据集,插入FP树,插入时按照排序后的顺序,插入FP树中,排序靠前的节点是祖先节点,而靠后的是子孙节点。如果有共用的祖先,则对应的公用祖先节点计数加1。插入后,如果有新节点出现,则项头表对应的节点会通过节点链表链接上新节点。直到所有的数据都插入到FP树后,FP树的建立完成。

4)从项头表的底部项依次向上找到项头表项对应的条件模式基。从条件模式基递归挖掘得到项头表项项的频繁项集。

5)如果不限制频繁项集的项数,则返回步骤4所有的频繁项集,否则只返回满足项数要求的频繁项集。

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值