关注 iteblog_hadoop 公众号并在本文末评论区留言(认真写评论,增加上榜的机会)。留言点赞数排名前5名的粉丝,各免费赠送一本《Python数据分析从入门到精通》,活动截止至05月14日18:00。
下面文章节选自《Python数据分析从入门到精通》一书。
协同过滤推荐系统在我们的日常生活中无处不在。比如,在电子商城“淘宝”“京东”上购物的时候,系统会根据客户购买商品的记录或者一些其他的信息自动筛选出客户可能需要的商品,并推荐给客户;再比如,“今日头条”“搜狐”等新闻客户端也会根据客户的阅读偏好,推荐给客户可能感兴趣的信息。总之,协同过滤推荐系统已经渗透到我们日常生活的方方面面,提供了一种更加智能的生活方式。
相似度计算
协同过滤技术在推荐系统中的应用非常广泛。协同过滤有两层含义。狭义的协同过滤即基于相似用户的喜好来自动实现用户的喜好预测。这种预测方式的假设条件是:A、B两位用户对某个事物有相同的观点,那么A用户在其他事物上的观点相比于随机挑选的一个人而言会更加接近B用户。广义的协同过滤,数据来源更加广泛,这里不进行深入的讨论。之所以叫作协同过滤,是因为在实现过滤推荐的时候是根据其他人的行为来做出预测的。
实现协同过滤的第一步是如何评价两位用户之间的相似度。用一个简单的数据集来说明如何计算相似度,如表13-2所示。数据集各列表示小明、小红、小李这三位同学对《白雪公主》和《灰太狼》这两部电视剧的评分。
表13-2 数据集
《白雪公主》 | 《灰太狼》 | |
---|---|---|
小明 | 5 | 5 |
小红 | 2 | 5 |
小李 | 1 | 4 |
现在有一个任务:已知小张对《白雪公主》和《灰太狼》的评分是3分,如何来实现对小张推荐电视据?第一步是寻找小张的评分和谁最接近。在度量相似度的时候有多种方法,比较容易想到的是把上面这些数据绘制在一张二维图形上,每个点代表一位同学,用这些点之间的距离来度量相似度,如下图所示。
度量相似度
最简单的度量两个点之间的距离的方式是Manhattan距离。在这个二维的问题上,每个人在平面上用(x,y)来表示。Manhantan距离的计算公式如下:
使用这个公式来分别计算小张与其他几位同学的距离。
从上面的计算结果来看,小张和小红、小李的相似度最高。因此,如果小红还观看了《奥特曼》这部电视据,并且评分还不错,则可以把这部电视据推荐给小张。
Manhattan距离的优点在于计算迅速、节省时间。
欧式距离也是一种常用的度量相似度的方法,它用于计算两个点之间的直线距离,公式如下:
下面使用开源数据集movieLen下的movies.csv和ratings.csv数据集来介绍如何实现一个协同过滤推荐系统。首先对数据集进行预处理。使用文本编辑器建立一个名为recommend.py的文件,写入下面的代码。
1import pandas as pd
2#读取电影文本和评分文本
3movies=pd.read_csv('./movies.csv')
4ratings=pd.read_csv('./ratings.csv')
5#对读取的数据框进行相加操作,两个数据框通过“movieId”连接
6#把读取的数据写入文本中,方便后期处理
7data=pd.merge(movies,ratings,on='movieId')
8#把读取的数据写入文本中,方便后期处理
9data[['userId','rating','movieId','title']].sort_values('userId').to_csv('./data.csv',index=False)
处理后的数据集部分如下所示,各列分别表示用户ID、评分、电影的ID及电影名。整个数据集有100 004条电影的评分记录。
1userId,rating,movieId,title
21,2.5,1371,Star Trek: The Motion Picture (1979)
31,2.5,31,Dangerous Minds (1995)
41,2.0,2193,Willow (1988)
5...
该数据集和之前介绍的简单的数据集有两点不同:每位用户的特征是高维度的;各位用户评论的电影可能有交集,也可能没有交集。使用下面的代码把数据读取到Python字典中。使用文本编辑器建立一个名为to_csv.py的文件,写入下面的代码,并执行这段代码,生成一个名为data.csv的文件,后面会用到这个文件。
1#打开文件
2file=open('./data.csv')
3#读取除各列名字以外的所有数据
4data={}
5for line in file.readlines()[1:100]:
6 #使用逗号分隔字符串
7 line=line.strip().split(',')
8 #如果字典中没有某位用户,则使用用户ID来创建这位用户
9 if not line[0] in data.keys():
10 data[line[0]]={line[3]:line[1]}
11 #否则把该用户评论的电影和评分添加到以该用户ID为Key的字典中
12 else:
13 data[line[0]][line[3]]=line[1]
用Python的字典来表示每位用户评论的电影和评分。下面列出了ID为1和2的两位用户的部分评论数据在字典里的表示方法。
1{
2‘1’:{'Tron (1982)': '4.0', 'Gandhi (1982)': '2.0', 'Sleepers (1996)': '3.0', '"Gods Must Be Crazy': '3.0', 'Cinema Paradiso (Nuovo cinema Paradiso) (1989)': '4.0', '"Fly': '2.5', 'Beavis and Butt-Head Do America (1996)': '1.0', '"Deer Hunter': '2.0', 'Dangerous Minds (1995)': '2.5', '"French Connection': '4.0', 'Cape Fear (1991)': '2.0', 'Escape from New York (1981)': '2.0', 'Willow (1988)': '2.0', 'Star Trek: The Motion Picture (1979)': '2.5', 'Antz (1998)': '2.0', "Dracula (Bram Stoker's Dracula) (1992)": '3.5', 'Time Bandits (1981)': '1.0', 'Dumbo (1941)': '3.0', 'Ben-Hur (1959)': '2.0', 'Blazing Saddles (1974)': '3.0'}
3,’2’: {'Forrest Gump (1994)': '3.0', 'GoldenEye (1995)': '4.0', 'Mrs. Doubtfire (1993)': '4.0', 'Clear and Present Danger (1994)': '4.0', 'While You Were Sleeping (1995)': '3.0', 'Nine Months (1995)': '3.0', '"Madness of King George': '3.0', 'Ed Wood (1994)': '3.0', 'Little Women (1994)': '4.0', 'Braveheart (1995)': '4.0', 'Aladdin (1992)': '3.0', '"Fugitive': '3.0', "Mr. Holland's Opus (1995)": '3.0', …}
4}
下面编写代码来计算任意两位用户之间的相似度。由于每位用户评论的电影不完全一样,所以首先需要找到两位用户共同评论过的电影,然后再使用欧氏距离公式计算两位用户之间的欧氏距离,最后计算两位用户之间的相似度。
1from math import *
2def Euclidean(user1,user2):
3 #取出两位用户评论过的电影和评分
4 user1_data=data[user1]
5 user2_data=data[user2]
6 distance=0
7 #找到两位用户都评论过的电影,并计算欧式距离
8 for key in user1_data.keys():
9 if key in user2_data.keys():
10 distance+=pow(float(user1_data[key])-float(user2_data[key]),2)
11 #返回两位用户的相似度
12 #注意这里返回的值越小,表示两位用户的相似度越高;反之亦然
13return 1/(1+sqrt(distance))
代码运行结果如下图所示,1表示两位用户没有共同的评影记录,0表示两位用户相同的评影记录完全一样。
下面编写代码来计算某位用户与其他所有用户的相似度。由于数据较大,所以这里只返回相似度前10位的用户。
1def top10_sim(user):
2 res=[]
3 for userid in data.keys():
4 #排除与自己计算相似度
5 if not userid==user:
6 #计算相似度
7 sim=Euclidean_sim(user,userid)
8 #添加到列表中
9 res.append((userid,sim))
10 #返回排序后的结果
11 res.sort(key=lambda val:val[1])
12 return res[:10]
输出结果如下图所示。
活动规则
关注 iteblog_hadoop 公众号,并在评论区留言获点赞数最高前5名将赠送;《Python数据分析从入门到精通》1本,共送出5本;
活动时间:即日起至05月14日18:00点;
活动结束后,收到中奖通知的用户请在公众号私信:微信号 + 姓名 + 地址+ 电话 + 邮编;最终快递信息请到本页获取;
本活动解释权归Hadoop技术博文所有。