zoukankan      html  css  js  c++  java
  • 机器学习实战(Machine Learning in Action)学习笔记————08.使用FPgrowth算法来高效发现频繁项集

    机器学习实战(Machine Learning in Action)学习笔记————08.使用FPgrowth算法来高效发现频繁项集

    关键字:FPgrowth、频繁项集、条件FP树、非监督学习
    作者:米仓山下
    时间:2018-11-3
    机器学习实战(Machine Learning in Action,@author: Peter Harrington)
    源码下载地址:https://www.manning.com/books/machine-learning-in-action
    git@github.com:pbharrin/machinelearninginaction.git

    *************************************************************
    一、使用FPgrowth算法来高效发现频繁项集

    FPgrowth算法原理:
    基于Apriori构建,但在完成相同任务时,采用了一些不同的的技术。这里的任务是将数据集存储在一个特定的称为FP树的结构之后发现频繁项集或则频繁项对,即在一块出现的的元素项的集合FP树。这种做法的执行速度要快于Apriori,通常性能要好两个数量级以上。
    FP——Frequent pattern(频繁模式)

    *************************************************************
    二、FPgrowth算法——构建FP树

    FP树构建函数
    ----------------------------------------------------------------------------
    输入:dataSet——待挖掘数据集;minSup——最小支持度,默认为1
    输出:retTree——构建的FP树; headerTable——头指针表

    def createTree(dataSet, minSup=1): #create FP-tree from dataset but don't mine
        headerTable = {}
        
        #扫描两次数据集dataSet
        for trans in dataSet:#第一次扫描,统计所有元素出现的频次
            for item in trans:
                headerTable[item] = headerTable.get(item, 0) + dataSet[trans]
        for k in headerTable.keys():  #移除不符合minSup的items
            if headerTable[k] < minSup:
                del(headerTable[k])
        freqItemSet = set(headerTable.keys())
        #print 'freqItemSet: ',freqItemSet
        if len(freqItemSet) == 0: return None, None  #没有items符合minSup,返回None退出
        for k in headerTable:
            headerTable[k] = [headerTable[k], None]  #结构化headerTable
        #print 'headerTable: ',headerTable
        retTree = treeNode('Null Set', 1, None)      #创建FP树根节点
        for tranSet, count in dataSet.items():       #第二次扫描,构建FP树retTree
            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)  #更新FP树retTree
        return retTree, headerTable                  #返回FP树retTree,头指针表headerTable

    注:createTree足够灵活,下面构建条件FP树时还要用到

    #更新FP树retTree
    def updateTree(items, inTree, headerTable, count):
        if items[0] in inTree.children:          #如果第一个元素orderedItems[0]在子节点中
            inTree.children[items[0]].inc(count) #增加计数
        else:                                    #不存在,增加子节点
            inTree.children[items[0]] = treeNode(items[0], count, inTree)
            if headerTable[items[0]][1] == None: #头指针表中items没有指向节点
                headerTable[items[0]][1] = inTree.children[items[0]]
            else:           #头指针表中items以指向某个相似节点,追加到后面
                updateHeader(headerTable[items[0]][1], inTree.children[items[0]])
        if len(items) > 1:  #items不止一个元素,去掉第一个元素,递归调用updateTree构建树
            updateTree(items[1::], inTree.children[items[0]], headerTable, count)

    ----------------------------------------------------------------------------
    测试:

    >>> import fpGrowth
    >>> simpdata=fpGrowth.loadSimpDat()
    >>> initset=fpGrowth.createInitSet(simpdata)
    >>> simpdata
    [['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']]
    >>> initset
    {frozenset(['e', 'm', 'q', 's', 't', 'y', 'x', 'z']): 1, frozenset(['x', 's', 'r', 'o', 'n']): 1, frozenset(['s', 'u', 't', 'w', 'v', 'y', 'x', 'z']): 1, frozenset(['q', 'p', 'r', 't', 'y', 'x', 'z']): 1, frozenset(['h', 'r', 'z', 'p', 'j']): 1, frozenset(['z']): 1}
    >>> minSup = 3
    >>> myFPtree, myHeaderTab = fpGrowth.createTree(initset, minSup)
    >>> myFPtree.disp()
       Null Set   1
         x   1
           s   1
             r   1
         z   5
           x   3
             y   3
               s   2
                 t   2
               r   1
                 t   1
           r   1
    >>> myHeaderTab
    {'s': [3, <fpGrowth.treeNode instance at 0x00000000039FE608>], 'r': [3, <fpGrowth.treeNode instance at 0x00000000039FE788>], 't': [3, <fpGrowth.treeNode instance at 0x00000000039FE688>], 'y': [3, <fpGrowth.treeNode instance at 0x00000000039FE5C8>], 'x': [4, <fpGrowth.treeNode instance at 0x00000000039FE588>], 'z': [5, <fpGrowth.treeNode instance at 0x00000000039FE548>]}
    >>>

    *************************************************************
    三、从一棵FP树种挖掘频繁项集

    #递归查找频繁项:mineTree函数
    ----------------------------------------------------------------------------

    #输入:inTree——输入FP树,递归调用时为此时的元素preFix条件FP树;headerTable——头指针表;minSup——最小支持数;preFix——初始化为set([]),递归调用时为条件FP树inTree对应的元素;freqItemList——初始化为[],用来存储频繁项集。
    #输出:freqItemList——用来存储频繁项集
    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:                #从头指针表bigL(headerTable)底端开始遍历(从小到大)
            newFreqSet = preFix.copy()
            newFreqSet.add(basePat)         #递归前,newFreqSet为单元素频繁项;递归时preFix不为空,开始组合
            freqItemList.append(newFreqSet) #将每个频繁项加入到列表freqItemList中
            condPattBases = findPrefixPath(basePat,        #抽取条件模式基condPattBases,去掉了元素本身
                            headerTable[basePat][1])
            myCondTree, myHead = createTree(condPattBases, #根据条件模式基condPattBases构建条件频繁树myCondTree
                                 minSup)
            if myHead != None:                              #挖掘FP条件树       
                #print 'conditional tree for: ',newFreqSet
                #myCondTree.disp(1)
                mineTree(myCondTree, myHead, minSup,       #newFreqSet不为空set([]),递归调用mineTree函数
                                  newFreqSet, freqItemList)

    ----------------------------------------------------------------------------
    将源码中下面两行取消注释:
    #print 'conditional tree for: ',newFreqSet
    #myCondTree.disp(1)      #打印条件树

    测试:

    >>> myFreqList = []
    >>> reload(fpGrowth)
    <module 'fpGrowth' from 'fpGrowth.py'>
    
    #遍历头指针表myHeaderTab,将其单元素频繁项加入myFreqList后,再找出每个元素的条件FP树。递归调用组合频繁项
    >>> fpGrowth.mineTree(myFPtree, myHeaderTab, minSup, set([]), myFreqList)
    conditional tree for:  set(['y'])
       Null Set   1
         x   3
           z   3
    conditional tree for:  set(['y', 'z'])
       Null Set   1
         x   3
    conditional tree for:  set(['s'])
       Null Set   1
         x   3
    conditional tree for:  set(['t'])
       Null Set   1
         y   3
           x   3
             z   3
    conditional tree for:  set(['x', 't'])
       Null Set   1
         y   3
    conditional tree for:  set(['z', 't'])
       Null Set   1
         y   3
           x   3
    conditional tree for:  set(['x', 'z', 't'])
       Null Set   1
         y   3
    conditional tree for:  set(['x'])
       Null Set   1
         z   3
    >>> myFreqList
    [set(['y']), set(['y', 'z']), set(['y', 'x', 'z']), set(['y', 'x']), set(['s']), set(['x', 's']), set(['t']), set(['z', 't']), set(['x', 'z', 't']), set(['y', 'x', 'z', 't']), set(['y', 'z', 't']), set(['x', 't']), set(['y', 'x', 't']), set(['y', 't']), set(['r']), set(['x']), set(['x', 'z']), set(['z'])]
    >>> len(myFreqList)
    18
    >>>


    *************************************************************
    四、示例:从新闻网站点击流中挖掘
    kosarak.dat中有将近100万条记录,每一行包含了某个用户浏览过得新闻报道。有些用户只看过一篇,有的用户看过2498篇报道。用户和报道编码成整数,利用FPgrowth算法

    #读取数据,数据集格式化

    >>> parsedDat=[line.split() for line in open('kosarak.dat').readlines()]
    >>> len(parsedDat)
    990002
    >>> initset=fpGrowth.createInitSet(parsedDat)
    
    #构建FP树,寻找阅读量10+的新闻报道
    >>> myFPtree, myHeaderTab = fpGrowth.createTree(initset, 100000)
    
    #创建条件FP树
    >>> myFreqList = []
    >>> fpGrowth.mineTree(myFPtree, myHeaderTab, 100000, set([]), myFreqList)
    >>> len(myFreqList)
    9
    >>> myFreqList
    [set(['1']), set(['1', '6']), set(['3']), set(['11', '3']), set(['11', '3', '6']), set(['3', '6']), set(['11']), set(['11', '6']), set(['6'])]
    >>>

    ----------------------------------------------------------------------------
    总结:

    优点:FPgrowth算法相比Apriori只需要对数据库进行两次扫描,能够显著加快频繁项集发现速度
    缺点:该算法能够更高效的发现频繁项集,但不能用于发现关联规则
    应用:搜索引擎推荐词(经常在一块出现的词对)等

  • 相关阅读:
    Java 蓝桥杯 算法训练 貌似化学
    Java 蓝桥杯 算法训练 貌似化学
    Java 蓝桥杯 算法训练 字符串的展开 (JAVA语言实现)
    Java 蓝桥杯 算法训练 字符串的展开 (JAVA语言实现)
    Java 蓝桥杯 算法训练 字符串的展开 (JAVA语言实现)
    Java 蓝桥杯 算法训练 字符串的展开 (JAVA语言实现)
    Java 蓝桥杯 算法训练 字符串的展开 (JAVA语言实现)
    JAVA-蓝桥杯-算法训练-字符串变换
    Ceph:一个开源的 Linux PB 级分布式文件系统
    shell 脚本监控程序是否正在执行, 如果没有执行, 则自动启动该进程
  • 原文地址:https://www.cnblogs.com/Micang/p/9900854.html
Copyright © 2011-2022 走看看