在Apriori算法原理总结中,咱们对Apriori算法的原理作了总结。做为一个挖掘频繁项集的算法,Apriori算法须要屡次扫描数据,I/O是很大的瓶颈。为了解决这个问题,FP Tree算法(也称FP Growth算法)采用了一些技巧,不管多少数据,只须要扫描两次数据集,所以提升了算法运行的效率。下面咱们就对FP Tree算法作一个总结。html
为了减小I/O次数,FP Tree算法引入了一些数据结构来临时存储数据。这个数据结构包括三部分,以下图所示:
第一部分是一个项头表。里面记录了全部的1项频繁集出现的次数,按照次数降序排列。好比上图中B在全部10组数据中出现了8次,所以排在第一位,这部分好理解。第二部分是FP Tree,它将咱们的原始数据集映射到了内存中的一颗FP树,这个FP树比较难理解,它是怎么创建的呢?这个咱们后面再讲。第三部分是节点链表。全部项头表里的1项频繁集都是一个节点链表的头,它依次指向FP树中该1项频繁集出现的位置。这样作主要是方便项头表和FP Tree之间的联系查找和更新,也好理解。
下面咱们讲项头表和FP树的创建过程。算法
FP树的创建须要首先依赖项头表的创建。首先咱们看看怎么创建项头表。
咱们第一次扫描数据,获得全部频繁一项集的的计数。而后删除支持度低于阈值的项,将1项频繁集放入项头表,并按照支持度降序排列。接着第二次也是最后一次扫描数据,将读到的原始数据剔除非频繁1项集,并按照支持度降序排列。
上面这段话很抽象,咱们用下面这个例子来具体讲解。咱们有10条数据,首先第一次扫描数据并对1项集计数,咱们发现O,I,L,J,P,M, N都只出现一次,支持度低于20%的阈值,所以他们不会出如今下面的项头表中。剩下的A,C,E,G,B,D,F按照支持度的大小降序排列,组成了咱们的项头表。
接着咱们第二次扫描数据,对于每条数据剔除非频繁1项集,并按照支持度降序排列。好比数据项ABCEFO,里面O是非频繁1项集,所以被剔除,只剩下了ABCEF。按照支持度的顺序排序,它变成了ACEBF。其余的数据项以此类推。为何要将原始数据集里的频繁1项数据项进行排序呢?这是为了咱们后面的FP树的创建时,能够尽量的共用祖先节点。
经过两次扫描,项头表已经创建,排序后的数据集也已经获得了,下面咱们再看看怎么创建FP树。
数据结构
有了项头表和排序后的数据集,咱们就能够开始FP树的创建了。开始时FP树没有数据,创建FP树时咱们一条条的读入排序后的数据集,插入FP树,插入时按照排序后的顺序,插入FP树中,排序靠前的节点是祖先节点,而靠后的是子孙节点。若是有共用的祖先,则对应的公用祖先节点计数加1。插入后,若是有新节点出现,则项头表对应的节点会经过节点链表连接上新节点。直到全部的数据都插入到FP树后,FP树的创建完成。
彷佛也很抽象,咱们仍是用第二节的例子来描述。
首先,咱们插入第一条数据ACEBF,以下图所示。此时FP树没有节点,所以ACEBF是一个独立的路径,全部节点计数为1, 项头表经过节点链表连接上对应的新增节点。
接着咱们插入数据ACG,以下图所示。因为ACG和现有的FP树能够有共有的祖先节点序列AC,所以只须要增长一个新节点G,将新节点G的计数记为1。同时A和C的计数加1成为2。固然,对应的G节点的节点链表要更新
一样的办法能够更新后面8条数据,以下8张图。因为原理相似,这里就很少文字讲解了,你们能够本身去尝试插入并进行理解对比。相信若是你们本身能够独立的插入这10条数据,那么FP树创建的过程就没有什么难度了。
post
咱们辛辛苦苦,终于把FP树创建起来了,那么怎么去挖掘频繁项集呢?看着这个FP树,彷佛仍是不知道怎么下手。下面咱们讲如何从FP树里挖掘频繁项集。获得了FP树和项头表以及节点链表,咱们首先要从项头表的底部项依次向上挖掘。对于项头表对应于FP树的每一项,咱们要找到它的条件模式基。所谓条件模式基是以咱们要挖掘的节点做为叶子节点所对应的FP子树。获得这个FP子树,咱们将子树中每一个节点的的计数设置为叶子节点的计数,并删除计数低于支持度的节点。从这个条件模式基,咱们就能够递归挖掘获得频繁项集了。
实在太抽象了,以前我看到这也是一团雾水。仍是以上面的例子来说解。咱们看看先从最底下的F节点开始,咱们先来寻找F节点的条件模式基,因为F在FP树中只有一个节点,所以候选就只有下图左所示的一条路径,对应{A:8,C:8,E:6,B:2, F:2}。咱们接着将全部的祖先节点计数设置为叶子节点的计数,即FP子树变成{A:2,C:2,E:2,B:2, F:2}。通常咱们的条件模式基能够不写叶子节点,所以最终的F的条件模式基以下图右所示。
经过它,咱们很容易获得F的频繁2项集为{A:2,F:2}, {C:2,F:2}, {E:2,F:2}, {B:2,F:2}。递归合并二项集,获得频繁三项集为{A:2,C:2,F:2},{A:2,E:2,F:2},...还有一些频繁三项集,就不写了。固然一直递归下去,最大的频繁项集为频繁5项集,为{A:2,C:2,E:2,B:2,F:2}
F挖掘完了,咱们开始挖掘D节点。D节点比F节点复杂一些,由于它有两个叶子节点,所以首先获得的FP子树以下图左。咱们接着将全部的祖先节点计数设置为叶子节点的计数,即变成{A:2, C:2,E:1 G:1,D:1, D:1}此时E节点和G节点因为在条件模式基里面的支持度低于阈值,被咱们删除,最终在去除低支持度节点并不包括叶子节点后D的条件模式基为{A:2, C:2}。经过它,咱们很容易获得D的频繁2项集为{A:2,D:2}, {C:2,D:2}。递归合并二项集,获得频繁三项集为{A:2,C:2,D:2}。D对应的最大的频繁项集为频繁3项集。
一样的方法能够获得B的条件模式基以下图右边,递归挖掘到B的最大频繁项集为频繁4项集{A:2, C:2, E:2,B:2}。
继续挖掘G的频繁项集,挖掘到的G的条件模式基以下图右边,递归挖掘到G的最大频繁项集为频繁4项集{A:5, C:5, E:4,G:4}。
E的条件模式基以下图右边,递归挖掘到E的最大频繁项集为频繁3项集{A:6, C:6, E:6}。
C的条件模式基以下图右边,递归挖掘到C的最大频繁项集为频繁2项集{A:8, C:8}。
至于A,因为它的条件模式基为空,所以能够不用去挖掘了。
至此咱们获得了全部的频繁项集,若是咱们只是要最大的频繁K项集,从上面的分析能够看到,最大的频繁项集为5项集。包括{A:2, C:2, E:2,B:2,F:2}。
经过上面的流程,相信你们对FP Tree的挖掘频繁项集的过程也很熟悉了。htm
这里咱们对FP Tree算法流程作一个概括。FP Tree算法包括三步:
1)扫描数据,获得全部频繁一项集的的计数。而后删除支持度低于阈值的项,将1项频繁集放入项头表,并按照支持度降序排列。
2)扫描数据,将读到的原始数据剔除非频繁1项集,并按照支持度降序排列。
3)读入排序后的数据集,插入FP树,插入时按照排序后的顺序,插入FP树中,排序靠前的节点是祖先节点,而靠后的是子孙节点。若是有共用的祖先,则对应的公用祖先节点计数加1。插入后,若是有新节点出现,则项头表对应的节点会经过节点链表连接上新节点。直到全部的数据都插入到FP树后,FP树的创建完成。
4)从项头表的底部项依次向上找到项头表项对应的条件模式基。从条件模式基递归挖掘获得项头表项项的频繁项集(能够参见第4节对F的条件模式基的频繁二项集到频繁5五项集的挖掘)。
5)若是不限制频繁项集的项数,则返回步骤4全部的频繁项集,不然只返回知足项数要求的频繁项集。blog
FP Tree算法改进了Apriori算法的I/O瓶颈,巧妙的利用了树结构,这让咱们想起了BIRCH聚类,BIRCH聚类也是巧妙的利用了树结构来提升算法运行速度。利用内存数据结构以空间换时间是经常使用的提升算法运行时间瓶颈的办法。
在实践中,FP Tree算法是能够用于生产环境的关联算法,而Apriori算法则作为先驱,起着关联算法指明灯的做用。除了FP Tree,像GSP,CBA之类的算法都是Apriori派系的。
(欢迎转载,转载请注明出处。欢迎沟通交流: liujianping-ok@163.com) 排序