从retail.dat文件中读取大量的数据,其中每一行代表一条交易记录。
①第一次扫描数据库,得到频繁1项集L1。
②将L1按照支持度递减的顺序进行排列,同时构造链表的头部表。
③第二次扫描数据库,建立FPTree。
④从FPTree的头表HashL1开始,按照每个频繁项的连接遍历FPTree
⑤遍历单个频繁项的链表找到所有前缀路径def PrePath,得到条件模式库ConPatBase
⑥每一次得到条件模式库之前,将符合条件的频繁项集加入到结果列表result中
⑦对于得到的每一个频繁模式库,建立条件FPTree,只要头表head不为空,就递归挖掘条件FPTree
最后挖掘所有的频繁项集保存在result列表中。结果输出包括所有的频繁项集和相应频率。源码如下:
import time
start=time.time()
class TreeNode:# FPTree类
def __init__(self, key, value, parent):#构造方法
self.key = key # 结点key
self.value = value # 结点的value
self.next = None # 连接key相同的项
self.parent = parent # 指向父结点
self.child = {} # 保存子结点
def addValue(self, value):
self.value += value
#构建FPTree
def FPTree(dataset,flag):
HashC1 = {}
HashL1={}
for trans in dataset:#每一项在记录中出现的次数,保存为value
for item in trans:
HashC1[item] = HashC1.get(item, 0) + dataset[trans]#加上原有的value
for key,value in HashC1.items():
if value>= flag:
# HashL1.update({key:value})
HashL1[key]=value #将其加入到HashL1中
L1 = set(HashL1.keys())
if len(L1) == 0:
return None#如果Lk为空,则退出
for k in HashL1:
HashL1[k] = [HashL1[k], None] #初始化链表头结点
node = TreeNode("root", 1, None) #创建树的根结点
Node=node #保存树根结点
for tranSet,count in dataset.items():
temp = {}#临时空字典
for item in tranSet:
if item in L1:#找出每条交易记录中在L1中的项
temp[item] = HashL1[item][0]
if len(temp) >0:#该条交易记录经过剔除且不为空,就按支持度降序排列并插入FPtree中
order = [] # 建立空列表,保存每条交易记录剔除后降序排列的临时结果
for n in sorted(temp.items(), key=lambda value: value[1], reverse=True):
order.append(n[0])
for n in order:
node = AddTree(n, node, HashL1, count)
node = Node
return HashL1 #返回所有链表头部的字典集合
def AddTree(n, node, HashL1, value):
if n in node.child:#检查order中的第一项是否存在子结点中
node.child[n].addValue(value)
else: #若不存在
node.child[n] = TreeNode(n, value, node)#创建一个新TreeNode
if HashL1[n][1] == None:#如果该结点的下一结点为空,则加入
HashL1[n][1] = node.child[n]
else:
AddNode(HashL1[n][1], node.child[n])#链表的当前结点和要插入的新结点
return node.child[n]
def AddNode(CurrentNode, NewNode):
while (CurrentNode.next != None): # 找到链表的最后一个结点
CurrentNode = CurrentNode.next
CurrentNode.next = NewNode # 将新结点插入链表末尾
# 条件模式基
def Traverse(CurrentNode, temp): ##从当前结点递归往上查找整棵树,也包括了当前结点
if CurrentNode.parent != None:#初始根结点的父结点为None
temp.append(CurrentNode.key)
Traverse(CurrentNode.parent, temp)
def PrePath(TreeNode):
ConPatBase = {} # 保存条件模式库
while TreeNode != None:
temp = []
Traverse(TreeNode, temp) # 寻找从该结点往上的所有结点的key
if len(temp) >= 1:#因为temp列表中也包含当前结点故需从第二个元素开始截取
ConPatBase[frozenset(temp[1:])] = TreeNode.value # 将当前结点的value赋值给前缀路径的value
TreeNode = TreeNode.next # 继续沿着链表寻找下一个
return ConPatBase
# 递归寻找频繁项集
def FPgrowth(HashL1,flag,FreqSet,result):
L1 = {}
for key,value in sorted(HashL1.items(), key=lambda value:value[1][0],reverse=False):
L1[key]=value[0] # 保存按value从小到大排列的L1
for n,value in L1.items(): #从头指针表的底端开始,遍历L1
newFreqSet = FreqSet.copy()
newFreqSet[n]=L1[n]
result.append(newFreqSet)#将符号条件频繁项集加入到结果列表中
ConPatBase = PrePath(HashL1[n][1])#遍历key为n的结点对应的链表中的结点对应的前缀路径
Head = FPTree(ConPatBase, flag)#递归创建条件FPTree
if Head != None: #则递归挖掘条件FPTree
FPgrowth( Head, flag, newFreqSet, result)
# minsup=float(input("请输入最小支持度:"))
minsup=0.005
datalist = []#保存数据
tranCount = 0
for t in open('retail.dat').readlines(): # 返回分割后的字符串列表
line = t.split()
tranCount += 1 # 记录交易的总数
datalist.append(list(map(int, line)))
flag=minsup*tranCount
dataset = {}
#将数据列表转为带有value且为1的字典
for trans in datalist:
dataset[frozenset(trans)] = dataset.get(frozenset(trans), 0) + 1
HashL1 = FPTree(dataset, flag)
result=[] #创建空列表,保存结果
# FreqSet=set()#创建空集合
FreqSet={}
FPgrowth(HashL1, flag, FreqSet, result)
num=0
for itemset in result:
num+=1
print(itemset)
print("一共有%d个频繁项"%num)
end=time.time()
print('Running time: %s Seconds'%(end-start))#程序开始到结束的时间