前言

若想具体理解FP-growth,请参阅这位大神的作品:
https://www.cnblogs.com/pinard/p/6307064.html
本文的前一节《FP-growth:构建FP树》请点击:
https://blog.csdn.net/weixin_43901558/article/details/104320588

现在,我们已经有了这样一棵FP树,和头指针表:

显而易见,我们已经找到了6个单元素项的频繁项(即头指针表中的六个元素)。接下来我们要做的是:以此为基础,构建多元素项的频繁项。

抽取条件模式基

其实,我觉得看书学习不太好的一点是,前面所学的概念,往往是在读到后面才知道他到底有什么作用。所以在学习过程中总是会一头雾水,只有在学完之后才会恍然大悟——那个地方原来是这么回事!
所以我想先把整个过程用大白话解释一遍,然后再讲具体流程。

现在,我们已经有了单元素项的频繁项,那我们怎么找双元素项的呢?
我的理解是:
以现在的FP树为基础,针对每个频繁的单元素项Ai,构建一个属于该元素的FP子树Bi。(想想为什么不用考虑FP树外的元素?)
我们也知道,FP树就是用来找频繁项的,那么Ai的FP子树的头节点表中都是相对Ai频繁的单元素项。Ai与这些单元素项的集合,不就是频繁的双元素项了吗?
那么怎么找三元素项呢?自然是构建双元素项的FP子树,再与该子树中的头节点表结合。以此类推,就会找到所有的多元素项。

那问题来了,怎么构建FP子树呢?这就要用到这里讲的条件模式基。
一个元素的条件模式基,就是指该元素的所有前缀路径的集合
直接上例子吧,通过上图的FP树构造:

每一条前缀路径都与一个计数值关联,该数值等于起始元素项的计数值(比对着原FP树画一画?)


或许你会问了,FP子树和条件模式基又有什么关系呢?
在上一篇博客《FP-growth:构建FP树中》建树方法createTree一共有两个参数,一个是数据集,一个是最小支持度。而一个元素的条件模式基,就是该元素对应子树的数据集。


那怎么求得条件模式基呢?大致思想是:原FP树中的头节点表包含着该元素在树中第一次出现的结点指针,同时,结点的linknode属性中存储着下一个同元素结点的指针。一旦到达了每一个元素项,就可以上溯这棵树直到根结点为止。
代码如下:

# 上溯树,直到根节点
def ascendTree(leafNode, prefixPath):              if leafNode.parent is not None:prefixPath.append(leafNode.parent, prefixPath)ascendTree(leafNode.parent, prefixPath)def findPrefixPath(basePat, treeNode):condPats = {}while treeNode is not None:prefixPath = []ascendTree(treeNode, prefixPath)if len(prefixPath) > 1:condPats[frozenset(prefixPath[1:])] = treeNode.count# 找到该元素在树中的下一个节点treeNode = treeNode.nodelink           return condPats

创建条件FP树

这里说的条件FP树也就是上文说的FP子树
对于每一个频繁项,都要创建一颗条件FP树(数据集为该频繁项的条件模式基),然后我们会递归地发现频繁项,再发现这些频繁项的条件模式基,再建立条件FP树…举个例子,为单元素频繁项t创建条件FP树,找到二元素频繁项{t,y},{t,x}…再以这些二元素频繁项创建条件FP树,得到三元素频繁项
{t,x,y}…重复该过程,直到条件FP树中没有元素为止。
注意:对于一个频繁项A的条件FP树中的频繁项a,a的频繁不是指a的存在是否频繁,而是a相对A是否频繁
代码如下:

def mineTree(inTree, headerTable, minSup, preFix, freqItemList):# 从头指针表的底端开始bigL = [v[0] for v in sorted(headerTable.items(), key=lambda p:p[1][0])]for basePat in bigL:newFreqSet = preFix.copy()# 头节点表中的元素add进原频繁项中newFreqSet.add(basePat)# 把更新后的频繁项添加到频繁项集freqItemList中freqItemList.append(newFreqSet)condPattBases = findPrefixPath(basePat, headerTable[basePat][1])# 构建FP子树myCondTree, myHead = createTree(condPattBases, minSup)# 如果FP子树的头节点表不为空,即可再更新该频繁项if myHead is not None:mineTree(myCondTree, myHead, minSup, newFreqSet, freqItemList)

总代码

class treeNode:def __init__(self, nameValue, numOccur, parentNode):self.name = nameValueself.count = numOccurself.nodeLink = Noneself.parent = parentNodeself.children = {}def inc(self, numOccur):self.count += numOccurdef disp(self, ind=1):print(' ' * ind, self.name, self.count)for child in self.children.values():child.disp(ind+1)# 传入的数据集其实是个字典,key值为事务, value值为数据集中该事务的频次
def createTree(dataSet, minSup=3):headerTable = {}for trans in dataSet:for item in trans:headerTable[item] = headerTable.get(item, 0) + dataSet[trans]# 遍历数据集,构建headerTabel。其key为元素,value为元素出现频次for k in list(headerTable.keys()):# 如果元素频次小于最小支持度,则删去if headerTable[k] < minSup:del headerTable[k]freqItemSet = set(headerTable.keys())if len(freqItemSet) == 0:return None, Nonefor k in headerTable:# 拓展头指针表,第二项存储着指向该元素在树中第一次出现位置的指针headerTable[k] = [headerTable[k], None]# 建一棵空树retTree = treeNode('Null Set', 1, None)for tranSet, count in dataSet.items():# localD存储过滤后的数据集localD = {}for item in tranSet:if item in freqItemSet:localD[item] = headerTable[item][0]if len(localD) > 0:# orderedItems存储过滤并重排序后的数据集orderedItems = [v[0] for v in sorted(localD.items(),key=lambda p: p[1], reverse=True)]updateTree(orderedItems, retTree,headerTable, count)return retTree, headerTabledef 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] is None:headerTable[items[0]][1] = inTree.children[items[0]]else:updateHeader(headerTable[items[0]][1],inTree.children[items[0]])# 如果事务中不止一个元素,则去掉第一个元素,再迭代if len(items) > 1:updateTree(items[1::], inTree.children[items[0]],headerTable, count)def updateHeader(nodeToTeset, targetNode):while nodeToTeset.nodeLink is not None:nodeToTeset = nodeToTeset.nodeLinknodeToTeset.nodeLink = targetNodedef 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)] = 1return retDict# 上溯树,直到根节点
def ascendTree(leafNode, prefixPath):if leafNode.parent is not None:prefixPath.append(leafNode.name)ascendTree(leafNode.parent, prefixPath)def findPrefixPath(basePat, treeNode):condPats = {}while treeNode is not None:prefixPath = []ascendTree(treeNode, prefixPath)if len(prefixPath) > 1:condPats[frozenset(prefixPath[1:])] = treeNode.count# 找到该元素在树中的下一个节点treeNode = treeNode.nodeLinkreturn condPatsdef mineTree(inTree, headerTable, minSup, preFix, freqItemList):# 从头指针表的底端开始bigL = [v[0] for v in sorted(headerTable.items(), key=lambda p:p[1][0])]for basePat in bigL:newFreqSet = preFix.copy()# 头节点表中的元素add进原频繁项中newFreqSet.add(basePat)# 把更新后的频繁项添加到频繁项集freqItemList中freqItemList.append(newFreqSet)condPattBases = findPrefixPath(basePat, headerTable[basePat][1])# 构建FP子树myCondTree, myHead = createTree(condPattBases, minSup)# 如果FP子树的头节点表不为空,即可再更新该频繁项if myHead is not None:mineTree(myCondTree, myHead, minSup, newFreqSet, freqItemList)simpDat = loadSimpDat()
initSet = createInitSet(simpDat)
myFPtree, myHeaderTab = createTree(initSet, 3)
freqItems = []
mineTree(myFPtree, myHeaderTab, 3, set([]), freqItems)
print(freqItems)

输出为所有的频繁项,如下:

[{'r'}, {'t'}, {'x', 't'}, {'t', 'z'}, {'x', 't', 'z'}, {'s'},
{'x', 's'}, {'y'}, {'x', 'y'}, {'t', 'y'}, {'x', 't', 'y'},
{'z', 'y'}, {'x', 'z', 'y'}, {'z', 't', 'y'}, {'x', 'z', 't', 'y'},
{'x'}, {'x', 'z'}, {'z'}]

代码部分来自《机器学习实战》
参考资料:《机器学习实战》第12章

FP-growth:从FP树中挖掘频繁项集相关推荐

  1. 河北工业大学数据挖掘实验三 应用 Apriori 算法挖掘频繁项集

    河北工业大学数据挖掘实验三 应用 Apriori 算法挖掘频繁项集 一.实验目的 二.实验原理 1.Apriori 算法 2.提高频繁项集逐层产生的效率 三.实验内容和步骤 1.实验内容 2.实验步骤 ...

  2. 使用python挖掘频繁项集

    本实验包含以下内容: 学习挖掘频繁项集,掌握apriori算法 1.实现用apriori算法挖掘频繁项集(最小支持度计数2) 2.分析你所实现的apriori算法的缺点 3. 数据集: 数据集 TID ...

  3. python 频繁项集_Apriori算法:从数据中挖掘频繁项集

    简介 Apriori是一种流行的算法,用于在关联规则学习中提取频繁项集.Apriori算法被设计用于对包含交易的数据库进行操作,例如商店客户的购买.如果项目集满足用户指定的支持阈值,则该项目集被视为& ...

  4. Apriori算法挖掘频繁项集

    用Apriori或者FP-growth算法挖掘出所有的频繁项集,并写出具体的实现代码.假设事务数据库D表1:最小支持度计数为2. 下图是以Apriori算法为例.       表1 事务数据库D Ti ...

  5. 机器学习之手把手实现,第 2 部分 频繁项集与关联规则 FP-growth 的原理和实现...

    https://www.ibm.com/developerworks/cn/analytics/library/machine-learning-hands-on2-fp-growth/index.h ...

  6. 使用FP-growth算法发现频繁项集

    源码如下: #coding=utf-8''' Created on Jun 14, 2011 FP-Growth FP means frequent pattern the FP-Growth alg ...

  7. FP-growth算法高效发现频繁项集

    在用搜索引擎时,我们发现输入单词的一部分时,搜索引擎会自动补全查询词项,这里的原理其实是通过查询互联网上的词来找出经常出现在一块的词对,这需要一种高效发现频繁集的方法. 它基于Apriori构建,但在 ...

  8. 机器学习实战(十一)FP-growth(频繁项集)

    目录 0. 前言 1. 构建FP树 2. 从FP树中挖掘频繁项集 3. 实战案例 3.1. FP-growth寻找频繁项集 学习完机器学习实战的FP-growth,简单的做个笔记.文中部分描述属于个人 ...

  9. 使用FP-growth算法来高效发现频繁项集

    FP-growth算法基于Apriori构建,但采用了高级的数据结构减少扫描次数,大大加快了算法速度.FP-growth算法只需要对数据库进行两次扫描,而Apriori算法对于每个潜在的频繁项集都会扫 ...

最新文章

  1. 什么BRIEF算法?BRIEF算法详解
  2. 用c语言编写心里测试,求各位大神赐教!我做了一个“心理测试的答题卷”编程,总共有1...
  3. 关于范式的一些简单理解
  4. Zabbix之监控Mysql性能
  5. 风吹来_梅花香自苦寒来!一组赏心悦目的梅花图……
  6. win7查看隐藏文件_隐藏在电脑里の秘密,放在你眼前,你也发现不了,就是这么奥给力...
  7. Vue采用input实现文件上传与删除
  8. 游标定位:Cursor类
  9. Ajax同步和异步的区别?
  10. Linux中以单容器部署Nginx+ASP.NET Core
  11. 应用新的JDK 11字符串方法
  12. 计算机基础:程序、进程、线程
  13. 职场生活:辞职也有大学问
  14. minishell的实现及IO接口的调用
  15. JSON与XML的选择
  16. C语言能够被替换吗?
  17. php做异地登录验证,PHP实现用户异地登录提醒功能的方法【基于thinkPHP框架】
  18. 西瓜决策树-ID3算法
  19. Elasticsearch之近义词/同义词的使用
  20. 营收增速环比放缓 Okta高歌猛进的那股劲去哪了?

热门文章

  1. 大学物理电场、电势基本公式
  2. NOIP2016(bao)游(zha)记
  3. 结对编程——电梯调度系统
  4. SpringBoot重点详解--使用过滤器映射访问路径
  5. PTA谁是赢家(思路简单)
  6. 为什么销售团队要用crm销售管理系统?
  7. 【华大九天Aether芯片EDA模拟电路仿真 Centos7安装】
  8. 拿什么拯救你?程序员的虚荣心...
  9. .net中for循环及break和continue的区别
  10. 路平石模具铺设路缘石公路项目质量提升的过程