MLiA笔记_fp-growth算法

#-*-coding:utf-8-*-

# 12.1 FP树的类定义
# 类中包含用于存放节点名字的变量和1个计数值
class treeNode:
    def __init__(self,nameValue, numOccur, parentNode):
        self.name = nameValue
        self.count = numOccur
        # nodeLink变量用于链接相似的元素项
        self.nodeLink = None
        # 类中还使用了父变量,来指向当前节点的父节点。通常情况下并不需要这个变量,因为通常是从上往下迭代访问节点的
        self.parent = parentNode
        # 还包含一个空字典变量,用于存放节点的子节点
        self.children = {}

    # inc()方法对count变量增加给定值
    def inc(self, numOccur):
        self.count += numOccur

    # disp()方法用于将树以文本形式显示(对于树的构建不是必要,但对于调试非常有用)
    def disp(self, ind = 1):
        print '' *ind, self.name, '', self.count
        for child in self.children.values():
            child.disp(ind+1)

# 12.3 FP树构建函数
# createTree()使用数据集以及最小支持度作为参数来构建FP树,构建过程会遍历数据集两次
def createTree(dataSet, minSup = 1):
    headerTable = {}
    # 第一次遍历扫描数据集并统计显示每个元素项出现的频度,这些信息被存储在头指针表中
    for trans in dataSet:
        for item in trans:
            headerTable[item] = headerTable.get(item,0) + dataSet[trans]
    # 接下来扫描指针表删掉那些出现次数少于minSup的项
    for k in headerTable.keys():
        if headerTable[k] < minSup:
            del(headerTable[k])
    freqItemSet = set(headerTable.keys())
    # 如果所有项都不频繁,就不需要进行下一步处理
    if len(freqItemSet) == 0:
        return None, None
    # 接下来,对头指针表稍加扩展便可以保存计数值及指向每种类型第一个元素项的指针
    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:
            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()方法
            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:
            # 如果不存在,创建一个新的treeNode并将其作为一个子节点添加到树中。这时,头指针表也要更新指向新的节点
            # 更新头指针表需要调用函数uodateHeader()
            updateHeader(headerTable[items[0]][1],inTree.children[items[0]])
    if len(items)>1:
        # updateTree()完成的最后一件事是不断迭代调用自身,每次调用时会去掉列表中第一个元素
        updateTree(items[1::], inTree.children[items[0]],headerTable, count)

# updateHeader()函数,确保节点链接指向树中该元素项的每一个实例
def updateHeader(nodeToTest,targetNode):
    # 从头指针nodeLink开始,一直沿着nodeLink直到链表末尾,这就是一个链表
    while (nodeToTest.nodeLink != None):
        nodeToTest = nodeToTest.nodeLink
    nodeToTest.nodeLink = targetNode

#12.3 简答数据集及数据包装器
def loadSimpDat():
    simpleDat = [
        ['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 simpleDat

def createIniteSet(dataSet):
    retDict = {}
    for trans in dataSet:
        retDict[frozenset(trans)] = 1
    return retDict

# 12.4 发现以给定元素项结尾的所有路径的函数
def ascendTree(leafNode, prefixPath):
    if leafNode.parent != None:
        prefixPath.append(leafNode.name)
        ascendTree(leafNode.parent, prefixPath)

def findPrefixPath(basePat, treeNode):
    condPats = {}
    while treeNode != None:
        prefixPath = []
        ascendTree(treeNode, prefixPath)
        if len(prefixPath)>1:
            condPats[frozenset(prefixPath[1:])] = treeNode.count
        treeNode = treeNode.nodeLink
    return condPats

# 12.5 递归查找频繁项集的mineTree函数

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)
        # 然后将每一个频繁项添加到频繁项集列表freqItemList中
        freqItemList.append(newFreqSet)
        # 接下来调用findPrefixPath()函数来创造条件基
        condPattBases = findPrefixPath(basePat, headerTable(basePat)[1])
        # 该条件基被当成一个新数据集输送给createTree()函数
        # 这里为createTree()函数添加了足够的灵活性,以确保它可以被重用于构建条件树
        myCondTree , myHead = createTree(condPattBases, minSup)
        # 最后,如果树中有元素项的话,递归调用mineTree()函数
        if myHead != None:
            mineTree(myCondTree, myHead, minSup, newFreqSet, freqItemList)

猜你喜欢

转载自blog.csdn.net/weixin_42836351/article/details/81393108