FP-growth算法基于Apriori构建,但采用了高级的数据结构减少扫描次数,大大加快了算法速度。FP-growth算法只需要对数据库进行两次扫描,而Apriori算法对于每个潜在的频繁项集都会扫描数据集判定给定模式是否频繁,因此FP-growth算法的速度要比Apriori算法快。
FP-growth算法发现频繁项集的基本过程如下:
1、构建FP树
2、从FP树中挖掘频繁项集
FP-growth算法:
优点:一般要快于Apriori。
缺点:实现比较困难,在某些数据集上性能会下降。
适用数据类型:离散型数据。
一、FP树:用于编码数据集的有效方式
FP-growth算法将数据存储在一种称为FP树的紧凑数据结构中。FP代表频繁模式(Frequent Pattern)。一棵FP树看上去与计算机科学中的其他树结构类似,但是它通过链接(link)来连接相似元素,被连起来的元素项可以看成一个链表。图5给出了FP树的一个例子。
与搜索树不同的是,一个元素项可以在一棵FP树种出现多次。FP树辉存储项集的出现频率,而每个项集会以路径的方式存储在数中。存在相似元素的集合会共享树的一部分。只有当集合之间完全不同时,树才会分叉。 树节点上给出集合中的单个元素及其在序列中的出现次数,路径会给出该序列的出现次数。
相似项之间的链接称为节点链接(node link),用于快速发现相似项的位置。
举例说明,下表用来产生图5的FP树:
对FP树的解读:
图5中,元素项z出现了5次,集合{r, z}出现了1次。于是可以得出结论:z一定是自己本身或者和其他符号一起出现了4次。集合{t, s, y, x, z}出现了2次,集合{t, r, y, x, z}出现了1次,z本身单独出现1次。就像这样,FP树的解读方式是读取某个节点开始到根节点的路径。路径上的元素构成一个频繁项集,开始节点的值表示这个项集的支持度。根据图5,我们可以快速读出项集{z}的支持度为5、项集{t, s, y, x, z}的支持度为2、项集{r, y, x, z}的支持度为1、项集{r, s, x}的支持度为1。FP树中会多次出现相同的元素项,也是因为同一个元素项会存在于多条路径,构成多个频繁项集。但是频繁项集的共享路径是会合并的,如图中的{t, s, y, x, z}和{t, r, y, x, z}
和之前一样,我们取一个最小阈值,出现次数低于最小阈值的元素项将被直接忽略。图5中将最小支持度设为3,所以q和p没有在FP中出现。
FP-growth算法的工作流程如下。首先构建FP树,然后利用它来挖掘频繁项集。为构建FP树,需要对原始数据集扫描两遍。第一遍对所有元素项的出现次数进行计数。数据库的第一遍扫描用来统计出现的频率,而第二遍扫描中只考虑那些频繁元素。
二、构建FP树
1.创建FP树的数据结构
由于树节点的结构比较复杂,我们使用一个类表示。创建文件fpGrowth.py并加入下列代码:
#FP树的类定义,将树的节点定义为一个类
class treeNode:
def __init__(self,nameValue,numOccur,parentNode):
self.name = nameValue
self.count = numOccur
#nodeLink变量用于链接相似项
self.nodeLink = None
self.parent = parentNode
#子树的存储结构为字典
self.children = {}
#节点对应元素计数函数
def inc(self,numOccur):
self.count += numOccur
#对当前树结构以文本形式进行输出函数
def disp(self,ind=1):
#输出当前节点的名字即计数,print()函数自动换行
print(' '*ind,self.name,' ',self.count)
#子树递归输出
for child in self.children.values():
child.disp(ind+2)
每个树节点由五个数据项组成:
name:节点元素名称,在构造时初始化为给定值
count:出现次数,在构造时初始化为给定值
nodeLink:指向下一个相似节点的指针,默认为None
parent:指向父节点的指针,在构造时初始化为给定值
children:指向子节点的字典,以子节点的元素名称为键,指向子节点的指针为值,初始化为空字典
成员函数:
inc():增加节点的出现次数值
disp():输出节点和子节点的FP树结构
2.构建FP树
头指针表
FP-growth算法还需要一个称为头指针表的数据结构,其实很简单,就是用来记录各个元素项的总出现次数的数组,再附带一个指针指向FP树中该元素项的第一个节点。这样每个元素项都构成一条单链表。图示说明:
这里使用Python字典作为数据结构,来保存头指针表。以元素项名称为键,保存出现的总次数和一个指向第一个相似元素项的指针。
第一次遍历数据集会获得每个元素项的出现频率,去掉不满足最小支持度的元素项,生成这个头指针表。
元素项排序
上文提到过,FP树会合并相同的频繁项集(或相同的部分)。因此为判断两个项集的相似程度需要对项集中的元素进行排序(不过原因也不仅如此,还有其它好处)。排序基于元素项的绝对出现频率(总的出现次数)来进行。在第二次遍历数据集时,会读入每个项集(读取),去掉不满足最小支持度的元素项(过滤),然后对元素进行排序(重排序)。
对示例数据集进行过滤和重排序的结果如下: