1 算法流程:
(1)构建FP树
(2)从FP树种挖掘频繁项集
1.1 构建FP树
(1)创建FP树的数据结构
因为FP树比较复杂,所以需要创建一个了类来存储每个节点。
(2)构建FP树
思想:遍历数据集中每个元素,获得每个元素出现的次数,然后根据元素出现的频率,去掉不满足最小支持度的元素项。获得过滤后的频繁项集,然后开始构建FP树。构建BP树的过程就是向树中添加频繁项集的过程,这就需要第二次遍历数据集,遍历数据集中元素时,这是只考虑频繁项集,对每个频繁项根据支持度递减的次序进行排序,然后使用排序后的频繁项集进行对树的填充,填充过程为:首先建一个空树,当遍历第一组频繁项集时,将所有项集填入树中,作为树的子节点(添的时候从上到下依次添入,比如下图中第一步add{z,r}),然后,再填入下一组频繁项集时,对每个频繁项有:遍历树中的每个元素,从上到下,从左到右,如果该频繁项已存在树的子节点中,只需将该子节点的频繁项数加1即可,如果该频繁项不存在树的子节点中,就将该频繁项添加到树中,作为新的子节点,接下来添加频繁项组的过程跟上述一样,直到将所有频繁项都添加到FP树中。
下图就是五步添加频繁项到树中的例子:
实现:
def createTree(dataSet, minSup=1): #create FP-tree from dataset but don't mine
headerTable = {} #建FP树都是从空集开始
#go over dataSet twice
for trans in dataSet:#遍历一遍扫描数据集并统计每个元素项出现的频度
for item in trans:
headerTable[item] = headerTable.get(item, 0) + dataSet[trans]
for k in headerTable.keys(): #移除不满足最小支持度的元素,获得频繁项集
if headerTable[k] < minSup:
del(headerTable[k])
freqItemSet = set(headerTable.keys())
#print 'freqItemSet: ',freqItemSet
if len(freqItemSet) == 0: return None, None #如果频繁项集为空,则退出
for k in headerTable: #扩展头指针表,第一个元素保存计数,第二个元素指向第一个元素项
headerTable[k] = [headerTable[k], None] #reformat headerTable to use Node link
#print 'headerTable: ',headerTable
retTree = treeNode('Null Set', 1, None) #开始构建FP树
for tranSet, count in dataSet.items(): #第二次遍历数据集
localD = {}
#对每条记录中属于频繁项集的各个子项赋予其支持度,用于排序,
# 这里只考虑频繁项集,不是频繁项集的子项去掉
for item in tranSet:
if item in freqItemSet:
localD[item] = headerTable[item][0]
if len(localD) > 0:
#按支持度递减的次序排列子项,只保留子项,不显示支持度
orderedItems = [v[0] for v in sorted(localD.items(), key=lambda p: p[1], reverse=True)]
#使用排序后的频繁项集对树进行填充
updateTree(orderedItems, retTree, headerTable, count)#populate tree with ordered freq itemset
return retTree, headerTable #return tree and header table
def updateTree(items, inTree, headerTable, count):
#每次循环都只测试第一个元素项是否作在原来的树中,以下程序都只是针对第一个元素的
#因为每次第一个元素处理完之后,都调用后面的updateHeader(去除第一个元素函数),
# 所以每次循环相当于遍历items中的每个元素
if items[0] in inTree.children:
inTree.children[items[0]].inc(count) #如果是,该元素数量+1
else: #创建树的新节点,创建的顺序为从上到下,从左到右
inTree.children[items[0]] = treeNode(items[0], count, inTree) #将该元素添加到原来的树中
if headerTable[items[0]][1] == None: #如果添加的元素的没有指向它的元素,
headerTable[items[0]][1] = inTree.children[items[0]] #便将树中的元素存到指向它元素的位置
else:#去掉第一个元素
updateHeader(headerTable[items[0]][1], inTree.children[items[0]])
if len(items) > 1:#迭代
updateTree(items[1::], inTree.children[items[0]], headerTable, count)
1.2 从FP树种挖掘频繁项集
步骤:(1)从FP树中获取条件模式基
(2)利用条件模式基,构建一个条件FP树
(3)迭代(1),(2)步骤,直到树中包含一个元素项为止。
条件模式基:所查元素项为结尾的路径集,(比如:上图中元素s的条件模式基为:{z,x,y}2,{x},1)
创建条件FP树:因为需要对每个频繁项都要挖掘频繁项集,所以对每个频繁项都要创建条件FP树。比如:
虽然s与r属于频繁项,可是{s,t}:2与{r,t}:1不频繁,所以需要去掉。
实现:
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)
#print 'finalFrequent Item: ',newFreqSet #append to set
#将频繁项存储到freqItemList集合中
freqItemList.append(newFreqSet)
#获取该频繁项集的条件模式基
condPattBases = findPrefixPath(basePat, headerTable[basePat][1])
myCondTree, myHead = createTree(condPattBases, minSup)
if myHead != None: #3. mine cond. FP-tree
print 'conditional tree for: ',newFreqSet
myCondTree.disp(1)
mineTree(myCondTree, myHead, minSup, newFreqSet, freqItemList)