一.假设数据集:
项的集合: I (A,B,C,D,E,F,G,H…Z)
交易数据库:D (001,002,003…007)
TID | Item1 | Item2 | Item3 | Item4 |
001 | A | B | C |
|
002 | B | C | F |
|
003 | D | F | G |
|
004 | A | B | C | Z |
005 | B | M | H |
|
006 | B | G |
|
|
007 | B |
|
|
|
二.采用FPGrowth 算法挖掘关联规则
1)算法介绍
FP growth算法采用分而治之的方法挖掘数据库中的频繁序列项。
算法描述:将数据库中的内容保存在FP Tree(频繁模式树(Frequent Pattern tree)简称为FP-tree)的数据结构中--该结构包含了所有itemsets间的关联信息。每个FP Tree为一组条件数据库,每个条件数据库关联一个频繁项集。
优点:不像Apriori那样需要产生大量候选项,只需要扫描2次数据库。
缺点:数据库庞大时,难以在内存中构筑如此大的FPTree对象。通常的解决方法是将数据库切分成若干个小数据库,进行并行处理。
FP Tree的结构:
由三部分组成:
1.根节点(值为null)
2.项前缀子树,树中的每个结点包括三个域:item_name、count和node_link,其中:
item_name表示项的名字;
count表示包含该节点的事务数;
node_link用于连接树中相同标识的下一个结点,如果不存在相同标识下一个结点,则值为“null”。
3.频繁项头表频繁项头表的表项包括一个频繁项标识域:item_name和一个指向树中具有该项标识的第一个频繁项结点的头指针:head of node_link。
FP Tree的构造过程:
1.Min_Support假设为2,扫描一次数据库,统计出每个1-itemset的数量,排序,删除不满足最小支持度的itemsets:
ItemSet | Sup.Count |
B | 6 |
C | 3 |
A | 2 |
F | 2 |
G | 2 |
2.创建一个树的根节点rootl。数据库中的每个事务按照上表中的顺序排列,不存在于上表中的项删除。整理后如下表所示:
TID | set |
001 | BCA |
002 | BCF |
003 | FG |
004 | BCA |
005 | B |
006 | BG |
007 | B |
eg:
对于事务001-------B:1,C:1,A:1,将B连接到root,C连接到B,A连接到C,形成一条子树,这三个节点的count记为1。
对于事务002-------B:1,C:1,F:1,因为已经存在B和C到达root的路径了,所以不需要另立分支,只需要对B和C节点count记为2,而在C处分出一个节点F,Count记为1.
对于事务003--------F:1,G:1,因为还不存在F到达null的路径,所以另立分支,如下图所示,count均记为1.
直到遍历完所有事务。
3.项头表记录了构造树中第一次出现该项的位置。如事务001构造过程中,B,C和A都是第一次出现,他们的位置均被该表所记录。而如果第二次出现B时,则由第一次出现的B节点中node_link来记录,并依次类推。
FPTree构造如下:
FP Tree的查找过程:
1.从项头表中最后一项G开始查找。以G为后缀寻找到达null的前缀路径,如下表所示得到了{B:1},{F:1},但他们与G可能的组合的频次都没有达到min_support,所以没有形成高频项。
2. 寻找到A的时候,{B,C:2}满足min_support,所以可以产生如表所示的高频项。
3.类似遍历树,最终的结果为:
Item | 条件数据库 | 条件FP Tree | 高频项 |
G | {B:1},{F:1} | 无 | 无 |
F | {B,C:1},null | 无 | 无 |
A | {B,C:2} | {B,C:2} | {A,B:2},{A,C:2},{A,B,C:2} |
C | {B:3} | {B:3} | {B,C:3} |
算法来源参考:
https://cwiki.apache.org/confluence/display/MAHOUT/Parallel+Frequent+Pattern+Mining
三.Mahout中的实现
FPGrowthDriver里一开始是各种参数的处理与校验,参数有以下8个:
minSupport 最小支持计数,默认3.
maxHeapSize 最大的堆大小,表示top K的item数,默认50。
numGroups 分组数,即将数据分成多少组来建立频繁树,默认1000。
splitterPattern 特征的分割符,默认 \"[ ,\\t]*[,|\\t][ ,\\t]*\" ", "[ ,\t]*[,|\t][ ,\t]*。
numTreeCacheEntries 树的entry的缓存数,用来防止树的重复建立,默认5,建议5到10。
method 指定是顺序方式(sequential),还是mapreduce计算方式(mapreduce)。
encoding 文件的编码集,默认utf-8。
userFPG2 用用户自定义的FPG实现方式。
支持单机版和mr版2种,通过method这个参数设置:
- if ("sequential".equalsIgnoreCase(classificationMethod)) {
- runFPGrowth(params);//如果单机版就runFPGrouth
- } else if ("mapreduce".equalsIgnoreCase(classificationMethod)) {
- Configuration conf = new Configuration();
- HadoopUtil.delete(conf, outputDir);
- PFPGrowth.runPFPGrowth(params);//mr版就会去跑runPFPGrouth这个方法
- }
1.先看比较简单的单机版,也就是runFPGrowth这个方法。
前面都是一堆简单的参数解析,关键就在
generateTopKFrequentPatterns(Iterator<Pair<List<A>,Long>> transactionStream,
Collection<Pair<A, Long>> frequencyList,
long minSupport,
int k,
Collection<A> returnableFeatures,
OutputCollector<A,List<Pair<List<A>,Long>>> output,
StatusUpdater updater)
这个方法,如果不设置参数userFPG2的话默认是用FPGrowth这个类的。这个 方法的作用是根据数据的最小支持计数和事务文件计算出前k条频繁模式。
首先fp.generateFList()这个方法统计所有feature的支持度计数,将所有大于minSupport的feature选出并排序。
然后生成2个map和一个数组,俩map的作用是给属性标id,一个是属性-id,一个是id-属性的映射,数组则是将id和次数做上对应。
最后通过第二部中生成的这些generateTopKFrequentPatterns(),包括生成FPTree,并进行算法的核心部分。
2.如果使用的mapreduce计算方式,则调用PFPGrowth的runPFPGrowth方法。具体可以看http://yaven.iteye.com/blog/1722702,说得挺清楚了。