关联规则--FpGrowth算法思想及编程实现
构建FpTree
FpTree线索的构造
挖掘关联规则
python代码实现
本文为博主原创文章,转载请注明出处,并附上原文链接。
原文链接:https://blog.csdn.net/qq_39872846/article/details/106042796
FpGrowth算法,全称:Frequent Pattern Growth—-频繁模式增长,该算法是Apriori算法的改进版本(若是不会这个算法或是有点遗忘了,可以移步到我的这篇博客大白话解析Apriori算法python实现(含源代码详解)),我们知道Apriori算法为了产生频繁模式项集,需要对数据库多次扫描,当数据库内容太大,那么算法运行的时间是难以忍受的,因此有人提出了FpGrowth算法,只须扫描数据库两次即可求出频繁项集,大大的缩减了扫描数据库的时间,下面我会尽量用简单易懂的语言描述这个算法所需要的概念及算法思想,希望对读者有帮助!
构建FpTree
(以下文章中所用到的概念在上一篇文章中已经详细解释过了,这里不再赘述,如果对概念有疑问,请移步这篇文章大白话解析Apriori算法python实现(含源代码详解))
FpGrowth算法最经典的思想就是构建一颗树来压缩大量数据记录,如何把多条数据记录压缩到一颗树中呢?用一个例子就可以清晰表达出这个思想。
我们以下面的数据记录为例:
(假设某超市有6种商品,以下是5个顾客的购买情况,我们依旧不关心购买数量,只关心购买种类)
顾客ID
购买种类(Item)
T1
牛奶,面包
T2
面包, 尿布, 啤酒, 鸡蛋
T3
牛奶, 尿布, 啤酒, 可乐
T4
面包 ,牛奶, 尿布, 啤酒
T5
面包, 牛奶, 尿布, 可乐
为了方便程序实现,把这些商品种类替换为字母表示:
牛奶 --> a
面包 --> b
尿布 --> c
啤酒 --> d
可乐 --> e
鸡蛋 --> f
替换后数据记录如下:
顾客ID
购买种类(Item)
T1
a, b
T2
b, c, d, f
T3
a, c, d, e
T4
b, a, c, d
T5
b, a, c, e
【注意】:为了方便程序实现简化代码,我依旧只使用支持度来判断。
对数据库进行第一次扫描,找出所给数据记录中商品的种类,并且对每一种商品出现的次数进行计数,即可得出第一次扫描结果,结果如下:
(这里有个细节,我们求出每种商品出现的次数后,需要按照 出现次数 的大小,由大到小排列,如果出现次数相同,则先后顺序无所谓)
这个时候,就要用到支持度的概念了,我们知道,如果某一种商品组合(这个组合,可以是1个,或者2个,甚至3个以上的不同种类商品的组合),在整条数据库中出现的次数太少,那我就认为他们没有关联, 这个道理很显然。就是对应与Apriori两个定理之一,非频繁项集的超集一定不是频繁项集。
所以,这里我设置最小支持度为3,只要支持度大于等于3,我就认为这个商品组合是频繁项集。
因此,对于上表,去除不符合条件的项集 e 和 f,结果如下:
第二次扫描数据库,开始创建FpTree, 初始时,先创建一个根节点,记为null。
首先对于每一条数据记录,先对里面的商品种类按照 “某种顺序” 排序,(这个某种顺序是,在第一次扫描数据库后,按照其商品出现次数,由大到小排列后,其对应的商品种类顺序。这个例子有点巧合,按照各个商品出现次数由大到小排序后,商品种类的顺序恰好是字母顺序 abcdef ,在真实的数据记录中,不一定是这样。比如,现在有一个新的数据记录,进行统计后,发现,a出现2次,b出现5次,c出现10次,d出现1次,e出现15次,f出现6次,那么,按照出现次数由大到小排序后,这个 “某种顺序” ,就是 ecfbad ,每条数据记录都要按照这个奇怪的顺序排列,不再是按照字母表顺序了 )。
现在对于第一条已经排好序的记录,就是(a,b)这条记录,先创建一个节点,命名为a,将其插入根节点null下,并且在这个节点内,设置一个count变量,令count=1,接着在创建一个节点,命名为b,将其插入节点a下,同样的,在节点b内,令它的count=1,至此,第一条记录扫描完成,形成的树见下图:
对于二条已经排好序的记录,就是(b, c, d, f),我们要先去除那些不是频繁项集的字母,也就是f,f的支持度为1,比最小支持度小。过滤掉这些非频繁项集后,第二条记录变为了(b, c, d)。现在开始插入节点,从根节点开始看,由于根节点的孩子中没有b这个孩子,那么现在创建一个节点b,把它插入根节点下,令这个b节点的count=1。在创建一个c节点,插入刚才的b节点下,令c节点count=1。在创建一个d节点,将其插入刚才的c节点下,令d节点的count=1。至此第二条记录扫描完毕,此时FpTree的结构如下图:
对于第三条已经排好序的记录,就是(a, c, d, e)同样的,我们要过滤到非频繁项集,所以第三条记录变为了(a, c, d)。现在开始插入节点,从根节点开始看,发现根节点null的孩子中有a节点,那么我们就不创建新节点了,我们将这个的a节点的count + 1,即现在a节点的count=2。接着看a节点的孩子中有没有c节点,发现找不到,则创建一个c节点,令count=1,将其插入a节点下。最后,创建一个d节点,令count=1,将其插入刚刚创建的c节点下。至此,第三条记录扫描完毕,现在的FpTree形状如下:
对于第四条已经排好序的记录,就是(a, b, c, d),过滤掉非频繁项集,第四条记录变为了(a, b, c, d)。现在开始插入节点,依旧从根节点开始看,发现根节点null的孩子中有a节点,则不创建新节点了,我们将这个的a节点的count + 1,即现在a节点的count=3。然后看a节点的孩子中有没有b节点,发现有b节点,那么不用创建了,直接对这个b节点的count + 1即可,现在这个b节点count=2。接着看这个b节点的孩子中有没有c,我们发现找不到c,则创建一个c节点,令count=1,插入刚才的b节点中。最后,在创建一个d节点,令count=1,插入刚才在c节点中。至此,第四条记录扫描完毕,现在的FpTree形状如下: