[转]使用Python MrJob的MapReduce实现电影推荐系统
[原文]:http://www.sobuhu.com/archives/567
最近发现一个很好玩的Python库,可以方便的使用在Python下编写MapReduce任务,直接使用Hadoop Streaming在Hadoop上跑。对于一般的Hadoop而言,如果任务需要大量的IO相关操作(如数据库查询、文件读写等),使用Python还是Java、C++,性能差别不大,而如果需要大量的数据运算,那可能Python会慢很多(语言级别上的慢),参考这里。
最常见的如日志分析、Query统计等,都可以直接用Python快速完成。
Python作为一种快速开发语言,优美、简洁的语法征服了很多人,现在很多的机器学习程序最初都是跑在Python上的(如知乎的推荐引擎),只有当规模大到一定程度才会转移到C或Java上。
本文会通过一个简单的电影推荐系统来介绍如何使用MrJOB。
首先,可能很多人对性能格外在意,可以先看这篇文章:
http://stackoverflow.com/questions/1482282/java-vs-python-on-hadoop
MrJob项目地址: https://github.com/Yelp/mrjob
MrJOB的精简介绍
这里重点在于实现电影推荐的系统,所以对于MrJob本身的介绍会比较简略,够用即可,详细说明可以看官方文档。
首先,在Python中安装mrjob后,最基本的MapReduce任务很简单:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
frommrjob.job importMRJob
importre
WORD_RE=re.compile(r"[\w']+")
classMRWordFreqCount(MRJob):
defmapper(self,_,line):
forword inWORD_RE.findall(line):
yieldword.lower(),1
defcombiner(self,word,counts):
yieldword,sum(counts)
defreducer(self,word,counts):
yieldword,sum(counts)
if__name__=='__main__':
MRWordFreqCount.run()
|
上面的代码中,有三个函数,mapper、combiner、reducer,作用和普通的Java版本相同:
- mapper用来接收每一行的数据输入,对其进行处理返回一个key-value对;
- combiner接收mapper输出的key-value对进行整合,把相同key的value作为数组输入处理后输出;
- reducer和combiner的作用完全相同,不同之处在于combiner是对于单个mapper进行处理,而reducer是对整个任务(可能有很多mapper在执行)的key-value进行处理。它以各个combiner的输出作为输入。
更为详细的介绍,如分步任务、数据初始化等可以参考其这份官方文档。
电影推荐系统
假设我们现在有一个影视网站,每一个用户可以给电影评1到5分,现在我们需要计算每两个电影之间的相似度,其过程是:
- 对于任一电影A和B,我们能找出所有同时为A和B评分过的人;
- 根据这些人的评分,构建一个基于电影A的向量和一个基于电影B的向量;
- 根据这两个向量计算他们之间的相似度;
- 当有用户看过一部电影之后,我们给他推荐与之相似度最高的另一部电影;
你可以从这里下载一些开源的电影评分数据,我们使用的是1000个用户对1700部电影进行的100000万个评分数据,下载后的数据文件夹包含一个README,里面有对各个文件的详细介绍,鉴于我们只需要(user|movie|rating)数据,所以我们用Python把这些数据进行一些处理:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
#!/usr/python/env python
if__name__=='__main__':
user_items=[]
items=[]
withopen('u.data')asf:
forline inf:
user_items.append(line.split('\t'))
withopen('u.item')asf:
forline inf:
items.append(line.split('|'))
print'user_items[0] = ',user_items[0]
print'items[0] = ',items[0]
items_hash={}
foriinitems:
items_hash[i[0]]=i[1]
print'items_hash[1] = ',items_hash['1']
forui inuser_items:
ui[1]=items_hash[ui[1]]
print'user_items[0] = ',user_items[0]
withopen('ratings.csv','w')asf:
forui inuser_items:
f.write(ui[0]+'|'+ui[1]+'|'+ui[2]+'\n')
|
处理后的数据类大约似于这样:
1
2
3
4
5
6
7
8
9
|
196|Kolya(1996)|3
186|L.A.Confidential(1997)|3
22|Heavyweights(1994)|1
244|LegendsoftheFall(1994)|2
166|JackieBrown(1997)|1
298|Dr.Strangeloveor: How I Learned to Stop Worrying and Love the Bomb (1963)|4
115|HuntforRedOctober,The(1990)|2
253|JungleBook,The(1994)|5
305|Grease(1978)|3
|
皮尔逊相关系数
判断两个向量的相似度的方式有很多种,比如测量其欧氏距离、海明距离等,这里我们用皮尔逊相关系数来计算器相关性,该系数可以理解为两个向量之间夹角的余弦值,介于-1到1之间,绝对值越大相关性越强,公式为:
第一步,我们首先对把每个用户的所有评分聚合到一起,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
#!/usr/bin/env python
# coding=utf-8
frommrjob.job importMRJob
classStep1(MRJob):
"""
第一步是聚合单个用户的下的所有评分数据
格式为:user_id, (item_count, rating_sum, [(item_id,rating)...])
"""
defgroup_by_user_rating(self,key,line):
"""
该mapper输出为:
17 70,3
35 21,1
49 19,2
49 21,1
"""
user_id,item_id,rating=line.split('|')
yielduser_id,(item_id,float(rating))
defcount_ratings_users_freq(self,user_id,values):
"""
该reducer输出为:
49 (3,7,[19,2 21,1 70,4])
"""
item_count=0
item_sum=0
final=[]
foritem_id,rating invalues:
item_count+=1
item_sum+=rating
final.append((item_id,rating))
yielduser_id,(item_count,item_sum,final)
defsteps(self):
return[self.mr(mapper=self.group_by_user_rating,
reducer=self.count_ratings_users_freq),]
if__name__=='__main__':
Step1.run()
|
使用命令 $python step1.py ratings.csv > result1.csv 获得第一步的结果。
第二步,根据第一步聚合起来的用户评分,按照皮尔逊系数算法获得任一两个电影之间的相关性,代码及注释如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
#!/usr/bin/env python
#! coding=utf-8
frommrjob.job importMRJob
fromitertoolsimportcombinations
frommathimportsqrt
classStep2(MRJob):
defpairwise_items(self,user_id,values):
'''
本mapper使用step1的输出作为输入,把user_id丢弃掉不再使用
输出结果为 (item_1,item2),(rating_1,rating_2)
这里combinations(iterable,number)的作用是求某个集合的组合,
如combinations([1,2,3,4],2)就是在集合种找出任两个数的组合。
这个mapper是整个任务的性能瓶颈,这是因为combinations函数生成的数据
比较多,这么多的零散数据依次写回磁盘,IO操作过于频繁,可以用写一个
Combiner来紧接着mapper做一些聚合操作(和Reducer相同),由Combiner
把数据写回磁盘,该Combiner也可以用C库来实现,由Python调用。
'''
# 这里由于step1是分开的,把数据dump到文件result1.csv中,所以读取的时候
# 需要按照字符串处理,如果step1和step2在同一个job内完成,则直接可以去掉
# 这一行代码,在同一个job内完成参见steps函数的使用说明。
values=eval(values.split('\t')[1])
item_count,item_sum,ratings=values
foritem1,item2 incombinations(ratings,2):
yield(item1[0],item2[0]),(item1[1],item2[1])
defcalculate_similarity(self,pair_key,lines):
'''
(Movie A,Movie B)作为Key,(A rating,B rating)作为该reducer的输入,
每一次输入属于同一个用户,所有当两个key相同时,代表他们两个都看了A和B,所以
按照这些所有都看了A、B的人的评分作为向量,计算A、B的皮尔逊系数。
'''
sum_xx,sum_xy,sum_yy,sum_x,sum_y,n=(0.0,0.0,0.0,0.0,0.0,0)
item_pair,co_ratings=pair_key,lines
item_xname,item_yname=item_pair
foritem_x,item_y inco_ratings:
sum_xx+=item_x*item_x
sum_yy+=item_y*item_y
sum_xy+=item_x*item_y
sum_y+=item_y
sum_x+=item_x
n+=1
similarity=self.normalized_correlation(n,sum_xy,sum_x,sum_y,sum_xx,sum_yy)
yield(item_xname,item_yname),(similarity,n)
defsteps(self):
return[self.mr(mapper=self.pairwise_items,
reducer=self.calculate_similarity),]
defnormalized_correlation(self,n,sum_xy,sum_x,sum_y,sum_xx,sum_yy):
numerator=(n*sum_xy-sum_x*sum_y)
denominator=sqrt(n*sum_xx-sum_x*sum_x)*sqrt(n*sum_yy-sum_y*sum_y)
similarity=numerator/denominator
returnsimilarity
if__name__=='__main__':
Step2.run()
|
使用命令 $python step2.py result1.csv > result2.csv 获得第二步的结果。
获得结果集示例:
[Movie A, Movie B] [similarity, rating count]
1
2
3
4
5
6
7
8
9
10
11
|
["Star Trek VI: The Undiscovered Country (1991)","Star Trek: Generations (1994)"] [0.31762191045234545,93]
["Star Trek VI: The Undiscovered Country (1991)","Star Trek: The Motion Picture (1979)"] [0.4632318663542742,96]
["Star Trek VI: The Undiscovered Country (1991)","Star Trek: The Wrath of Khan (1982)"] [0.44969297939248015,148]
["Star Trek VI: The Undiscovered Country (1991)","Star Wars (1977)"] [0.08625580124837125,151]
["Star Trek VI: The Undiscovered Country (1991)","Stargate (1994)"] [0.30431878197511564,94]
["Star Trek VI: The Undiscovered Country (1991)","Stars Fell on Henrietta, The (1995)"] [1.0,2]
["Star Trek VI: The Undiscovered Country (1991)","Starship Troopers (1997)"] [0.14969005091372395,59]
["Star Trek VI: The Undiscovered Country (1991)","Steal Big, Steal Little (1995)"] [0.74535599249993,5]
["Star Trek VI: The Undiscovered Country (1991)","Stealing Beauty (1996)"] [-0.4879500364742666,10]
["Star Trek VI: The Undiscovered Country (1991)","Steel (1997)"] [1.0,2]
["Star Trek VI: The Undiscovered Country (1991)","Stephen King's The Langoliers (1995)"] [-0.11470786693528087,16]
|
可以看到结果还是具有一定的实际价值的,需要注意的是,Stars Fell on Henrietta, The (1995) 这部电影是1.0,也就是完全相关,但是由于只有两个人同时对他们进行了评价,所以结果并非全都很正确,这里还要考虑多少人进行了评价。
结语
本文的内容来自于参考资料中的博客,博主仅做了整理工作,有任何问题可以和我交流。需要指出的是,类似于本文中的电影推荐仅仅是众多推荐算法中一种,可以说是对物品进行相似度判断,实际上也可以根据用户进行用户相似度判断,相似的用户总是喜欢相同的电影,这在实践中效果更好一点,也更容易根据社交关系进一步挖掘。
参考资料:http://aimotion.blogspot.com.br/2012/08/introduction-to-recommendations-with.html
转载于:https://www.cnblogs.com/naniJser/archive/2013/04/10/3013160.html
[转]使用Python MrJob的MapReduce实现电影推荐系统相关推荐
- python实现电影推荐系统_[转]使用Python MrJob的MapReduce实现电影推荐系统
最近发现一个很好玩的Python库,可以方便的使用在Python下编写MapReduce任务,直接使用Hadoop Streaming在Hadoop上跑.对于一般的Hadoop而言,如果任务需要大量的 ...
- Python+Django+Mysql实现在线电影推荐系统 基于用户、项目的协同过滤推荐在线电影系统 代码实现 源代码下载
Python+Django+Mysql实现在线电影推荐系统(基于用户.项目的协同过滤推荐算法) 一.项目简介 1.开发工具和实现技术 pycharm2020professional版本,python3 ...
- mysql项目案例电影_Python+Django+Mysql实现在线电影推荐系统 基于用户、项目的协同过滤推荐在线电影系统 代码实现 源代码下载...
Python+Django+Mysql实现在线电影推荐系统(基于用户.项目的协同过滤推荐算法) pycharm2020professional版本,python3.8版本,django3.1.1版本, ...
- hadoop调用python算法_使用Python实现Hadoop MapReduce程序
根据上面两篇文章,下面是我在自己的ubuntu上的运行过程.文字基本采用博文使用Python实现Hadoop MapReduce程序, 打字很浪费时间滴. 在这个实例中,我将会向大家介绍如何使用Py ...
- 使用Python实现Hadoop MapReduce程序
根据上面两篇文章,下面是我在自己的ubuntu上的运行过程.文字基本采用博文使用Python实现Hadoop MapReduce程序, 打字很浪费时间滴. 在这个实例中,我将会向大家介绍如何使用Py ...
- 【机器学习】使用 Python 构建电影推荐系统
本文将余弦相似度与 KNN.Seaborn.Scikit-learn 和 Pandas 结合使用,创建一个使用用户评分数据的电影推荐系统. 在日常数据挖掘工作中,除了会涉及到使用Python处理分类或 ...
- python爬电影_使用Python多线程爬虫爬取电影天堂资源
最近花些时间学习了一下Python,并写了一个多线程的爬虫程序来获取电影天堂上资源的迅雷下载地址,代码已经上传到GitHub上了,需要的同学可以自行下载.刚开始学习python希望可以获得宝贵的意见. ...
- 教你用Python 编写 Hadoop MapReduce 程序
摘要:Hadoop Streaming 使用 MapReduce 框架,该框架可用于编写应用程序来处理海量数据. 本文分享自华为云社区<Hadoop Streaming:用 Python 编写 ...
- python 爬取豆瓣top100电影页面
python 爬取豆瓣top100电影页面 运行结果截图: 代码: (原网站:https://movie.douban.com/top250) 1.将页面保存 避免多次访问 (登陆状态需页面cooki ...
最新文章
- 通信专业学python有用吗-一起学Python:网络通信过程
- 隐私设置错误您的连接不是私密连接_用小米手机的,赶紧将这些保护个人隐私的功能设置起来,安全好用...
- 初识Mysql(part7)--我需要知道的5个关于正则的小知识
- SAP Spartacus org unit页面的三种focus border及细节讨论
- nginx实现负载均衡配置
- Boost Graph
- C++ STL list的成员函数splice的使用
- 具有IDE或IDE插件的Spring Boot Initilizr
- 《疯狂Java讲义》(十八)---- JAR文件
- 数据中心运维管理经验39条
- 基于微信小程序的点餐系统设计
- matlab 矩阵白化,主成分分析中如何对矩阵进行白化处理
- git远程上传gitbub的相关问题
- wordpress 搭建的博客: 增加网站备案信息
- OneNote使用技巧 - 5.快速设置首行缩进
- AUTOSAR DCM Configuration
- 新疆大盘鸡的标准做法
- python编程阶乘_Python阶乘实现的三种方法
- Python画地图数据可视化分析
- 关于DoEvents
热门文章
- Python爬虫编程实践 Task04
- python去重排序_python读取TXT到数组及列表去重后按原来顺序排序的方法
- es文件浏览器怎么用_python爬虫入门:什么是爬虫,怎么玩爬虫?
- mysql学习day02
- java怎么限制一个对象的内存_java对象的内存布局及创建过程
- 基于人脸识别的课堂签到管理系统(三)---实时时间显示以及百度AI人脸识别
- jenkins docker 自动部署 构建_Docker_Jenkins自动部署项目
- 全球首款5G手机出炉?其实只是一个笑话
- springboot异常
- Algs4-1.2.14实现Transaction中的equals()方法