FP-growth算法高效发现频繁项集(Python代码)
来源:互联网 发布:易云网络人气 编辑:程序博客网 时间:2024/05/18 01:52
FP-growth算法高效发现频繁项集
1. 介绍
我们都有过这样的经历,在百度搜索里输入一个单词或者单词一部分的时候,搜索引擎会自动补全查询词项,比如当我输入“人工”两字的时候,度娘第一个反应是:咦,这人是不是想找人工受精相关的信息呢?所以就有了下面的这幅图:
图1 示例图片
FP-growth算法是伊利罗伊香槟分校的韩嘉炜教授于2004年[1]提出的,它是为了解决Apriori算法每次增加频繁项集的大小都要遍历整个数据库的缺点,特别是当数据集很大时,该算法执行速度要快于Apriori算法两个数量级。FP-growth算法的任务是将数据集存储在一个特定的称为FP树的结构之后发现频繁项集或者频繁项对,虽然它能够高效地发现频繁项集,但是不能用来发现关联规则,也就是只优化了Apriori算法两个功能中的前一个功能。
FP-growth算法只需要对数据集进行两次扫描,所以即使数据集很大时也不会花费太多的时间在扫描数据上,它发现频繁项集的基本过程如下:
1)构建FP树
2)从FP树中挖掘频繁项集
2. 算法详解
2.1 用FP树编码数据集
FP-growth算法将数据存储在一个称为FP树的紧凑数据结构中,它与计算机科学中的其他树的结构类似,但是它通过链接来链接相似元素,被连起来的元素可以看做一个链表,如下图:
图 2 FP树的结构示意图
FP树会存储项集出现的频率,每个项集都会以路径的形式存储在树中,存在相似元素的集合会共享树的一部分。只有当集合之间完全不同时树才会分叉,树节点上给出集合中单个元素及其在序列中出现的次数,路径会给出该序列的出现次数。
相似项之间的链接即节点链接,用于快速发现相似项的位置,下面的例子:
图3 用于发现图2中FP树的事务数据样例
第一列是事务的ID,第二列是事务中的元素项,在图2中z出现了5次,而{r,z}项支出项了一次,所以z一定自己本身或者和其他的符号一起出现了4次,而由图2同样可知:集合{t,s,y,x,z}出现了2次,集合{t,r,y,x,z}出现了1次,所以z一定本身出现了1次。看了图3可能会有疑问,为什么在图2中没有p,q,w,v等元素呢?这是因为通常会给所有的元素设置一个阈度值(Apriori里的支持度),低于这个阈值的元素不加以研究。暂时不理解没关系,看了下面的内容可能会对这一段的内容有比较好的理解。
2.1.1 构建FP树
构建FP树是算法的第一步,在FP树的基础之上再对频繁项集进行挖掘。为了构建FP树,要对数据集扫描两次,第一次对所有元素项出现次数进行计数,记住如果一个元素不是频繁的,那么包含这个元素的超集也不是频繁的,所以不需要考虑这些超集,第二遍的扫描只考虑那些频繁元素。
除了图2给出的FP树之外,还需要一个头指针表来指向给定类型的第一个实例。利用头指针表可以快速访问FP树中一个给定类型的所有元素,发现相似元素项,如下图所示:
图 4 带头指针的FP树
头指针表的数据结构是字典,除了存放头指针元素之外,还可以存放FP中每类元素的个数。第一次遍历数据集得到每个元素项出现的频率,接下来去掉不满足最小值支持度的元素项,在接下来就可以创建FP树了,构建时,将每个项集添加到一个已经存在的路径中,如果该路径不存在,则创建一个新的路径。每个事务都是一个无序的集合,然而在FP树中相同项只会出现一次,{x,y,z}和{y,z,x}应该在同一个路径上,所以在将集合添加到树之前要对每个集合进行排序,排序是基于各个元素出现的频率来进行的,使用图4头指针表中单个元素的出现值,对图3中的数据进行过滤,重排后的新数据如下:
图5 移除非频繁项,重新排序后的事务表
现在,就可以构建FP树了,从空集开始,向其中不断添加频繁项集。过滤,排序后的事务依次添加到树中,如果树中已有现有元素,则增加该元素的值;如果元素不存在,则添加新分枝。图5中事务表前两条事务添加的过程如下图所示:
图 6 FP构建过程示例图
现在应该大致知道数据集转换成FP树的思想了吧。
2.2 从FP树中挖掘频繁项
有了FP树之后就可以抽取频繁项集了,思想与Apriori算法大致一样,从单元素项集开始,逐步构建更大的集合,只不过不需要原始的数据集了。
从FP树中抽取频繁项集的三个基本步骤:
1)从FP树中获得条件模式基;
2)利用条件模式基,构建一个条件FP树;
3)迭代重复步骤(1)(2)直到树只包含一个元素项为止
2.2.1抽取条件模式基
条件模式基是以所查找元素项为结尾的路径集合,每一条路径包含一条前缀路径和结尾元素,图4中,符号r的前缀路径有{x,s}、{z,x,y}和{z},每一条前缀路径都与一个数据值关联,这个值等于路径上r的数目,下表中列出单元素频繁项的所有前缀路径。
图7 每个频繁项的前缀路径
前缀路径将被用于构建条件FP树。为了获得这些路径,可以对FP树进行穷举式搜索,直到获得想要的频繁项为止,但可以使用一个更为有效的方法加速搜索过程。可以用先前的头指针表来创建一种更为有效的方法,头指针表中包含相同类型元素链表的起始指针。一旦到达了每一个元素项,就可以上溯这棵树直到根节点为止。
2.2.2 创建条件FP树
对于每一个频繁项,都要创建一个条件FP树,将上面的条件模式基作为输入,通过相同的建树方法来构建这些条件树,然后递归地发现频繁项、发现条件模式基,以及发现另外的条件树。举个例子,假定为频繁项t创建一个条件FP树,然后对{t,y},{t,x}、...重复该过程。元素项t的条件FP树的构建过程如下:
图 8
s,r虽然是条件模式基的一部分,且单独看都是频繁项,但是在t的条件树中,他却是不频繁的,分别出现了2次和一次,小于阈值3,所以{t,r},{t,s}不是频繁的。接下来对集合{t,z},{t,x},{t,y}来挖掘对应的条件树,会产生更复杂的频率项集,该过程重复进行,直到条件树中没有元素 为止,停止。
3 代码实现
定义树的结构:
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)
创建树:
#dataSet是记录,minSup是最小支持度def createTree(dataSet,minSup=1): #对每个元素进行计数 headerTable = {} for trans in dataSet for item in trans: headerTable[item] = headerTable.get(item,0) + dataSet[trans]#删除项集大小为1的非频繁项集,根据apriori原则,包含该非频繁项集的项集都不可能是频繁项集 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: headereTable[k] = [headerTable[k],None] #创建根节点 retTree = treeNode('Null Set',1,None) #得到删除非频繁k=1的项的 项集,并以字典树的形式插入树里。 for tranSet, count in dataSet.items(): localID = {} 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) return retTree,headerTable
更新HeaderLink的链:
def updateHeader(nodeToTest,targetNone): while(nodeToTest.nodeLink != None): nodeToTest = nodeToTest.nodeLink nodeToTest.nodeLink = targetNone
测试数据:
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 simpDatdef createInitSet(dataSet): retDict = {} for trans in dataSet: retDict[frozenset(trans)] = 1 return retDict
4. 参考文献
[1] Machine Learning in Action
0 0
- FP-growth算法高效发现频繁项集(Python代码)
- 使用FP-growth算法来高效发现频繁项集
- 使用FP-growth算法来高效发现频繁项集
- FP-growth算法高效发现频繁项集
- 使用FP-growth算法来高效发现频繁项集
- FP-growth算法高效发现频繁项集
- 机器学习实战代码详解(12)使用FP-growth算法来高效发现频繁集
- 发现频繁项集FP-growth算法
- 代码注释:机器学习实战第12章 使用FP-growth算法来高效发现频繁项集
- FP-growth算法发现频繁项集(二)——发现频繁项集
- [完]机器学习实战 第十二章 使用FP-growth算法来高效发现频繁项集
- py2.7《机器学习实战》使用FP-growth算法高效发现频繁项集
- 【机器学习实战-python3】使用FP-growth算法来高效 发现频繁项集
- 机器学习之使用FP-growth算法来高效发现频繁项集
- FP-growth算法,高效发现频繁项集,找出最短时序路径
- 机器学习实战-使用FP-growth算法来高效发现频繁项集
- 【机器学习实战】第12章 使用FP-growth算法来高效发现频繁项集
- 【机器学习实战】第12章 使用 FP-growth 算法来高效发现频繁项集
- android 多媒体和相机详解九
- C#_关于Using作用域问题
- MySQL 数据库性能优化之索引优化
- PureFtpd
- python time模块使用实例
- FP-growth算法高效发现频繁项集(Python代码)
- c++强制类型转换:dynamic_cast、const_cast 、static_cast、reinterpret_cast
- DayDayUP_Python自学记录[7]_日期和时间
- spark sql运行出错(Container killed on request. Exit code is 143)
- 欢迎使用CSDN-markdown编辑器
- MySQL 数据库性能优化之SQL优化
- JAVA客户端调用memcached
- textview设置多种不同的字体颜色和点击事件
- LINUX 命令使用技巧