Python实现FP-growth算法

**

1、创建FP树节点

**

#创建FP树节点
class treeNode():
    def __init__(self,nodeName,parentNode,count):
        self.nodeName=nodeName
        self.parentNode=parentNode
        self.childNodes={} #有很多个
        self.nextLink=None
        self.count=count
    def increte(self,count):
        self.count+=count
    def display(self,level=1):
        print(level*"-",self.nodeName,self.count)
        for child in self.childNodes.values():
            child.display(level+1)
 #测试
rootNode=treeNode("fruit",None,9)
rootNode.childNodes["apple"]=treeNode("apple",None,13)
rootNode.childNodes["pear"]=treeNode("pear",None,21)
rootNode.display()

输出
在这里插入图片描述
**

2、根据原始数据集创建FP树

**
**

输入:数据集、最小支持度

输出:fp树、头指针

1.遍历数据集,统计各元素项出现次数,创建头指针表

2.移除头指针表中不满足最小值尺度的元素项

3.第二次遍历数据集,创建FP树,对每个数据集中的项集:

3.1初始化空fp树
3.2对每个项集进行过滤和重排序
3.3使用这个项集更新Fp树,从fp树的根节点开始:
3.3.1如果当前项集的第一个元素存在于fp树当前节点的子节点中,则更新这个子节点的计数值
3.3.2否则,创建新的子节点,更新头指针表
3.3.3对当前的其余元素项和当前元素项的对应子节点递归3.3的过程

**

'''
功能:将 新的相似节点添加  头指针对应元素的链表结构的最后
参数说明:
    nodeToUpdate:头指针中对应的节点,将   targetNode 添加到它的链表的最后一个元素  nodeLink上
    targetNode:要添加的相似节点
'''
def updateHeader(updateNode,targetNode):
    #print(updateNode.nextLink)
    while updateNode.nextLink!=None:
        updateNode=updateNode.nextLink
    updateNode.nextLink=targetNode


'''
功能:更新fp树
参数说明:
    orderItems:对应一条事务经过筛选后的路径,只保留频繁项,并且排好序
    rootTree:要更新的树的根节点
    headerTable:头指针表,以备更新  headerTable结构:{k-1频繁项:[次数,指针]}
    count:这条事务对应项的出现次数
'''
def updateTree(orderItems,rootTree,headerTable,count):
    if orderItems[0] in rootTree.childNodes:
        #有该元素时计数值+1
        rootTree.childNodes[orderItems[0]].increte(count)
    else:
        #2.没有时创建相应的节点,并添加到树中,同时还要更新头指针列表,以指向新的节点
        rootTree.childNodes[orderItems[0]]=treeNode(orderItems[0],rootTree,count)
        #更新头指针表或前一个相似元素项节点的指针指向新节点
        if headerTable[orderItems[0]][1]==None:
            headerTable[orderItems[0]][1]=rootTree.childNodes[orderItems[0]]
        else:  #如果指针已经有一个了,则需要重新更新
            updateHeader(headerTable[orderItems[0]][1],rootTree.childNodes[orderItems[0]])
    #oreredItems如果还有节点,则需继续递归
    if len(orderItems)>1:
        updateTree(orderItems[1::],rootTree.childNodes[orderItems[0]],headerTable,count)



 '''
创建树
    参数说明:
        dataset:原始事务集
            {frozenset({'z'}): 1,
             frozenset({'h', 'j', 'p', 'r', 'z'}): 1,
             frozenset({'s', 't', 'u', 'v', 'w', 'x', 'y', 'z'}): 1,
             frozenset({'n', 'o', 'r', 's', 'x'}): 1,
             frozenset({'p', 'q', 'r', 't', 'x', 'y', 'z'}): 1,
             frozenset({'e', 'm', 'q', 's', 't', 'x', 'y', 'z'}): 1}
        minsup:最小支持度
    返回:Fp树、头指针
        
'''
#创建头指针列表
def craeteHeaderTable(dataSet,minSup=1):
    	headerTable={}  #第一次循环产生结构:{k-1频繁项集:次数}  ->下面再循环headerTable,增加一个指向相似元素项指针  {k-1频繁项集:[次数,指针]
    for transaction in dataSet:
        for item in transaction:
            headerTable[item]=headerTable.get(item,0)+dataSet[transaction]
    #移除不满足最小支持度的元素项
    '''
    原python2中可以,但python3中 字典在遍历时不能进行修改,建议转成列表或集合处理
        for key in headerTable.keys():
            del(headerTable[key]) 
    '''
    for key in list(headerTable.keys()):
        if headerTable[key]<minSup:
            del(headerTable[key])
    return headerTable
def createTree(dataSet,minSup=1):
    #创建fp树
    #第一次遍历数据集,创建头指针表
    headerTable=craeteHeaderTable(dataSet,minSup)
    #存所有的频繁项的集合
    #freqItemSet=set(headerTable.keys())
    #空频繁元素集,返回空
    if len(headerTable)==0:
        return  None,None
    #增加一个数据项,用于存放指向相似元素项指针
    for key in headerTable:
        headerTable[key]=[headerTable[key],None]
    rootTree=treeNode("Null Set",None,1)  #根节点,是一个空元素
    #第二次遍历数据集,对每个事务,创建FP树的一条路径
    for transaction,count in dataSet.items():
        #localID中存的是一条路径(对应一个transcation)
        localID={}
        for transact in transaction:
            if transact in headerTable.keys():
                localID[transact]=headerTable[transact][0]
        if len(localID)>0:
            #对频繁项集进行排序
            oderItems=[v[0] for v in sorted(localID.items(), key=lambda p:p[1], reverse=True)]
            updateTree(oderItems,rootTree,headerTable,count) #更新fp树
    return rootTree,headerTable

**

测试以上的函数

**

#1.定一个函数:加载数据集
def laodSimpleData():
    simpleData=[['r','z','h','j','p'],
               ['z','y','x','w','v','u','t','s'],
                ['z'],
                ['r','x','n','o','s'],
                ['y','r','x','z','q','t','p'],
                ['y','z','x','e','q','s','t','m']
               ]
    return simpleData
#定义一个函数:用于将事务列表转为frozenset,并存为字典,每条记录记值为1
def createInitset(dataSet):
    retDict={}
    for trans in dataSet:
        retDict[frozenset(trans)]=1
    return retDict
dataSet=laodSimpleData()
print(dataSet)

输出
在这里插入图片描述

transactionDict=createInitset(dataSet)
transactionDict

输出
在这里插入图片描述

rootTree,headerTable=createTree(transactionDict)
rootTree.display()

输出
在这里插入图片描述

3、从一颗fp树中挖掘频繁项集

从fp树中抽取频繁项集的三个基本步骤如下:
1.从fp树中获取条件模式基;
2.利用条件模式基,构建一个fp树;
3.迭代重复步骤1步骤2,直接树包括一个元素项为止
'''
为给定元素项生成一个条件模式基(前缀路径),这通过访问树中包含给定元素项的节点的完成
参数说明:
    baseRequenceList:输入的频繁项
    treeNode为当前FP树中对应的第一个节点(可在函数外部通过headerTable[basePat][1]获取)
函数返回值:
    条件模式基condPats,用一个字典表示,{frozenset(前缀路径):计数值}
'''
def findPrefixPath(baseRequenceList,treeNode):
    '''创建路径'''
    condPats={}
    while treeNode!=None:
        prefixPath=[]
        ascendTree(treeNode,prefixPath)
        if len(prefixPath)>1:
            condPats[frozenset(prefixPath[1:])]=treeNode.count
        treeNode=treeNode.nextLink
    return condPats
'''
函数功能:直接修改prefixPath的值,将当前节点leafNode添加到prefixPath的末尾,然后递归添加其父节点。
返回值:prefixPath就是一条从treeNode(包括treeNode)到根节点(不包括根节点)的路径
调用方法:在主函数findPrefixPath()中再取prefixPath[1:],即为treeNode的前缀路径
'''
def ascendTree(leafNode,prefixPath):
    #print(leafNode.nodeName)
    if leafNode.parentNode!=None:
        prefixPath.append(leafNode.nodeName)
        ascendTree(leafNode.parentNode,prefixPath)
 
 #测试 生成条件模式基
print(findPrefixPath('x',headerTable['x'][1]))
print(findPrefixPath('t',headerTable['t'][1]))
print(findPrefixPath('s',headerTable['s'][1]))

输出
在这里插入图片描述

4、创建条件FP树

对于每一个频繁项集,都要创建一颗条件FP树,可以使用刚才发现的条件模式作为输入数据,并通过相同的建树代码来构建这些树
过程说明:比如:t的条件FP树
它的条件模式基为:{frozenset({‘s’, ‘x’, ‘z’}): 2, frozenset({‘z’, ‘x’, ‘r’}): 1}
最小支持度为3
则可以过滤掉 r
在形成条件fp树
z:3 y:3 x:3
'''
用于根据每一个频繁项集basePat,先找到条件模式基,再创建一颗条件fp树
'''
condPatBases=findPrefixPath('t',headerTable["t"][1])
#print(condPatBases)
myCondTree,myHead=createTree(condPatBases,2)
print("根据条件模式基生成的FP树:",myCondTree)
myCondTree.display()
print("这个条件FP树对应的头指针表:",myHead)

输出
在这里插入图片描述

5、递归查找频繁项集

有了fp树和条件FP树,我们就可以在前两步的基础上递归得查找频繁项集
递归过程如下
输入:我们有当前数据集得FP树
1.初始化一个空列表prefix表示前缀
2.初始化一个空列表freqItemList接收生成得频繁项集
3.对headerTable中的每个元素basePat(按计数值与小到大),递归
3.1计basePat+preFix为当前频繁项集newFreqSet
3.2将newFreqSet添加到freqItemList中
3.3将计算newFreqSet的条件FP树(myConditionTree、myHeaderTable)
3.4当条件Fp树不为空时,继续下一步;否则退出递归
3.5myConditionTree、myHeaderTable,以newFreqSet为新的preFix,外加freqItemList,递归这个过程
'''
输入参数:
    inTree和headerTable是由createTree()函数生成的数据集的FP树
    minSup表示最小支持度
    preFix请传入一个空项集(set([])),将在函数中用于保存当前前缀
    fresItemList请传入一个空列表([]),将用来存储生成频繁项集
'''
def mineTree(rootTree,headerTable,minSup,preFix,freqItemList):
    #头指针表中的元素项按照频繁度排序,从小到大
    bigL=[v[0] for v in sorted(headerTable.items(),key=lambda p:str(p[1]))]
    #从底层开始 循环
    for basePat in bigL:
        #加入频繁项集列表
        newFreqSet=preFix.copy()
        newFreqSet.add(basePat)
        freqItemList.append(newFreqSet)
        #递归调用函数来创建条件模式基
        conditionPatternBases=findPrefixPath(basePat,headerTable[basePat][1])
        #构建条件模式Tree,及头指针列表
        myCondTree,myHead=createTree(conditionPatternBases,minSup)
        if myHead!=None:
            #用于测试
            print('conditional tree for:',newFreqSet)
            myCondTree.display()
            mineTree(myCondTree,myHead,minSup,newFreqSet,freqItemList)
          
       #测试
freqItemList=[]
mineTree(rootTree,headerTable,3,set([]),freqItemList)

输出
在这里插入图片描述
#输出频繁项集
freqItemList
输出
在这里插入图片描述

从新闻网站点击流中挖掘新闻报道

从新闻站点击流中挖掘热门新闻报道,这是一个很大的数据集,有将近100万条记录
参考网站: http://fimi.ua.ac.be/data
在原数据集合保存文件kosarak.dat中。该文件的每一行包含某个用户浏览过的新闻报道。新闻报道被编码成整数,我们可以使用Apriori或FP-growth算法挖掘
其中的频繁项集,查看哪些新闻ID被用户大量观看到(最小支持度100000)

kosarak.dat

parsedData=[line.split() for line in open('kosarak.dat').readlines()]
initSet=createInitset(parsedData)
myFPTree,myHeaderTable=createTree(initSet,100000)
myFreqList=[]
mineTree(myFPTree,myHeaderTable,100000,set([]),myFreqList)
myFreqList

输出
在这里插入图片描述

  • 5
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值