1. 程式人生 > >第12章:使用FP-growth演算法高效發現頻繁項集

第12章:使用FP-growth演算法高效發現頻繁項集

原理:通過構建FP樹,在FP樹中發現頻繁項集。如下圖所示。

       由圖可知FP樹包含頭指標,父節點,節點的名字,節點的值,節點連結值(虛線),節點的孩子節點,因此構建類定義樹結構,如下所示:

class treeNode:
    def __init__(self,nameValue,numOccur,parentNode):
        self.name=nameValue
        self.count=numOccur
        self.nodeLink=None #用於連結相同元素
        self.parent=parentNode
        self.children={}
    def inc(self,numOccur):
        self.count+=numOccur
    def disp(self,ind=1):
        print(' ' * ind, self.name, ' ', self.count)
        for child in self.children.values():
            #self.children.values()是相當於treeNode類
            #對不同層級的treeNode輸出不同空格
            child.disp(ind+1)

構建FP樹

       第一次遍歷資料集先獲得每個元素出現的頻率,去掉不滿足最小支援度的元素;然後構建FP樹,讀入每個項集,並將其新增到一條已存在的路徑中,如果該路徑不存在,則建立一條路徑。在新增每個項集時,要先對項集中的元素按照頻率由大到小排序。下圖展示了將非頻繁項移除並重排序後的事務資料集。

對事務記錄過濾和排序後就可以建立FP樹了,從空集開始,向其中不斷新增頻繁項集。如下圖所示。

程式碼:

def createTree(dataSet,minSup=1):
    headerTable={}
    for trans in dataSet:
        for item in trans:
            #headerTable.get(item,0)返回指定鍵的值,沒有返回0
            headerTable[item]=headerTable.get(item,0)+dataSet[trans]
    #移除不滿足最小支援度的項

    for k in list(headerTable.keys()):
        if headerTable[k]<minSup:
            del(headerTable[k])
    freqItemSet=set(headerTable.keys())
    #如果沒有元素項滿足要求則退出
    if(len(freqItemSet)==0):
        return None,None
    #重新調整headerTable以使用Node Link
    for k in headerTable:
        headerTable[k]=[headerTable[k],None]
    retTree=treeNode('Null Set',1,None)

    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)]
            #使用排序後的頻率項對樹填充
            #pdb.set_trace()
            updateTree(orderedItems,retTree,headerTable,count)
    return retTree,headerTable

def updateTree(items,inTree,headerTable,count):
    if items[0] in inTree.children:
        inTree.children[items[0]].inc(count)
    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函式
        updateTree(items[1::], inTree.children[items[0]], headerTable, count)

def updateHeader(nodeToTest,targetNode):
    while(nodeToTest.nodeLink!=None):
        nodeToTest=nodeToTest.nodeLink
    nodeToTest.nodeLink=targetNode