所 谓挖掘频繁模式,关联和相关,即指在出现的数据集中找到一个经常出现的序列模式或者是一个经常出现的数据结构。就像搞CPU设计的人知道,Cache的预 取机制有流预取和指针预取,前者就是发现流模式,即发现在地址上顺序出现的序列模式,后者即发现指针链接模式,即链式数据结构。

比 如一个人逛超市,她的购物篮里可能装有各种商品的组合。我们设想所有的商品构成全集,每种商品用0-1表示是否出现,那么每个购物篮就可以用一个布尔向量 表示,如(0,1,...,1,0)可能表示:(没有买酸奶,买了冰激凌...买了批萨,没有买牛排),分析大量顾客的购物篮就可以得到一个用购物模式, 这个模式我们用关联规则表示,如 :

冰激凌=>批萨 [支持度 = 2%, 置信度 = 60%]

这个就表示所有顾客中有2%的人同时购买了冰激凌和批萨,而买了冰激凌的人中有60%的购买了批萨。一般来说,如果某个模式的支持度和置信度都大于各自的一个阈值,那么这个模式就是一个我们感兴趣的模式(这个就称为强关联规则)。

结合数学语言来说,就是I = {I1,I2,...Im}是所有物品的集合,而事务集D表示所有购物篮里可能的物品组合,事务T是D中的一种可能,也是I中许多物品的一个组合,这个事务用TID标识。假设A,B都是一个元素集合,并且事务T包含A,B。定义关联规则是形如A=>B的蕴含式。

若D中出现AUB的百分比为s,则称A=>B在事务集D中成立的支持度为s。所以support(A=>B) = P(AUB) // 注意,这里的U表示事务集包含A和B的并集,而不是A or B的意思

若出现A的情况下出现B的百分比为c,则称A=>B在事务集D中具有置信度c。所以confidence(A=>B) = P(B|A)

{冰激凌,批萨}是一个2项集。一个项集的出现频率是包含项集的事务数,即包含该物品组合的篮子数量,这个称为该项集的绝对支持度或计数:support_count,若这个值大于某个阈值,那么这个项集就称为频繁项集。

由条件概率公式可以得出:confidence(A=>B) = P(B|A) = support(AUB)/support(A) = support_count(AUB)/support_count(A)

那么只要知道有多少篮子里出现了批萨,以及有多少篮子里同时出现冰激凌和批萨,就可以求得出现冰激凌的条件下出现批萨的概率。

关联规则的挖掘就可以归结为挖掘频繁项集:

(1)找出所有的频繁项集。

(2)由频繁项集产生强关联规则

也就是说找出所有篮子里常出现的组合,然后在这些组合中发现规律。

显然第一步的复杂度远高于第二步,因而总体性能由第一步决定。

显然一个项集是频繁的,其子集也是频繁的,因为包含了该项集的事务必然也包含该项集的子集。换句话说只要冰激凌和批萨的组合是频繁出现的,那么冰激凌和批萨本身必然也是频繁出现的。所以往往频繁项集的数据量是非常大的。为了克服这个困难,引入了闭频繁项集和极大频繁项集的概念。

若项集X是闭的,那么只要X是Y的子集,则Y的计数一定与X的计数不同。

若项集X是极大频繁的,那么只要X是频繁的,并且X是Y的子集,那么Y一定不是频繁的。

这里,“极大”很好理解,只要再多一个物品,那么这个组合就不符合频繁了。“闭”这个字不好理解,我们可以认为只要多一个元素,一定就会发生改变,就像临界点一样。


如数据库里只有两个事务,或者说我们只调查了两个顾客的篮子。第一个是{柴,米,油,盐,酱,醋,茶},第二个是{柴,米,油,盐}。加入最小阈值为1,
也就是说出现次数多于1次的组合就是频繁的。那么显然柴,米,油,盐,酱,醋,茶都是频繁的,而柴,米,油,盐的计数为2,酱,醋,茶的计数为1。这时如
果把在集合{柴,米,油,盐}中再增加一个元素,那么新集合的计数必然变化为2,因而第二个集合是闭频繁的,同理一也是闭频繁的,另外若在一中再增加一个
元素,那么新集合计数就变为0了,因而一还是极大频繁的。

以上购物篮分析只是频繁挖掘的一种形式。事实上,形式有很多种,不同类型的形式对应了不同的计算和优化方法。我们主要研究挖掘频繁项集的完全集,闭频繁项集,和被约束的频繁项集(即满足用户指定的一组约束的频繁项集),我们的研究针对最基本的情况(单层、单维、布尔)。

单层:表示每个物品只有一个抽象层(如冰激凌和DQ就是两个抽象层的东西)

单维:表示每个物品只涉及一个维(如30-40年龄段的人、收入5000到8000的人的购物篮)

布尔:即只考虑每个元素是否出现。

Apriori算法:利用频繁项集性质的先验知识,使用层序搜索迭代。具体方法是遍历数据库,记录每项的计数,并收集满足最小支持度的项,以得出频繁1项集--L1。然后用L1找出L2,用L2找出L3,以此类推,直到不能再找到频繁k项集。

由于每次都要遍历数据库,所以需要找到一种减少搜索空间的办法--利用Apriori性质:

"频繁项集的非空子集也是频繁的"---反单调性

这个命题可以证逆否命题:即只要子集不频繁,则该项集不频繁。因为包含越多的项集,总体概率一定越小,所以命题很容易得证。试想有n个人买了大白菜,那同时买大白菜和土豆的人数肯定不会比n大。

换句话说所以只要某项集不频繁,则其超集都不频繁。所以只要迭代的找到Lk-1项频繁项集,并且发现找不到Lk项频繁项集,那么更多项的频繁项集一定不存在,因而迭代结束。

那么迭代的过程如何呢?这里主要用到连接步和剪枝步:

【连接步】大概的意思就是把两个k-1项集连接成k项集,具体算法可以参考现有资料。

【剪枝步】指的是每一步都检查该项集是否有非频繁子集,如果有则丢弃。

这样,首先遍历一次数据库,获得所有1项集的支持度,然后筛选出频繁1项集,再用频繁1项集进行连接步,得出备选的2项集,然后对2项集统计计算支持度并剪枝,结果得出频繁2项集,再用频繁2项集连接步,得备选3项集,再对3项集统计支持度并剪枝,得出频繁3项集....

所以就是这样一个过程的迭代:【对备选k项集统计支持度,并剪枝】--得出频繁k项集--【用频繁k项集连接步】--得出备选k 1项集

这样就可以得出所有的频繁项集,并且记录下每个项集的支持度。因而利用上一篇的公式:

confidence(A=>B) = P(B|A) = support(AUB)/support(A) = support_count(AUB)/support_count(A)

就可以得出所有规则的置信度,并挖掘出感兴趣的强规则。

---------------------------------------------------------------------------------------------------------------------------------------

频繁模式(Frequent Pattern)是频繁出现在数据集中的模式(如项集,子序列和子结构)。频繁模式一般可以用关联规则表示如何判断模式是否频

繁,有两个基本的度量:

支持度(support):该模式在所有被考察的对象中的占比,表示了该模式(规则)的有用性;

置信度(cofidence):由规则的前因推出后果的可信度,表示了规则的确定性;

设规则为A->B,则支持度和置信度可以表示如下:

support(A->B) = P(AUB)

confidence(A->B) = P(A|B)

根据上面的定义,可以得出挖掘关联规则(A->B)的问题可以归结为挖掘频繁项集(因为这里的概率运算都可以用满足条件的项的出现次数和总个数的

比表示):

1. 找出所有的频繁项集;

2. 有频繁项集产生强关联规则;

将可以看到,第一步的开销远大于第二步,所以性能将由第一步决定。

挖掘海量数据的主要挑战是这种挖掘常常产生大量满足最小支持度阈值的项集,因为如果一个项集是频繁的,那么它的每个子集也是频繁的。比如说

包含100个项集的子集就远远超出了目前计算机的储存限制。为了克服这个问题,提出了比频繁项集和极大频繁项集的概念。

闭频繁项集:如果不存在真超项集Y使得Y与X在项集S中有相同的支持度计数,则称X在S中试闭的。项集X是S中的闭频繁项集,如果X在S中是闭的

和频繁的;

极大频繁项集:如果X是频繁的,并且不存在超项集Y使得X属于Y,并且Y在S中是频繁的。

闭频繁项集的集合包含了频繁项集的完整信息,但是从极大频繁项集只能知道一个特定的项集是否是频繁的,而无从得知其实际支持度计数。

下面是从事务或关系数据集中挖掘频繁项集的方法。

Apriori算法---使用候选产生发现频繁项集

Apriori算法使用逐层搜索的迭代方法,即使用包含了k个元素的项集K来探索K+1项集。每产生一个层次的项集,需要扫描整个项集一遍。为了提高逐

层扫描的效率,使用如下的Apriori 规则来压缩搜索空间。

Apriori性质:频繁项集的所有非空子集也必须是频繁的

该性质意味着"大"频繁项集可以有"小"频繁项集来产生。

设定L(k)是指每个项包含k个元素的频繁项集,意味着k层的扫描。Apriori算法 主要有两步,可以表示如下:

连接步:假设已经得到L(K-1),那么将L(K-1)与自身连接产生L(k)的候选集合。这一步主要是集合的合并运算,施加一定的限制,使得连接产生

的是K个元素;

剪枝步:得到候选集合后,应用Apriori性质。对候选集合的每一个项集,检查它的k-1子集是否在L(K)中,如果有不在的情况,则从候选项集中

删除此项集。最终得到L'(k),然后扫描整个项集,得到L'(k)每个项集的支持度计数,筛选即可得到L(k);

连续执行这两步,就可以得到所有的频繁项集:L(1),L(2),…,L(n)。

现在又很多的方法可以用来提高Apriori算法的效率,如基于散列的技术、事务压缩、划分、抽样、动态项集技术等。其中“划分”方法类似与分治

法,将数据集划分成n份,第一步得到局部的频繁项集,第二部将局部频繁项集合并得到全局频繁项集候选,最后扫描整个项集,删除候选中不符合

最小支持度计数的从未得到频繁项集。第一步中使用一种特殊的数据结构使得只需要扫描一遍局部项集就可以得到所有的局部频繁项集。至于局部项

集的划分以每个划分可以放入内存为标准。

不候选产生挖掘频繁项集

Apriori的候选-产生机制显著压缩了候选项集的大小,并导致的很好的性能,但是也有一些缺点,比如说当数据量很大的时候,候选集将会非常的大

(划分方法可以避免这一点);并且需要多次扫描数据库(划分应该是一个非常好的方法)。所以一种称作“频繁模式增长”或简称FP增长(FP Growth)

的方法应运而生了。它采用分治策略,将提供频繁项的数据库压缩到一颗频繁模式树中,但仍保留项集的相关信息。然后将压缩后的数据库划分成一

组条件数据库 ,每个关联一个频繁项或模式段,并分别挖掘每个条件数据库。其主要的过程描述如下:

1.构造FP树和项头表  FP树包含了原始数据的关联关系和计数信息。

1.1 首先遍历一遍数据库,得到1项集的计数信息,并按减序排列成L 。
        1.2 初始化一颗树T,根节点为NULL;
        1.3 第二次遍历数据库,对其中的每一项,先按照L的顺序重新组织项里面的元素,得到E'。然后查找T,检查T是否已经有一条路径为项E',若没有,则根据情况增加T的节点。并且将路径上各元素的计数加1;
        1.4 对于每一项得到的叶节点,更新项头表:如果叶节点为新加入的,则添加指针到该节点对应元素的桶的末尾。

2.由FP树得到条件模式基并构造其FP树  条件模式基实际上是由FP树中的后缀模式以及与其一起出现的前缀路径集组成。

2.1 从L中的最后一个元素e开始,以e作为后缀开始构造FP树。首先沿着项头表对应的桶得到其在T中叶子节点的位置,向上回溯就会得到其
前缀路径集:以e为结尾的所有路径的集合,并携带此路径的计数信息。路径集和e就构成了e的条件模式基;
        2.2 按照第一步的方法,从条件模式中构造它的FP树。这里就包括了多个FP树,称作条件FP树;
        2.3 条件FP树的所有路径上的元素的组合和它的后缀构成了频繁模式集;

我对这个算法的理解有几点是:

1. 数据库中的项需要根据1项集的计数从大到小排序,保证后续FP树的构造过程,使得构造过程非常简单易懂;

2. 由第一步的FP树构造过程可以看出,对于元素e,如果把在1项集中计数比e大的元素集合称作S,那么S中的元素只可能出现在e的前缀路

径集中;
        3. 由第2点可以看出 从计数小的元素开始寻找条件模式基 的原因。这样带来的一个好处是计数大的后缀模式对应的频繁模式中不用考虑计

数比自己小的元素e,因为包含e的频繁模式已近都在前面被找出来了;

FP增长方法适当变形也可以适用于大型数据库。它方法可以利用递归方法实现,有时间的话我倒想实现一个C++语言的版本看看,挺有意思的。

05-02 20:03