FP-growth算法发现频繁项集——构建FP树


Posted in Python onJune 24, 2021

  FP代表频繁模式(Frequent Pattern),算法主要分为两个步骤:FP-tree构建、挖掘频繁项集。

FP树表示法

  FP树通过逐个读入事务,并把事务映射到FP树中的一条路径来构造。由于不同的事务可能会有若干个相同的项,因此它们的路径可能部分重叠。路径相互重叠越多,使用FP树结构获得的压缩效果越好;如果FP树足够小,能够存放在内存中,就可以直接从这个内存中的结构提取频繁项集,而不必重复地扫描存放在硬盘上的数据。

  一颗FP树如下图所示:

FP-growth算法发现频繁项集——构建FP树

  通常,FP树的大小比未压缩的数据小,因为数据的事务常常共享一些共同项,在最好的情况下,所有的事务都具有相同的项集,FP树只包含一条节点路径;当每个事务都具有唯一项集时,导致最坏情况发生,由于事务不包含任何共同项,FP树的大小实际上与原数据的大小一样。

  FP树的根节点用φ表示,其余节点包括一个数据项和该数据项在本路径上的支持度;每条路径都是一条训练数据中满足最小支持度的数据项集;FP树还将所有相同项连接成链表,上图中用蓝色连线表示。

  为了快速访问树中的相同项,还需要维护一个连接具有相同项的节点的指针列表(headTable),每个列表元素包括:数据项、该项的全局最小支持度、指向FP树中该项链表的表头的指针。

FP-growth算法发现频繁项集——构建FP树

构建FP树

  现在有如下数据:

FP-growth算法发现频繁项集——构建FP树  

FP-growth算法需要对原始训练集扫描两遍以构建FP树。

  第一次扫描,过滤掉所有不满足最小支持度的项;对于满足最小支持度的项,按照全局最小支持度排序,在此基础上,为了处理方便,也可以按照项的关键字再次排序。

FP-growth算法发现频繁项集——构建FP树

第一次扫描的后的结果

  第二次扫描,构造FP树。

  参与扫描的是过滤后的数据,如果某个数据项是第一次遇到,则创建该节点,并在headTable中添加一个指向该节点的指针;否则按路径找到该项对应的节点,修改节点信息。具体过程如下所示:

FP-growth算法发现频繁项集——构建FP树

事务001,{z,x}

FP-growth算法发现频繁项集——构建FP树

事务002,{z,x,y,t,s}

FP-growth算法发现频繁项集——构建FP树

事务003,{z}

FP-growth算法发现频繁项集——构建FP树

事务004,{x,s,r}

FP-growth算法发现频繁项集——构建FP树

事务005,{z,x,y,t,r}

FP-growth算法发现频繁项集——构建FP树

事务006,{z,x,y,t,s}

  从上面可以看出,headTable并不是随着FPTree一起创建,而是在第一次扫描时就已经创建完毕,在创建FPTree时只需要将指针指向相应节点即可。从事务004开始,需要创建节点间的连接,使不同路径上的相同项连接成链表。

  代码如下:

def loadSimpDat():
    simpDat = [['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 simpDat
def createInitSet(dataSet):
    retDict = {}
    for trans in dataSet:
        fset = frozenset(trans)
        retDict.setdefault(fset, 0)
        retDict[fset] += 1
    return retDict
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():
            child.disp(ind + 1)

def createTree(dataSet, minSup=1):
    headerTable = {}
    #此一次遍历数据集, 记录每个数据项的支持度
    for trans in dataSet:
        for item in trans:
            headerTable[item] = headerTable.get(item, 0) + 1
    #根据最小支持度过滤
    lessThanMinsup = list(filter(lambda k:headerTable[k] < minSup, headerTable.keys()))
    for k in lessThanMinsup: del(headerTable[k])
    freqItemSet = set(headerTable.keys())
    #如果所有数据都不满足最小支持度,返回None, None
    if len(freqItemSet) == 0:
        return None, None
    for k in headerTable:
        headerTable[k] = [headerTable[k], None]
    retTree = treeNode('φ', 1, None)
    #第二次遍历数据集,构建fp-tree
    for tranSet, count in dataSet.items():
        #根据最小支持度处理一条训练样本,key:样本中的一个样例,value:该样例的的全局支持度
        localD = {}
        for item in tranSet:
            if item in freqItemSet:
                localD[item] = headerTable[item][0]
        if len(localD) > 0:
            #根据全局频繁项对每个事务中的数据进行排序,等价于 order by p[1] desc, p[0] desc
            orderedItems = [v[0] for v in sorted(localD.items(), key=lambda p: (p[1],p[0]), reverse=True)]
            updateTree(orderedItems, retTree, headerTable, count)
    return retTree, headerTable

def updateTree(items, inTree, headerTable, count):
    if items[0] in inTree.children:  # check if orderedItems[0] in retTree.children
        inTree.children[items[0]].inc(count)  # incrament count
    else:  # add items[0] to inTree.children
        inTree.children[items[0]] = treeNode(items[0], count, inTree)
        if headerTable[items[0]][1] == None:  # update header table
            headerTable[items[0]][1] = inTree.children[items[0]]
        else:
            updateHeader(headerTable[items[0]][1], inTree.children[items[0]])
    if len(items) > 1:  # call updateTree() with remaining ordered items
        updateTree(items[1:], inTree.children[items[0]], headerTable, count)

def updateHeader(nodeToTest, targetNode):  # this version does not use recursion
    while (nodeToTest.nodeLink != None):  # Do not use recursion to traverse a linked list!
        nodeToTest = nodeToTest.nodeLink
    nodeToTest.nodeLink = targetNode
simpDat = loadSimpDat()
dictDat = createInitSet(simpDat)
myFPTree,myheader = createTree(dictDat, 3)
myFPTree.disp()

  上面的代码在第一次扫描后并没有将每条训练数据过滤后的项排序,而是将排序放在了第二次扫描时,这可以简化代码的复杂度。

  控制台信息:

FP-growth算法发现频繁项集——构建FP树

项的顺序对FP树的影响

  值得注意的是,对项的关键字排序将会影响FP树的结构。下面两图是相同训练集生成的FP树,图1除了按照最小支持度排序外,未对项做任何处理;图2则将项按照关键字进行了降序排序。树的结构也将影响后续发现频繁项的结果。

FP-growth算法发现频繁项集——构建FP树

图1 未对项的关键字排序

FP-growth算法发现频繁项集——构建FP树

图2 对项的关键字降序排序

总结  

本派文章就到这里了,下篇继续,介绍如何发现频繁项集。希望能给你带来帮助,也希望您能够多多关注三水点靠木的更多内容!

Python 相关文章推荐
python中的内置函数getattr()介绍及示例
Jul 20 Python
python使用urlparse分析网址中域名的方法
Apr 15 Python
解析Python中的二进制位运算符
May 13 Python
python解决pandas处理缺失值为空字符串的问题
Apr 08 Python
Sanic框架蓝图用法实例分析
Jul 17 Python
不到20行代码用Python做一个智能聊天机器人
Apr 19 Python
Python 实现自动获取种子磁力链接方式
Jan 16 Python
python解释器pycharm安装及环境变量配置教程图文详解
Feb 26 Python
python 实现在无序数组中找到中位数方法
Mar 03 Python
Python中使用aiohttp模拟服务器出现错误问题及解决方法
Oct 31 Python
五种Python转义表示法
Nov 27 Python
Django搭建项目实战与避坑细节详解
Dec 06 Python
python ansible自动化运维工具执行流程
关于python中readlines函数的参数hint的相关知识总结
详解Python为什么不用设计模式
linux中nohup和后台运行进程查看及终止
Jun 24 #Python
Python面向对象之成员相关知识总结
Jun 24 #Python
Python面向对象之内置函数相关知识总结
Jun 24 #Python
python面向对象版学生信息管理系统
You might like
PHP生成腾讯云COS接口需要的请求签名
2018/05/20 PHP
jQuery中的bind绑定事件与文本框改变事件的临时解决方法
2010/08/13 Javascript
一个简单的网站访问JS计数器 刷新1次加1次访问
2012/09/20 Javascript
js生成随机数之random函数随机示例
2013/12/20 Javascript
JS中生成随机数的用法及相关函数
2016/01/09 Javascript
jquery实现表格中点击相应行变色功能效果【实例代码】
2016/05/09 Javascript
EasyUI 中combotree 默认不能选择父节点的实现方法
2016/11/07 Javascript
JavaScript自动点击链接 防止绕过浏览器访问的方法
2017/01/19 Javascript
详解AngularJS中$filter过滤器使用(自定义过滤器)
2017/02/04 Javascript
Angularjs实现上传图片预览功能
2017/09/01 Javascript
zTree jQuery 树插件的使用(实例讲解)
2017/09/25 jQuery
vue+iview写个弹框的示例代码
2017/12/05 Javascript
layui实现动态和静态分页
2018/04/28 Javascript
基于element-ui的rules中正则表达式
2018/09/04 Javascript
angular4笔记系列之内置指令小结
2018/11/09 Javascript
react配置antd按需加载的使用
2019/02/11 Javascript
[18:20]DOTA2 HEROS教学视频教你分分钟做大人-昆卡
2014/06/11 DOTA
python自动翻译实现方法
2016/05/28 Python
Python 3中print函数的使用方法总结
2017/08/08 Python
matplotlib subplots 调整子图间矩的实例
2018/05/25 Python
详解Django+Uwsgi+Nginx的生产环境部署
2018/06/25 Python
Python实现基于SVM的分类器的方法
2019/07/19 Python
python中property和setter装饰器用法
2019/12/19 Python
python实现遍历文件夹图片并重命名
2020/03/23 Python
Python类的继承super相关原理解析
2020/10/22 Python
马来西亚网上购物:Youbeli
2018/03/30 全球购物
贝佳斯官方网站:Borghese
2020/05/08 全球购物
路德维希•贝克(LUDWIG BECK)中文官网:德国大型美妆百货
2020/09/19 全球购物
承认错误的检讨书
2014/01/30 职场文书
《第一朵杏花》教学反思
2014/04/16 职场文书
《大作家的小老师》教学反思
2014/04/16 职场文书
2014年社会实践活动总结范文
2014/04/29 职场文书
爱心捐书活动总结
2014/07/05 职场文书
服务行业演讲稿
2014/09/02 职场文书
汉字听写大会观后感
2015/06/12 职场文书
浅析Python OpenCV三种滤镜效果
2022/04/11 Python