机器学习实战(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(['']), set(['', '']), set(['']), set(['', '']), set(['', '', '']), set(['', '']), set(['']), set(['', '']), set([''])]
>>>

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

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

最新文章

  1. asp.net中缓存的使用介绍一
  2. 消息摘要算法-MAC算法系列
  3. 简单的cookie使用
  4. 2016.7.9 计算机网络复习要点第四章之网际控制报文协议ICMP
  5. 转 java 类 单例
  6. [百度空间] [转] 在 Visual C++ 中控制全局对象的初始化顺序
  7. 关于如何使用Navicat(11.1.13) for MySQL如何创建存储过程
  8. FZU 2082 过路费 (树链剖分 修改单边权)
  9. deepin软件中心打不开
  10. CodeForces 712D Memory and Scores
  11. STM32读取温湿度传感器DHT11和DHT21(AM2301)系列问题
  12. mysql进阶知识
  13. 通过mycat实现mysql的读写分离
  14. HTTP请求头和响应头部包括的信息有哪些?(转)
  15. 对www.518shengmao.com站资源打包,采用vue Node.js
  16. iOS开发简记(3):tips提示
  17. react与fetch
  18. cocos2dx九宫图使用方法
  19. 现有工程中集成Cordova
  20. 【Android】1.2 创建Android模拟器

热门文章

  1. TFS2018环境搭建一硬件要求
  2. 输入两棵二叉树A,B,判断B是不是A的子结构(c++实现)
  3. 从学CodeSmith谈程序员学习方法
  4. 全网最详细的hive-site.xml配置文件里添加&lt;name&gt;hive.cli.print.header&lt;/name&gt;和&lt;name&gt;hive.cli.print.current.db&lt;/name&gt;前后的变化(图文详解)
  5. PHP 编程小点
  6. golang内置数据类型作为函数参数
  7. java的构造方法链
  8. 记一次java程序占用cpu超高排查
  9. 设置tabBar、使用第三方插件和自定义组件使用简单实例
  10. 联想拯救者ISK代开BIOS的方法