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处理csv数据的方法
Mar 11 Python
使用Python制作获取网站目录的图形化程序
May 04 Python
python处理图片之PIL模块简单使用方法
May 11 Python
Python判断文件和字符串编码类型的实例
Dec 21 Python
用tensorflow实现弹性网络回归算法
Jan 09 Python
python读取文本绘制动态速度曲线
Jun 21 Python
解决Pycharm界面的子窗口不见了的问题
Jan 17 Python
linux环境下安装python虚拟环境及注意事项
Jan 07 Python
python中pyqtgraph知识点总结
Jan 26 Python
python绘制高斯曲线
Feb 19 Python
教你如何使用Python开发一个钉钉群应答机器人
Jun 21 Python
python ConfigParser库的使用及遇到的坑
Feb 12 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静态文件返回304技巧分享
2015/01/06 PHP
PHP PDOStatement::execute讲解
2019/01/31 PHP
jQuery each()方法的使用方法
2010/03/18 Javascript
js截取函数(indexOf,join等)
2010/09/01 Javascript
jquery ajax例子返回值详解
2012/09/11 Javascript
前台js调用后台方法示例
2013/12/02 Javascript
两个多选select(multiple左右)添加、删除选项和取值实例
2014/05/12 Javascript
通过设置CSS中的position属性来固定层的位置
2015/12/14 Javascript
浅谈regExp的test方法取得的值变化的原因及处理方法
2017/03/01 Javascript
原生JS实现隐藏显示图片 JS实现点击切换图片效果
2021/01/27 Javascript
详解webpack之图片引入-增强的file-loader:url-loader
2018/10/08 Javascript
angular4 获取wifi列表中文显示乱码问题的解决
2018/10/20 Javascript
vue动态配置模板 'component is'代码
2019/07/04 Javascript
vue 实现滚动到底部翻页效果(pc端)
2019/07/31 Javascript
Vue js with语句原理及用法解析
2020/09/03 Javascript
Python编程中归并排序算法的实现步骤详解
2016/05/04 Python
Python数据分析之真实IP请求Pandas详解
2016/11/18 Python
Python实现可自定义大小的截屏功能
2018/01/20 Python
python实现周期方波信号频谱图
2018/07/21 Python
selenium + python 获取table数据的示例讲解
2018/10/13 Python
python将字符串list写入excel和txt的实例
2019/07/20 Python
简单了解python 邮件模块的使用方法
2019/07/24 Python
python3的数据类型及数据类型转换实例详解
2019/08/20 Python
20行Python代码实现一款永久免费PDF编辑工具的实现
2020/08/27 Python
Python+unittest+DDT实现数据驱动测试
2020/11/30 Python
python中的插入排序的简单用法
2021/01/19 Python
吃透移动端 1px的具体用法
2019/12/16 HTML / CSS
利用Node实现HTML5离线存储的方法
2020/10/16 HTML / CSS
世界上最大的在线旅行社新加坡网站:Expedia新加坡
2016/08/25 全球购物
信息科学与技术专业求职信范文
2014/02/20 职场文书
工伤事故赔偿协议书
2014/10/27 职场文书
干部考察材料范文
2014/12/24 职场文书
php中配置文件保存修改操作 如config.php文件的读取修改等操作
2021/05/12 PHP
你喜欢篮球吗?Python实现篮球游戏
2021/06/11 Python
低版本Druid连接池+MySQL驱动8.0导致线程阻塞、性能受限
2021/07/01 MySQL
Nginx反向代理至go-fastdfs案例讲解
2021/08/02 Servers