FP增长算法(FP Growth Algorithm)

0 问题描述

给定事务集 TS (Transaction Set), 项全集 IUS (Item Universal Set)以及支持度阈值 s0 , 求所有支持度大于 s0 的项集, 即频繁项集.

TS 给定以后, 任意项集的支持度 s 和它在事务集中出现的频数 f 是等价的:

f=s|TS|
因此为了方便叙述, 我使用”支持度”同时代表”项在事务集中出现的频数”以及”项在事务集中出现的频数与事务集大小之比”, 具体代表哪个含义, 可以根据上下文轻易区分.

1 记号

我们知道FP树是一棵前缀树, 树上每个节点关联一个项. 设 iIUS 是一个项, fp 表示一棵FP树, 为方便叙述, 我引进以下符号:

  • nodesi : FP树上与项 i 相关联的节点的集合, 注意这样的节点可能有多个, 因此 nodei 表示一类节点而不是FP树上特定的某个节点
  • fp . root : fp 的根节点, 在前缀树的通常实现方式里, 根节点不关联任何项
  • fp . headers : FP增长算法需要遍历一棵FP树上的所有关联到同一个项的节点, 因此我们使用一个链表将 nodesi 中的元素串联在一起.这样, 每个 nodesi 关联一个链表, 所有这些链表的头存储在 fp . headers

我们说项是有大小的, 项的大小等于其支持度,, 因此项集是可以排序的. 对于已经排序的项集, 我们说”项集的最后一个元素”是指”项集中最小的项, 即项集中支持度最小的项.

2 从事务集构造一颗FP树

我们假设用于构造FP树的事务集为 ts , 项全集为 ius . FP增长算法的第一步是从 ts , ius 构造一颗FP树 fp , 然后删掉树上所有支持度小于 s0 的单项. 这个过程同时会构造出 fp . heders .

首先, 在算法开始的时候, ius 中项的大小是未知的. 为了明确每个项的大小, 我们扫描事务集 ts , 记录每个单项 i 的支持度 si . 这个过程结束后, 我们就可以将每个事务的项集按照项的大小降序排序.

然后, 我们开始更新项全集 ius , 删除 ius 中所有支持度小于 s0 的项, 我们将更新后的项全集记为 ius . 我们将利用 ius 构造 fp .

最后, 为了尽可能地压缩前缀树, 我们让支持度最高的节点出现在树的根部, 支持度最低的节点则出现在树梢. 具体地, 对于每个 tts , 我们顺序扫描其项集, 并依次将扫描到的每个项 iius 插入到 fp 上. 在扫描过程中我们始终忽略不属于 ius 中的项. 注意, 对于每个新插入的节点 node , 我们都要相应地更新 fp . headers 表.

我们构造的FP树符合以下两个性质:

  • 性质1: 树上每个节点对应的单项都是频繁的.
    这是显然的, 因为不频繁的单项不会出现在 ius 中, 而不出现在 ius 中的项不会被插入到 fp 上.

  • 性质2: 对于从根到树上任意节点的路径, 路径上不会有相同节点, 按照从根开始的方向,各个节点的支持度是单调不增的.
    由于从根到任意节点的路径都来自于一个事务项集或其子集, 所以绝不会有相同的节点.另一方面, 对于一个特定的事务项集, 其支持度大的项总是被我们首先扫描并插入, 并且后插入的项总是连接到新插入的项, 因此路径上支持度是单调不增的.

由于性质2, 我们可以把FP树上从根开始的任意路径视为一个集合, 并由此得到额外的结论:

  • 性质3: 对于从根到任意节点的路径, 路径的任意子集的支持度等与子集中最后一个项的支持度.

3 从简单的FP树生成频繁项集

在以下两种情况下, 算法无需递归, 直接返回结果:

  1. fp 为空
  2. fp 只有一个树叶

对于情况1, 直接返回空集.

情况2稍微复杂一些, fp 只有一个树叶, 此时树退化为一条从树根到其唯一树叶的链表.链表上的所有元素构成一个集合 S , 由FP树的性质3和性质1可知, S 的任意子集都是频繁项集, 因此, 算法返回 S 的幂集.

FP增长过程是一个递归过程, 因此以上两种情况被视为递归地基本解.

4 从复杂的FP树生成频繁项集

在最一般的情况下, fp 有多个分支.此时, 算法为每个(频繁)单项 i 生成一颗FP树, 称为该频繁单项的条件FP树, 记为 CFPi , 然后递归求解每棵 CFPi 上的频繁项集, 最后合并所有返回结果, 生成并返回 fp 上的所有频繁项集.

这种情况具体分三步执行.

第一步: 生成条件样式基

首先, 对于 fp 上的每个(频繁)单项 i , 我们找到 nodesi , 遍历 nodesi 中的每个节点 node , 并沿其父指针上溯, 生成(复制)一条前缀路径(注意,所有前缀路经均不包含 node 本身), 将这条复制出的路径存入该单项的条件样式基 CPBi (Conditional Pattern Base of i )中, 同时, 该路径上每个节点(单项)的支持度减少为该单项的支持度.

第二步: 生成条件事务集

i 的条件样式基 PCBi 生成 i 的事务集 tsi 的规则如下:

  1. PCBi 中的每个前缀路径对应一组事务, 该组中的所有事务具有相同的项集
  2. 每组事务的频繁项集由该组事务对应的前缀路径上的所有节点(对应的项)组成
  3. 每组事务中事务的个数是该组事务对应的前缀路径上支持度最低的节点的支持度

我们可以利用上述规则容易地生成对应每个项的事务集.

第三步: 生成频繁项集

设有项集 X , 且 X CFPi 上的支持度为 s1 , 并且出现在 CFPi 中的事务的集合 A={t1,t2,...,ts1} 的每个事务中.现在向 A 中的每个项集添加项 i 生成新的事务集合 A=t1,t2,...,ts1 , 我们知道 A 必是 FP 上的事务构成的集合.

Y=Xi , 我们有以下两个结论:

  1. tA,Yt
  2. tAti,Yt

第一个结论是显然的.

对于第二个结论, 设 t i 结尾, 并且 tA ,
Yt ,
则必有 (Yi)(ti) .
由于第一步的工作, 我们有这样的事实: CFPi 中的事务是由 FP 上所有以 i 结尾的事务去掉 i 后生成的
所以 (ti) CFPi 上的事务
又因为 (Yi)(ti)(Yi)=X
所以 (ti)A
所以 tA .
这与我们的假设矛盾, 因此结论2也是正确的.

对于 CPFi 中的每个项集 X , 设 X CPFi 中的支持度为 s1 ; 现在向 X 中添加项 i , 并设 X FP 上的支持度为 s2 . 由结论1可以知道 σFP(Y)σCFPi(X) , 由于 Y FP 上以 i 结尾的项集, 结合结论2可以知道, 不存在 FP 上的事务 t , 使得 tAYt . 于是, 我们有 s1=s2 .

这样, 对于 CFPi 上的任意频繁项集 X , Y=Xi FP 上以 i 结尾的频繁项集, 另一方面, 若 Y FP 上以 i 结尾的频繁项集, 则必有 X=Yi , 且 X CFPi 上的频繁项集.

于是我们可以通过在 CFPi 上的所有频繁项集 X 中添加 i , 形成 FP 上所有以 i 结尾的频繁项集 Y=Xi .

这样, 我们就可以构造 FP 上以任意单项 i 结尾的频繁项集, 合并这些项集, 就可以得到 FP 上的所有频繁项集.

参考

  1. https://github.com/integeruser/FP-growth
  2. <数据挖掘导论>

你可能感兴趣的:(信笔涂鸦,数据挖掘)