mahout关联规则源码分析 part2

mahout里面的关联规则是用FP-tree实现的,上次简单分析了下实现的第一步,一共有三步,如下:

mahout关联规则源码分析 part2

现简要分析下第二步:

假如原始数据如下:

牛奶,鸡蛋,面包,薯片
鸡蛋,爆米花,薯片,啤酒
鸡蛋,面包,薯片
牛奶,鸡蛋,面包,爆米花,薯片,啤酒
牛奶,面包,啤酒
鸡蛋,面包,啤酒
牛奶,面包,薯片
牛奶,鸡蛋,面包,黄油,薯片
牛奶,鸡蛋,黄油,薯片
那么生成的fList如下:

薯片  7
鸡蛋  7
面包  7
牛奶  6
啤酒  4

根据上面的两个输入(当然fList是放入内存的),ParallelFPGrowthMapper的作用就是完成每条记录的转化和输出,和Part1的截图一样,比如:

首先是转化:薯片-->0, 鸡蛋-->1,面包-->2,牛奶-->3,啤酒-->4;接着是针对每一条记录进行输出比如针对第一条记录:

牛奶,鸡蛋,面包,薯片
输出如下:

groupId    transactionTree
3    [0, 1, 2, 3]
2    [0, 1, 2]
1    [0, 1]
0    [0]
接着到ParallelFPGrowthReducer的reduce方法,(在这之前有个combiner,但是个人没有看,而是在源码中直接注释了,反正也不影响结果,应该是只影响性能的吧),此Reducer的setup方法是读取fList的,暂时没有用到。此Reducer把所有groupID相同的transactionTree通过TransactionTree.addPattern()把这些transactionTrees加入到一个TransactionTree中,然后通过这个TransactionTree构建本地的fList,即localFList(要按照出现次数由大到小排序)。

比如当groupId为3的时候,所有的transactionTree如下:

[([0, 1, 2, 3],1)]
[([0, 1, 2, 3],1)]
[([1, 3],1)]
[([0, 1, 3],1)]
[([0, 1, 2, 3],1)]
[([0, 2, 3],1)]
通过上面的TransactionTree得到localFList如下:

[(3,6), (0,5), (1,5), (2,4)]
接着调用了FPGrowth.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
其实这个方法我看了好久但是还是不知道它是如何运作的,transactoinStream应该是TransactionTree的遍历输出,frequencyList是本地的fList,output应该就是输出最后的结果;这个方法刚开始是一些转化工作,接着递归调用自己,不过这时的参数有变:

generateTopKFrequentPatterns(new TransactionIterator<A>(transactionStream,
attributeIdMapping), attributeFrequency, minSupport, k, reverseMapping
.size(), returnFeatures, new TopKPatternsOutputConverter<A>(output,
reverseMapping), updater);

其中的输出的类变为了TopKPatternOutputConverter,然后我测试到这个类输出如下,同时这个方法只递归了一次:

0    [([0],7)]
1    [([1],7), ([0, 1],5)]
2    [([2],7), ([0, 2],6), ([1, 2],5), ([0, 1, 2],4)]
3    [([3],6), ([1, 3],5), ([0, 3],5), ([0, 2, 3],4), ([0, 1, 3],4), ([0, 1, 2, 3],3)]
4    [([4],4), ([2, 4],3), ([1, 4],3)]
而整个parallelFPGrowth的输出如下,也就是第二个阶段的输出:

key:薯片,value:([薯片],7)
key:面包,value:([面包],7), ([薯片, 面包],5)
key:鸡蛋,value:([鸡蛋],7), ([薯片, 鸡蛋],6), ([面包, 鸡蛋],5), ([薯片, 面包, 鸡蛋],4)
key:牛奶,value:([牛奶],6), ([面包, 牛奶],5), ([薯片, 牛奶],5), ([薯片, 鸡蛋, 牛奶],4), ([薯片, 面包, 牛奶],4), ([薯片, 面包, 鸡蛋, 牛奶],3)
key:啤酒,value:([啤酒],4), ([鸡蛋, 啤酒],3), ([面包, 啤酒],3)
上面的两个结果其实是一样的,只要转化一下就可以了,但是转化的过程在哪里?returnFeatures即是转化的关键,但是是在哪个地方什么时候实现的?还有既然是用的FP-tree实现的,那么建立的FP-tree是哪个类?TransactionTree是这个么?。。。

其实,我已经看了关联规则第二部分好长时间了,但是一直还是没有看的明白。只能说:源码艰晦涩,入读需谨慎。

以上仅代表个人观点,难免有误,望指正。





分享,成长,快乐









你可能感兴趣的:(Mahout)