用Spark学习FP Tree算法和PrefixSpan算法
在FP Tree算法原理总结和PrefixSpan算法原理总结中,我们对FP Tree和PrefixSpan这两种关联算法的原理做了总结,这里就从实践的角度介绍如何使用这两个算法。由于scikit-learn中没有关联算法的类库,而Spark MLlib有,本文的使用以Spark MLlib作为使用环境。
1. Spark MLlib关联算法概述
在Spark MLlib中,也只实现了两种关联算法,即我们的FP Tree和PrefixSpan,而像Apriori,GSP之类的关联算法是没有的。而这些算法支持Python,Java,Scala和R的接口。由于前面的实践篇我们都是基于Python,本文的后面的介绍和使用也会使用MLlib的Python接口。
Spark MLlib关联算法基于Python的接口在pyspark.mllib.fpm包中。FP Tree算法对应的类是pyspark.mllib.fpm.FPGrowth(以下简称FPGrowth类),从Spark1.4开始才有。而PrefixSpan算法对应的类是pyspark.mllib.fpm.PrefixSpan(以下简称PrefixSpan类),从Spark1.6开始才有。因此如果你的学习环境的Spark低于1.6的话,是不能正常的运行下面的例子的。
Spark MLlib也提供了读取关联算法训练模型的类,分别是 pyspark.mllib.fpm.FPGrowthModel和pyspark.mllib.fpm.PrefixSpanModel。这两个类可以把我们之前保存的FP Tree和PrefixSpan训练模型读出来。
2. Spark MLlib关联算法参数介绍
对于FPGrowth类,使用它的训练函数train主要需要输入三个参数:数据项集data,支持度阈值minSupport和数据并行运行时的数据分块数numPartitions。对于支持度阈值minSupport,它的取值大小影响最后的频繁项集的集合大小,支持度阈值越大,则最后的频繁项集数目越少,默认值0.3。而数据并行运行时的数据分块数numPartitions主要在分布式环境的时候有用,如果你是单机Spark,则可以忽略这个参数。
对于PrefixSpan类, 使用它的训练函数train主要需要输入四个参数:序列项集data,支持度阈值minSupport, 最长频繁序列的长度maxPatternLength 和最大单机投影数据库的项数maxLocalProjDBSize。支持度阈值minSupport的定义和FPGrowth类类似,唯一差别是阈值默认值为0.1。maxPatternLength限制了最长的频繁序列的长度,越小则最后的频繁序列数越少。maxLocalProjDBSize参数是为了保护单机内存不被撑爆。如果只是是少量数据的学习,可以忽略这个参数。
从上面的描述可以看出,使用FP Tree和PrefixSpan算法没有什么门槛。学习的时候可以通过控制支持度阈值minSupport控制频繁序列的结果。而maxPatternLength可以帮忙PrefixSpan算法筛除太长的频繁序列。在分布式的大数据环境下,则需要考虑FPGrowth算法的数据分块数numPartitions,以及PrefixSpan算法的最大单机投影数据库的项数maxLocalProjDBSize。
3. Spark FP Tree和PrefixSpan算法使用示例
这里我们用一个具体的例子来演示如何使用Spark FP Tree和PrefixSpan算法挖掘频繁项集和频繁序列。
完整代码参见我的github: https://github.com/ljpzzz/machinelearning/blob/master/classic-machine-learning/fp_tree_prefixspan.ipynb
要使用 Spark 来学习FP Tree和PrefixSpan算法,首先需要要确保你安装好了Hadoop和Spark(版本不小于1.6),并设置好了环境变量。一般我们都是在ipython notebook(jupyter notebook)中学习,所以最好把基于notebook的Spark环境搭好。当然不搭notebook的Spark环境也没有关系,只是每次需要在运行前设置环境变量。
如果你没有搭notebook的Spark环境,则需要先跑下面这段代码。当然,如果你已经搭好了,则下面这段代码不用跑了。
import os
import sys #下面这些目录都是你自己机器的Spark安装目录和Java安装目录
os.environ['SPARK_HOME'] = "C:/Tools/spark-1.6.1-bin-hadoop2.6/" sys.path.append("C:/Tools/spark-1.6.1-bin-hadoop2.6/bin")
sys.path.append("C:/Tools/spark-1.6.1-bin-hadoop2.6/python")
sys.path.append("C:/Tools/spark-1.6.1-bin-hadoop2.6/python/pyspark")
sys.path.append("C:/Tools/spark-1.6.1-bin-hadoop2.6/python/lib")
sys.path.append("C:/Tools/spark-1.6.1-bin-hadoop2.6/python/lib/pyspark.zip")
sys.path.append("C:/Tools/spark-1.6.1-bin-hadoop2.6/python/lib/py4j-0.9-src.zip")
sys.path.append("C:/Program Files (x86)/Java/jdk1.8.0_102") from pyspark import SparkContext
from pyspark import SparkConf sc = SparkContext("local","testing")
在跑算法之前,建议输出Spark Context如下,如果可以正常打印内存地址,则说明Spark的运行环境搞定了。
print sc
比如我的输出是:
<pyspark.context.SparkContext object at 0x07D9E2B0>
现在我们来用数据来跑下FP Tree算法,为了和FP Tree算法原理总结中的分析比照,我们使用和原理篇一样的数据项集,一样的支持度阈值20%,来训练数据。代码如下:
from pyspark.mllib.fpm import FPGrowth
data = [["A", "B", "C", "E", "F","O"], ["A", "C", "G"], ["E","I"], ["A", "C","D","E","G"], ["A", "C", "E","G","L"],
["E","J"],["A","B","C","E","F","P"],["A","C","D"],["A","C","E","G","M"],["A","C","E","G","N"]]
rdd = sc.parallelize(data, 2)
#支持度阈值为20%
model = FPGrowth.train(rdd, 0.2, 2)
我们接着来看看频繁项集的结果,代码如下:
sorted(model.freqItemsets().collect())
输出即为所有 满足要求的频繁项集,大家可以和原理篇里面分析时产生的频繁项集比较。代码输出如下:
[FreqItemset(items=[u'A'], freq=8),
FreqItemset(items=[u'B'], freq=2),
FreqItemset(items=[u'B', u'A'], freq=2),
FreqItemset(items=[u'B', u'C'], freq=2),
FreqItemset(items=[u'B', u'C', u'A'], freq=2),
FreqItemset(items=[u'B', u'E'], freq=2),
FreqItemset(items=[u'B', u'E', u'A'], freq=2),
FreqItemset(items=[u'B', u'E', u'C'], freq=2),
FreqItemset(items=[u'B', u'E', u'C', u'A'], freq=2),
FreqItemset(items=[u'C'], freq=8),
FreqItemset(items=[u'C', u'A'], freq=8),
FreqItemset(items=[u'D'], freq=2),
FreqItemset(items=[u'D', u'A'], freq=2),
FreqItemset(items=[u'D', u'C'], freq=2),
FreqItemset(items=[u'D', u'C', u'A'], freq=2),
FreqItemset(items=[u'E'], freq=8),
FreqItemset(items=[u'E', u'A'], freq=6),
FreqItemset(items=[u'E', u'C'], freq=6),
FreqItemset(items=[u'E', u'C', u'A'], freq=6),
FreqItemset(items=[u'F'], freq=2),
FreqItemset(items=[u'F', u'A'], freq=2),
FreqItemset(items=[u'F', u'B'], freq=2),
FreqItemset(items=[u'F', u'B', u'A'], freq=2),
FreqItemset(items=[u'F', u'B', u'C'], freq=2),
FreqItemset(items=[u'F', u'B', u'C', u'A'], freq=2),
FreqItemset(items=[u'F', u'B', u'E'], freq=2),
FreqItemset(items=[u'F', u'B', u'E', u'A'], freq=2),
FreqItemset(items=[u'F', u'B', u'E', u'C'], freq=2),
FreqItemset(items=[u'F', u'B', u'E', u'C', u'A'], freq=2),
FreqItemset(items=[u'F', u'C'], freq=2),
FreqItemset(items=[u'F', u'C', u'A'], freq=2),
FreqItemset(items=[u'F', u'E'], freq=2),
FreqItemset(items=[u'F', u'E', u'A'], freq=2),
FreqItemset(items=[u'F', u'E', u'C'], freq=2),
FreqItemset(items=[u'F', u'E', u'C', u'A'], freq=2),
FreqItemset(items=[u'G'], freq=5),
FreqItemset(items=[u'G', u'A'], freq=5),
FreqItemset(items=[u'G', u'C'], freq=5),
FreqItemset(items=[u'G', u'C', u'A'], freq=5),
FreqItemset(items=[u'G', u'E'], freq=4),
FreqItemset(items=[u'G', u'E', u'A'], freq=4),
FreqItemset(items=[u'G', u'E', u'C'], freq=4),
FreqItemset(items=[u'G', u'E', u'C', u'A'], freq=4)]
接着我们来看看使用PrefixSpan类来挖掘频繁序列。为了和PrefixSpan算法原理总结中的分析比照,我们使用和原理篇一样的数据项集,一样的支持度阈值50%,同时将最长频繁序列程度设置为4,来训练数据。代码如下:
from pyspark.mllib.fpm import PrefixSpan
data = [
[['a'],["a", "b", "c"], ["a","c"],["d"],["c", "f"]],
[["a","d"], ["c"],["b", "c"], ["a", "e"]],
[["e", "f"], ["a", "b"], ["d","f"],["c"],["b"]],
[["e"], ["g"],["a", "f"],["c"],["b"],["c"]]
]
rdd = sc.parallelize(data, 2)
model = PrefixSpan.train(rdd, 0.5,4)
我们接着来看看频繁序列的结果,代码如下:
sorted(model.freqSequences().collect())
输出即为所有满足要求的频繁序列,大家可以和原理篇里面分析时产生的频繁序列比较。代码输出如下:
[FreqSequence(sequence=[[u'a']], freq=4),
FreqSequence(sequence=[[u'a'], [u'a']], freq=2),
FreqSequence(sequence=[[u'a'], [u'b']], freq=4),
FreqSequence(sequence=[[u'a'], [u'b'], [u'a']], freq=2),
FreqSequence(sequence=[[u'a'], [u'b'], [u'c']], freq=2),
FreqSequence(sequence=[[u'a'], [u'b', u'c']], freq=2),
FreqSequence(sequence=[[u'a'], [u'b', u'c'], [u'a']], freq=2),
FreqSequence(sequence=[[u'a'], [u'c']], freq=4),
FreqSequence(sequence=[[u'a'], [u'c'], [u'a']], freq=2),
FreqSequence(sequence=[[u'a'], [u'c'], [u'b']], freq=3),
FreqSequence(sequence=[[u'a'], [u'c'], [u'c']], freq=3),
FreqSequence(sequence=[[u'a'], [u'd']], freq=2),
FreqSequence(sequence=[[u'a'], [u'd'], [u'c']], freq=2),
FreqSequence(sequence=[[u'a'], [u'f']], freq=2),
FreqSequence(sequence=[[u'b']], freq=4),
FreqSequence(sequence=[[u'b'], [u'a']], freq=2),
FreqSequence(sequence=[[u'b'], [u'c']], freq=3),
FreqSequence(sequence=[[u'b'], [u'd']], freq=2),
FreqSequence(sequence=[[u'b'], [u'd'], [u'c']], freq=2),
FreqSequence(sequence=[[u'b'], [u'f']], freq=2),
FreqSequence(sequence=[[u'b', u'a']], freq=2),
FreqSequence(sequence=[[u'b', u'a'], [u'c']], freq=2),
FreqSequence(sequence=[[u'b', u'a'], [u'd']], freq=2),
FreqSequence(sequence=[[u'b', u'a'], [u'd'], [u'c']], freq=2),
FreqSequence(sequence=[[u'b', u'a'], [u'f']], freq=2),
FreqSequence(sequence=[[u'b', u'c']], freq=2),
FreqSequence(sequence=[[u'b', u'c'], [u'a']], freq=2),
FreqSequence(sequence=[[u'c']], freq=4),
FreqSequence(sequence=[[u'c'], [u'a']], freq=2),
FreqSequence(sequence=[[u'c'], [u'b']], freq=3),
FreqSequence(sequence=[[u'c'], [u'c']], freq=3),
FreqSequence(sequence=[[u'd']], freq=3),
FreqSequence(sequence=[[u'd'], [u'b']], freq=2),
FreqSequence(sequence=[[u'd'], [u'c']], freq=3),
FreqSequence(sequence=[[u'd'], [u'c'], [u'b']], freq=2),
FreqSequence(sequence=[[u'e']], freq=3),
FreqSequence(sequence=[[u'e'], [u'a']], freq=2),
FreqSequence(sequence=[[u'e'], [u'a'], [u'b']], freq=2),
FreqSequence(sequence=[[u'e'], [u'a'], [u'c']], freq=2),
FreqSequence(sequence=[[u'e'], [u'a'], [u'c'], [u'b']], freq=2),
FreqSequence(sequence=[[u'e'], [u'b']], freq=2),
FreqSequence(sequence=[[u'e'], [u'b'], [u'c']], freq=2),
FreqSequence(sequence=[[u'e'], [u'c']], freq=2),
FreqSequence(sequence=[[u'e'], [u'c'], [u'b']], freq=2),
FreqSequence(sequence=[[u'e'], [u'f']], freq=2),
FreqSequence(sequence=[[u'e'], [u'f'], [u'b']], freq=2),
FreqSequence(sequence=[[u'e'], [u'f'], [u'c']], freq=2),
FreqSequence(sequence=[[u'e'], [u'f'], [u'c'], [u'b']], freq=2),
FreqSequence(sequence=[[u'f']], freq=3),
FreqSequence(sequence=[[u'f'], [u'b']], freq=2),
FreqSequence(sequence=[[u'f'], [u'b'], [u'c']], freq=2),
FreqSequence(sequence=[[u'f'], [u'c']], freq=2),
FreqSequence(sequence=[[u'f'], [u'c'], [u'b']], freq=2)]
在训练出模型后,我们也可以调用save方法将模型存到磁盘,然后在需要的时候通过FPGrowthModel或PrefixSpanModel将模型读出来。
以上就是用Spark学习FP Tree算法和PrefixSpan算法的所有内容,希望可以帮到大家。
(欢迎转载,转载请注明出处。欢迎沟通交流: liujianping-ok@163.com)
用Spark学习FP Tree算法和PrefixSpan算法的更多相关文章
- 强化学习中REIINFORCE算法和AC算法在算法理论和实际代码设计中的区别
背景就不介绍了,REINFORCE算法和AC算法是强化学习中基于策略这类的基础算法,这两个算法的算法描述(伪代码)参见Sutton的reinforcement introduction(2nd). A ...
- Prim算法和Kruskal算法的正确性证明
今天学习了Prim算法和Kruskal算法,因为书中只给出了算法的实现,而没有给出关于算法正确性的证明,所以尝试着给出了自己的证明.刚才看了一下<算法>一书中的相关章节,使用了切分定理来证 ...
- 使用Apriori算法和FP-growth算法进行关联分析
系列文章:<机器学习实战>学习笔记 最近看了<机器学习实战>中的第11章(使用Apriori算法进行关联分析)和第12章(使用FP-growth算法来高效发现频繁项集).正如章 ...
- mahout中kmeans算法和Canopy算法实现原理
本文讲一下mahout中kmeans算法和Canopy算法实现原理. 一. Kmeans是一个很经典的聚类算法,我想大家都非常熟悉.虽然算法较为简单,在实际应用中却可以有不错的效果:其算法原理也决定了 ...
- Prim算法和Kruskal算法
Prim算法和Kruskal算法都能从连通图找出最小生成树.区别在于Prim算法是以某个顶点出发挨个找,而Kruskal是先排序边,每次选出最短距离的边再找. 一.Prim(普里姆算法)算法: ...
- 最小生成树之Kruskal算法和Prim算法
依据图的深度优先遍历和广度优先遍历,能够用最少的边连接全部的顶点,并且不会形成回路. 这样的连接全部顶点并且路径唯一的树型结构称为生成树或扩展树.实际中.希望产生的生成树的全部边的权值和最小,称之为最 ...
- BF算法和KMP算法
这两天复习数据结构(严蔚敏版),记录第四章串中的两个重要算法,BF算法和KMP算法,博主主要学习Java,所以分析采用Java语言,后面会补上C语言的实现过程. 1.Brute-Force算法(暴力法 ...
- 最小生成树---Prim算法和Kruskal算法
Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (gra ...
- 转载:最小生成树-Prim算法和Kruskal算法
本文摘自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html 最小生成树-Prim算法和Kruskal算法 Prim算 ...
随机推荐
- mysql 触发器学习
1. 一个简单的例子 1.1. 创建表: create table t(s1 integer); 1.2. 触发器: delimiter | create trigger t_trigger befo ...
- STL中map的一个知识点
问题背景 在做USACO Section 1.1 Greedy Gift Givers的时候,我最初的想法是直接用一个map来进行数据处理.但是后来产生一个让我感到疑问的地方,后来我经过测试,发现了这 ...
- Docker 新网络 overlay 网络
Overlay网络是指在不改变现有网络基础设施的前提下,通过某种约定通信协议,把二层报文封装在IP报文之上的新的数据格式. 这样不但能够充分利用成熟的IP路由协议进程数据分发,而且在Overlay技术 ...
- iOS进阶
著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处.作者:wjh2005链接:https://www.zhihu.com/question/28518265/answer/887505 ...
- Yaf 使用遇到的坑
yaf 使用心得: 1. yaf中使用__get魔术方法后,直接导致模板不能自动渲染,需要手动指定模板 ? 1 $this->getView()->display('index/in ...
- bitmap格式分析(转)
源:bitmap格式分析 参考:bitmap图像介绍 最近正在着手开发一个图片库,也就是实现对常见图片格式的度写操作.作为总结与积累,我会把这些图片格式以及加载的实现写在我的Blog上. 说到图片,位 ...
- OSD的主要实现方法和类型(转)
源:OSD的主要实现方法和类型 目前有两种主要的OSD实现方法:外部OSD发生器与视频处理器间的叠加合成;视频处理器内部 支持OSD,直接在视频缓存内部叠加OSD信息. 外部OSD发生器与视频处理器间 ...
- Vue.js与angular在数据实现的思考
Vue.js,其简洁的API以及活跃的社区,对于打算从angular转向Vue还是挺友好的,打算最近一段时间去整理下Vue自己的一些思考,加深下对于此的印象. Vue与Angular同属于MVVM框架 ...
- Xcode6之后创建Pch预编译文件
在Xcode6之前,创建一个新工程xcode会在Supporting files文件夹下面自动创建一个“工程名-Prefix.pch”文件,也是一个头文件,pch头文件的内容能被项目中的其他所有源文件 ...
- HTML CSS基础(三)
3种列表:有序列表.无序列表和定义列表 表1 3种列表记忆 标签 语义 说明 ol ordered list 有序列表 ul unordered list 无序列表 dl definition lis ...