**
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)
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
输出