Apriori Algorithm介绍及Python实现
Comment如果商店里有5种商品Items = [I1, I2, I3, I4, I5],现在记录了9条商品的购买记录
事件编号 | 商品列表 | 事件编号 | 商品列表 |
---|---|---|---|
T100 | I1, I2, I5 | T600 | I2, I3 |
T200 | I2, I4 | T700 | I1, I3 |
T300 | I2, I3 | T800 | I1, I2, I3, I5 |
T400 | I1, I2, I4 | T900 | I1, I2, I3 |
T500 | I1, I3 |
我该如何知道某几个商品同时被购买的可能行(频率),如买I2的人也买I1的可能性多大?,买的人多不多?
这里可以用两个参数来描述,支持度(support)与置信度(confidence)。
support(I2->I1) = P(I2, I1) = 4 / 9 ([T100, T400, T800, T900])
confidence(I2->I1) = P(I1 | I2) = 4 / 7
([T100, T400, T800, T900] / [T100, T200, T300, T400, T600, T800, T900])
其中,confidence(I2->I1) = P(I1 | I2) = P(I1, I2) / P(I1) = support(I1,I2) / support(I2)
类似的,confidence(I2,I3 -> I1) = P(I1 | I2, I3) = P(I1, I2, I3) / P(I2, I3)
所以,只要知道所有情况的支持度,就能知道所有希望得到的置信度。可是,每算一次置信度就要遍历整个数据库。5个商品理论上就要遍历C(5,1) + C(5,2) + C(5,3) + C(5,4) + C(5,5) = 2^5 -1 = 31遍。如果有100个商品则是2^100 -1遍,这是很可怕的。
为了降低计算时间,首先想到的就是,减少一些不重要的情况。可以想象,商店老板希望算法可以让他知道什么商品经常被买以及经常一起被买。也就是说销量不高的商品就不需要计算了。因此一般我们都会设定一个最低支持度阈值,小于某个支持度就视为不重要的数据。假设我们设定上述的支持度阈值为2(为了方便,不归一化了),这样出现次数为0和1的情况我们就不继续计算了。
其次这里有个定理1:子集的置信度不会超过母集,比如上述商品中I3与I5同时出现的情况只有一次(T800),那么I1,I3,I5,I2,I3,I5等等包含I3,I5的情况不可能超过1,所以这些情况都不用考虑了。Apriori主要就是利用这个性质减少遍历数据库的次数。
Apriori 算法核心思路是从小集合到大集合。先找出只有一个商品且满足支持度大于等于2的集合L1,然后找出两个商品的L2,最后找出5个商品的(其实不用找到5个因为我们发现4个商品的支持度已经只有1,小于最小支持度阈值),L称为频繁项集集合(支持度大于阈值则视为频繁)。
条件 | 频率 |
---|---|
一个商品 | I1=6, I2=7, I3, I4, I5 |
两个商品 | I1,I2=4 ; I1,I3 ; I1,I4 … |
三个商品 | I1,I2,I3=2 ; I1,I2,I4 … |
该思路的难点仅在于,如何从k-1个商品(k-1项集)连接到k个商品。算法分两步
1. 连接:
让Lk-1(满足支持度阈值要求的k-1项集的集合)中的每个项集(如I1,I2)中的项按序列从小到大排列,(I1 < I2 < I3 < I4 < I5)
当两个项集的前k-2项相同时,则连接两项集的k-1项,共k项
以L3 -> L4的其中一个例子
I1, I2, I3
I1, I2, I4
上述两个项前两项相同,所以新的项集ck = {I1, I2, I3, I4}。这些新的项集的集合Ck为候选项集集合。
这一步就能去掉子集不满足的集合,比如{I1,I2,I3,I5}集合支持度只有1,不在L4中(事实上L4为空集),所以不会去找比之更大的项集。
同样,{I3,I5}的支持度为1,所以I3,I5,Ix都不会出现。
2. 剪枝:
如连接中的例子,虽然新的{I1, I2, I3, I4}项集满足 子集{I1, I2, I3}; {I1, I2, I4} 都是频繁项集,但其他子集也得满足,这里特指剩下两个{I1, I3, I4},{I2, I3, I4}。所以验证一下他们,如果他们不满足,可根据定理1,新的项集也肯定不频繁。
所以剪枝的过程就是验证Ck中所有项集的所有k-1子集是否都频繁(只要看看他们是不是在Lk-1集合中即可),这样虽然要检查很多遍,但不需要对整个数据库进行遍历就能筛去许多不满足的情况。
上述方法是经典的Apriori算法,这两个步骤在k较高(3或以上)时效果非常好,因为商品同时存在的可能性会随k增大显著减小。
但是在k=2的时候(k=1用不到Apriori算法,必须遍历一遍数据库,相当于“链引发”),因为1项集一般都是频繁的,所以上述两个步骤基本上相当于没有用,还得遍历C(n,2)次数据库,n为频繁1项集的数量。
于是需要进一步的优化(FP-Tree算法),这里不讲了。
参考文章:Jiawei Han 数据挖掘概念与技术 第三版 第六章
看到有前辈已经做过这个介绍了http://www.tanglei.name/apriori-algorithm-in-python/ 心里有点沉闷,似乎这是学计算的人才应该了解的知识,我一个学药学的人为何要起劲呢。