系列文章目录
频繁模式挖掘系列算法(一):ML【2】:Apriori 算法
频繁模式挖掘系列算法(二):
频繁模式挖掘系列算法(三):
文章目录
前言
在 Apriori
算法原理总结中,我们对 Apriori
算法的原理做了总结。作为一个挖掘频繁项集的算法,Apriori
算法需要多次扫描数据,I/O 是很大的瓶颈。为了解决这个问题,FP Tree
算法(也称 FP Growth
算法)采用了一些技巧,无论多少数据,只需要扫描两次数据集,因此提高了算法运行的效率
有关 Apriori
算法的内容可以参考我的另一篇 blog:ML【2】:Apriori 算法
1. 算法思想
FP-growth
(Frequent Pattern-growth) 是一种常用的频繁模式挖掘算法,用于从大规模数据集中挖掘频繁项集。与传统的 Apriori
算法相比,FP-growth
算法可以更快地发现频繁项集,并且不需要产生候选项集,因此在大规模数据集上具有更好的性能。
FP-growth
算法的核心思想是利用数据集中项之间的关系来构建一棵 FP
树(Frequent Pattern Tree)。FP
树是一种压缩数据集的数据结构,它将每个频繁项集映射为树上的一个路径,从而避免了频繁项集的重复计数。同时,FP-growth
算法采用递归方法来遍历 FP
树,从而发现频繁项集。
2. 算法流程
- 核心思想
- 通过模式和数据库分区递归增长频繁模式
- 实现方法
- 扫描数据,得到所有频繁一项集的的计数
- 然后删除支持度低于阈值的项,将 1 项频繁集放入项头表,并按照支持度降序排列
- 扫描数据,将读到的原始数据剔除非频繁 1 项集,并按照支持度降序排列
- 读入排序后的数据集,插入FP树
- 插入时按照排序后的顺序,插入FP树中,排序靠前的节点是祖先节点,而靠后的是子孙节点
- 如果有共用的祖先,则对应的公用祖先节点计数加 1
- 插入后,如果有新节点出现,则项头表对应的节点会通过节点链表链接上新节点
- 直到所有的数据都插入到FP树后,FP树的建立完成
- 插入时按照排序后的顺序,插入FP树中,排序靠前的节点是祖先节点,而靠后的是子孙节点
- 具体来说,
FP-growth
算法从树的底部开始,以计数值降序的顺序递归地处理每个项的条件模式基- 条件模式基是指在树中以某个项为结尾的所有路径所包含的项集
- 对每个条件模式基,
FP-growth
算法递归地构建一棵条件FP
树,然后对条件 FP 树重复以上步骤,直到不能再构建频繁项集为止。
- 如果不限制频繁项集的项数,则返回步骤4所有的频繁项集,否则只返回满足项数要求的频繁项集。
- 扫描数据,得到所有频繁一项集的的计数
3. 算法实现
3.1. FP Tree 数据结构
为了减少I/O次数,FP Tree算法引入了一些数据结构来临时存储数据。这个数据结构包括三部分,如下图所示:
- 第一部分是一个项头表
- 里面记录了所有的1项频繁集出现的次数,按照次数降序排列
- 比如上图中 B 在所有 10 组数据中出现了 8 次,因此排在第一位
- 第二部分是
FP Tree
- 它将我们的原始数据集映射到了内存中的一颗 FP 树
- 第三部分是节点链表
- 所有项头表里的 1 项频繁集都是一个节点链表的头,它依次指向FP树中该 1 项频繁集出现的位置
- 这样做主要是方便项头表和 FP Tree 之间的联系查找和更新,也好理解
3.2. 构建项头表
算法完整流程:
- 项头表的建立
- 第一次扫描数据,得到所有频繁一项集的的计数。然后删除支持度低于阈值的项,将 1 项频繁集放入项头表,并按照支持度降序排列
- 接着第二次扫描数据,将读到的原始数据剔除非频繁1项集,并按照支持度降序排列
- 这是为了后面建立
FP
树时,可以尽可能的共用父节点
- 这是为了后面建立
示例,min_support > 20%:
- 有 10 条数据
- 第一次扫描数据并对 1 项集计数
- O、I、L、J、P、M、N 都只出现一次,支持度低于 20% 的阈值,因此他们不会出现在下面的项头表中
- 剩下的 A、C、E、G、B、D、F 按照支持度的大小降序排列,组成了项头表
- 接着第二次扫描数据,对于每条数据剔除非频繁 1 项集,并按照支持度降序排列
- 比如数据项 ABCEFO,里面 O 是非频繁1项集,因此被剔除,只剩下了 ABCEF
- 按照支持度的顺序排序,它变成了 ACEBF
- 其他的数据项以此类推
3.2. 构建 FP Tree
算法完整流程:
- FP Tree的建立
- 开始时
FP
树没有数据,通过一条条的读入排序后的数据集并插入FP树,以建立FP
树 - 插入时按照排序后的顺序插入FP树中,排序靠前的节点是祖先节点,而靠后的是子孙节点
- 如果有共用的祖先,则对应的公用祖先节点计数加 1
- 插入后,如果有新节点出现,则项头表对应的节点会通过节点链表链接上新节点
- 直到所有的数据都插入到
FP
树后,FP
树的建立完成
- 开始时
- 终止条件
- 产生的
FP
树是空的 - 产生的
FP
树只包含一条路径
- 产生的
示例:
- 首先,插入第一条数据
ACEBF
,如下图所示- 此时
FP
树没有节点,因此ACEBF
是一个独立的路径,所有节点计数为 1,项头表通过节点链表链接上对应的新增节点 - 接着插入数据ACG
,如下图所示 - 由于
ACG
和现有的FP
树可以有共有的祖先节点序列AC
,因此只需要增加一个新节点G
,将新节点G
的计数记为 1 - 同时
A
和C
的计数加 1 成为 2,对应的G
节点的节点链表要更新
- 此时
- 同样的办法可以更新后面8条数据
- 所有的数据插入成功后 ,构建的 FP Tree 如下所示
- 所有的数据插入成功后 ,构建的 FP Tree 如下所示
3.3. 寻找最大频繁集
算法完整流程:
- 挖掘频繁项集
- 首先要从项头表的底部项依次向上挖掘
- 项头表对应于
FP
树的每一项,挖掘时需要找到它的条件模式基- 所谓条件模式基是以要挖掘的节点作为叶子节点所对应的
FP
子树
- 所谓条件模式基是以要挖掘的节点作为叶子节点所对应的
- 得到这个
FP
子树后,将子树中每个节点的的计数设置为叶子节点的计数,并删除计数低于支持度的节点
- 项头表对应于
- 利用这个条件模式基,就可以递归挖掘得到频繁项集了
- 首先要从项头表的底部项依次向上挖掘
示例:
- 从最底下的
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的条件模式基如下图右所示
- 最大的频繁项集为频繁 5 项集,为
{A:2, C:2, E:2, B:2, F:2}
- 由于
- 接着挖掘
D
节点,与F
节点不同的是,D
节点有两个叶子节点- 首先得到的
FP
子树如下图左 - 接着将所有的祖先节点计数设置为叶子节点的计数,即变成
{A:2, C:2, E:1, G:1, D:1}
- 此时
E
节点和G
节点由于在条件模式基里面的支持度低于阈值,被删除 - 同时,同时是两个
D
叶子节点的祖先节点的计数被设置为D
叶子结点的计数之和
- 此时
- 最终在去除低支持度节点并不包括叶子节点后
D
的条件模式基为{A:2, C:2}
-
D
对应的最大的频繁项集为频繁 3 项集,频繁三项集为{A:2, C:2, D:2}
- 首先得到的
- 其余结点同理
- 挖掘到结点
A
时,由于它的条件模式基为空,递归终止- 至此我们得到了所有的频繁项集,如果只是要最大的频繁 K 项集,从上面的分析可以看到,最大的频繁项集为 5 项集,包括
{A:2, C:2, E:2, B:2, F:2}
- 至此我们得到了所有的频繁项集,如果只是要最大的频繁 K 项集,从上面的分析可以看到,最大的频繁项集为 5 项集,包括
4. 算法伪代码
- Input:
- D, a transaction database
- min_sup, the minimum support count threshold
- Output:
- The complete set of frequent patterns
- Method
总结
FP-growth
算法的优点是它不需要生成候选项集,因此可以避免 Apriori
算法中的大量重复计算。另外,由于 FP
树的压缩性质,FP-growth
算法也可以在较小的空间内处理大规模数据集。
FP Tree
算法改进了Apriori
算法的 I/O 瓶颈,巧妙的利用了树结构。利用内存数据结构以空间换时间是常用的提高算法运行时间瓶颈的办法。
在实践中,FP Tree
算法是可以用于生产环境的关联算法,而 Apriori
算法则做为先驱,起着关联算法指明灯的作用。除了 FP Tree
,像 GSP
,CBA
之类的算法都是 Apriori
派系的
本文部分内容参考自:FP Tree算法原理总结
本文部分内容参考自:BUPT 物联网信息处理技术——张海涛老师