PFP(Parallel FPGrowth)
分布式FP-tree
1.首先还是对购物篮数据进行排序,计数,假设min_sup=3.去掉支持度小于3的项。
2.按照fp-tree的画法,对第二列整理过的项建树,fcamp,fcabm,fb,cbp,fcamp,建立fp-tree如下:
3.第三列是从右向左遍历第二列,得到至某点的路径,例如,到p的路径为fcam,到m的是fca,到a的是fc,到c的是f,该过程发生在map端,购物篮数据存放在各个节点上,产生如上图所示的第三列的<k,v>
4.通过shuffle过程,发送至reducer,在reduce端很容易就发现了频繁模式
为了验证上述结果,用fp-tree挖掘频繁模式:
p:第一条路径上p计数为2,小于min_sup,则去掉所有计数为2的项(f,a,m),最右边的路径上c,p各出现1次,加上第一条路径上的p:2,c:2,最终为p:3,c:3
m:第一条路径上f2-c2-a2-m2,第二条路径f1-c1-b1-m1,过滤掉b之后,总共是f3-c3-a3-m3,最终模式是:f:3,c:3,a:3,m:3
b:挖不出任何东西
同理:
a:f:3,c:3,a:3
c:f:3,c:3
命理得证。
PFP算法瓶颈:
在reduce端,mapshuffle过后将所有数据放在了reduce端,同样很容易将reduce节点的内存撑爆
http://infolab.stanford.edu/~echang/recsys08-69.pdf给出了一种方法
1.假设分成两组G1和G2,G1包含商品c,a,p;G2包含商品f,b,m,
2.对每一个购物篮数据进行处理
第一个购物篮数据:f,c,a,m,p,分成G1,G2两组,上面的思想是根据商品映射出许多<k,v>,在这里不再根据商品映射,而是根据分组映射,G1组中处于第一个购物篮中最右边的是p,则写下购物篮fcamp,这里key是G1,value是fcamp;同理G2为key时,value是fcam,即<G1,fcamp><G2,fcam>;
第二个购物篮数据:f,c,a,b,m,分成G1,G2两组,<G1,fca><G2,fcabm>
第三个购物篮数据:f,b,分成G1,G2两组,<G1,null><G2,fb>
第四个购物篮数据:c,b,p分成G1,G2两组,<G1,cbp><G2,cb>
第五个购物篮数据:f,c,a,b,m,分成G1,G2两组,<G1,fcamp><G2,fcam>
过程如下图:
3.上面的<k,v>会映射到G1,G2两台机,分别重构出fp-tree
G1映射出的fp-tree及从该树中挖取的频繁模式如下:
G2映射出的fp-tree及从该树中挖取的频繁模式如下:
Mahout实现:
mahout fpg -i output.dat -o patterns -k 10 -method mapreduce -regex '[\ ]' -s 10
指令的含义在mahout的网站上有详细说明,简要说下,-i表示输入,-o表示输出,-k 10表示找出和某个item相关的前十个频繁项,-method mapreduce表示使用mapreduce来运行这个作业,-regex '[\ ]'表示每个transaction里用空白来间隔item的,-s 10表示只统计最少出现10次的项。
成功运行后在patterns文件夹里会出现四个文件或者文件夹
- fList: 记录了每个item出现的次数的序列文件
- frequentpatterns: 记录了包含每个item的频繁项的序列文件
- fpGrowth
- parallelcounting
当然这些结果是在hdfs上面的,可以使用mahout命令查看下这些输出,在终端输入 mahout seqdumper -i patterns/frequentpatterns/part-r-00000
数据结果是序列化的,需要执行seqdumper最终输出结果如下图: