【Python机器学习】FP-growth算法——从一棵FP树中挖掘频繁项集

有了FP树之后,就可以抽取频繁项集了。这里的思路与Apriori算法大致类似,首先从单元素项集合开始,然后在此基础上逐步构建更大的集合。这里将利用FP树来做实现上述过程,不再需要原始数据集。

从FP树中抽取频繁项集的三个基本步骤如下:

1、从FP树中获得条件模式基;

2、利用条件模式基,构建一个条件FP树;

3、迭代重复步骤1、2,直到树包含一个元素项为止。

抽取条件模式基

首先从已经保存在头指针表中的单个频繁元素项开始。对于每一个元素项,获得其对应的条件模式基。条件模式基是以所查找元素项为结尾的路径集合。每一条路径其实都是一条前缀路径。简而言之,一条前缀路径是介于所查找元素项与树根节点之间的所有内容。

以之前的数据为例,符号r的前缀路径是{x,s}、{z,x,y}和{z}。每一条前缀路径都与一个计数值关联。该计数值等于起始元素项的计数值,该计数值给了每条路径上r的数目。下表列出了每个频繁项的所有前缀路径:

前缀路径将被用于构建条件FP树。为了获取这些前缀路径,可以对树进行穷举式搜索,直到获得想要的频繁项集为止,或者使用一个更有效的方法来加速搜索过程。可以利用先前创建的头指针表来得到一种更有效的方法。头指针表包含相同类型元素链表的起始指针。一旦到达了每一个元素项,就可以上溯这棵树直到根节点为止。

下面是前缀路径发现的代码:

def ascendTree(leafNode,prefixPath):
    #迭代整棵树
    if leafNode.parent != None:
        prefixPath.append(leafNode.name)
        ascendTree(leafNode.parent,prefixPath)
def findPrefixPath(basePat,treeNode):
    condPats={}
    while treeNode != None:
        prefixPath=[]
        ascendTree(treeNode,prefixPath)
        if len(prefixPath)>1:
            condPats[frozenset(prefixPath[1:])]=treeNode.count
        treeNode = treeNode.nodeLink
    return condPats

上述程序中的代码用于为给定元素项生成一个条件模式基,这通过访问树中所有包含给定元素项的节点来完成。当创建树的时候,使用头指针表来指向该类型的第一个元素项,该元素项也会链接到其后续元素项。函数findPrefixPath()遍历链表直到到达结尾。每遇到一个元素项都会调用ascendTree()来上溯FP树,并收集所有遇到的元素项的名称。该列表返回之后添加到条件模式基字典condPats中。

使用之前构建的树来看一下实际的运行效果:

print(findPrefixPath('x',myHeaderTab['x'][1]))
print(findPrefixPath('z',myHeaderTab['z'][1]))
print(findPrefixPath('r',myHeaderTab['r'][1]))

可以看到,运行结果和之前表中的结果是一致的。

有了条件模式基之后,就可以创建条件FP树

创建条件FP树

对于每一个频繁项,都要创建一棵条件FP树。我们会为z、x以及其他频繁项构建条件树。可以使用刚才发现的条件模式基作为输入数据,并通过相同的建树代码来构建这些树。然后,我们会递归地发现频繁项、发现条件模式基,以及发现另外的条件树。举例来说,假定为频繁项t创建一个条件FP树,然后对{t,y}、{t,x}、……重复该过程。元素项t的条件FP树的构建过程如下所示:

在图中,可以注意到元素项s以及r是条件模式基的一部分,但是它们并不属于条件FP树。原因是单独来看它们都是频繁项,但是在t的条件树中,它们却不是频繁的,也就是说,{t,r}和{t,s}是不频繁的。

接下来,对集合{t,z},{t,x}以及{t,y}来挖掘对应的条件树。这会产生更复杂的频繁项集。该过程重复进行,直到条件树中没有元素为止,然后就可以停止了。具体代码实现:

def mineTree(inTree,headerTable,minSup,preFix,freqItemList):
    #从头指针表的底端开始
    bigL=[v[0] for v in sorted(headerTable.items(),key=lambda p: p[1])]
    for basePat in bigL:
        newFreqSet=preFix.copy()
        newFreqSet.add(basePat)
        freqItemList.append(newFreqSet)
        condPattBases=findPrefixPath(basePat,headerTable[basePat][1])
        #从条件模式基来构建条件FP树
        myCondTree,myHead=createTree(condPattBases,minSup)
        #挖掘条件FP树
        if myHead !=None:
            mineTree(myCondTree,myHead,minSup,newFreqSet,freqItemList)

创建条件树、前缀路径以及条件基的过程听起来比较复杂,但是代码实现起来相对简单。程序首先对头指针表中的元素项按照其出现的频率进行排序(从小到大)。然后,将每一个频繁项添加到频繁项集列表freqItemList中。接下来,递归调用程序findPrefixPath()函数来创建条件基。该条件基被当成一个新数据集输送给createTree()函数。这里为函数createTree()添加了足够的灵活性,以确保它可以被重用与构建条件树。最后,如果树中有元素项的话,递归调用mineTree()函数。

下面看运行效果:

建立一个空列表来存储所有的频繁项集,然后运行mineTree(),并显示出所有的条件树:

freqItems=[]
mineTree(myFPtree,myHeaderTab,3,set([]),freqItems)

为了得到上面的输出结果,在mineTree()函数中添加了两行:

print('conditional tree for: ', newFreqSet)
myCondTree.disp(1)

下面检查返回的项集与条件树是否匹配:

print(freqItems)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值