突发!员工跳楼!只拿低保工资!央企设计院集体罢工!

突发!北京某院集体罢工!

淄博向东,惠泊向西:在人民与人民币之间,惠泊停车选择了人民币

【少儿禁】马建《亮出你的舌苔或空空荡荡》

10部适合女性看的唯美情色电影

生成图片,分享到微信朋友圈

自由微信安卓APP发布,立即下载! | 提交文章网址
查看原文

算法告诉你,如何推荐一部电影

胡萝卜酱 DataGo数据狗 2022-07-01

上文,胡萝卜酱给大家讲述了协同过滤算法的原理,那么就来进行一次实战吧。数据集来源于

https://grouplens.org/datasets/movielens/

这里胡萝卜酱下载的是小数据集,当然你也可以下载大数据集来进行计算。


数据探索


数据解压会有四张表,这里小编只用到了“movies”和“ratings”两个表,同时通过movieId将两张表合成为一个数据框。

1import pandas as pd
2import numpy as np
3
4ratings = pd.read_csv('ml-latest-small/ratings.csv',index_col=None)
5movies = pd.read_csv('ml-latest-small/movies.csv',index_col=None)
6data = pd.merge(ratings,movies,on='movieId')
7print (data.head(10))

需要了解的是,该数据集一共有多少用户参与了多少部电影的评分,有如下代码

1#数据透视用户评分情况
2user_rating = data.pivot_table(values = 'title',index = 'userId',columns = 'rating',aggfunc = 'count')
3print (user_rating.head())
4# 计算唯一用户和电影的数量
5n_user = data.userId.unique().shape[0]
6n_movie = data.movieId.unique().shape[0]
7print('用户数量:' + str(n_user) )
8print ('电影数量' + str(n_movie))

用户数量:671,电影数量:9066


用户—评分矩阵


本文只进行基于用户的协同过滤算法的演示,所以,这里需要创建一个以用户为行,电影评分为列的二维矩阵。若是基于电影的协同过滤算法,则将矩阵进行转置即可。同时,需要将数据集分为训练集和测试集。

1# 使用scikit-learn库将数据集分割成测试和训练,本例中是0.25,
2from sklearn.model_selection import train_test_split
3train_data, test_data = train_test_split(data, test_size=0.25)
4# 第一步是创建uesr-item矩阵,此处需创建训练和测试两个UI矩阵
5movie_index = list(set(data.movieId))
6movie_index.sort()
7train_data_matrix = np.zeros((n_user, n_movie))
8#line[1]是userId,line[2]是movieId,line[3]是评分
9for line in train_data.itertuples():
10    train_data_matrix[line[1] - 1, movie_index.index(line[2])] = line[3]
11test_data_matrix = np.zeros((n_user, n_movie))
12for line in test_data.itertuples():
13    test_data_matrix[line[1] - 1, movie_index.index(line[2])] = line[3]


相似度计算


本文采取的是求余弦相似度,考虑到余弦相似度只关注方向,为考虑具体得分值,同时,考虑到用户评分偏好的不同,比如有些用户喜爱的电影给5分,不喜欢的给3分,而有的用户,喜爱的电影给4分,不喜爱的给1分。所以需要求其平均值,来进行标准化。

1#用户平均评分
2def average_rating(user):  
3    average = []
4    for i in range(user.shape[0]):
5        sum , num = 0 , 0
6        for j in range(user.shape[1]):
7            if user[i][j] != 0:
8                sum = sum + user[i][j]
9                num = num + 1
10        average.append(sum*1.0/num)
11    return average
12#标准化用户评分
13def standard(user,average):  
14    for i in range(user.shape[0]):
15        for j in range(user.shape[1]):
16            if user[i][j] != 0:
17                user[i][j] = user[i][j] - average[i]
18    return user
19train_average = average_rating(train_data_matrix)
20train_data_matrix = standard(train_data_matrix,train_average)
21
22# 使用sklearn的pairwise_distances函数来计算余弦相似性
23from sklearn.metrics.pairwise import cosine_similarity
24
25# 计算用户相似度
26user_similarity = cosine_similarity(train_data_matrix)
27
28# 计算物品相似度
29movie_similarity = cosine_similarity(train_data_matrix.T)


基于前K相似度推荐


上文一样,本文只选取前K相似度进行推荐,并把相似度作为权重,计算推荐电影评分,并基于评分,推荐前10的电影。

1from operator import itemgetter
2def getRecommendations(userid, similarity, k, user_matrix):
3    pred={}
4    average_u_rate = train_average[userid-1]
5    sim = -np.sort(-similarity[userid-1])[1:k+1#相似度排前k的值
6    index = np.argsort(-similarity[userid-1])[1:k+1#前k的索引
7    sumUserSim = 0
8    for i,j in zip(index,sim):
9        for m,n in zip(range(len(user_matrix[i])),user_matrix[i]):  
10            if n != 0 and user_matrix[userid-1][m] == 0:
11                pred.setdefault(m,0)
12                pred[m] += j*n
13        sumUserSim += j   
14    for i, rating in pred.items():  
15        pred[i] = average_u_rate + (pred[i]*1.0) / sumUserSim  
16
17    # top-10 pred  
18    pred = sorted(pred.items(), key=itemgetter(1), reverse=True)[0:10]  
19    return pred 


结果比较


假设以用户id为‘182’的用户进行推荐,并和测试集里这位用户还观看的电影进行对比,验证推荐是否有效。

1recom = getRecommendations(182, user_similarity, 20, train_data_matrix)  
2name,mark = [],[]
3for i, rating in recom:  
4    film_id = movie_index[i]
5    film_name = movies[movies['movieId'] == film_id].title.values
6    name.append(film_name)
7    mark.append(rating)
8    #print (' filmname:{}, rating: {}'.format( film_name, rating) )
9test = test_data[test_data['userId'] == 182]
10
11from pyecharts import Bar,Line,Overlap
12myBar = Bar("观看电影及评分")
13myBar.add("",test.title.values,test.rating.values)
14line = Line("推荐电影及评分")
15line.add('',name,mark)
16overlap = Overlap()
17overlap.add(myBar)
18overlap.add(line,is_add_xaxis=True)  #是否新增一个 x 坐标轴,默认为 False
19overlap.render('movie.html')

由上,我们只推荐了十部电影,这十部电影,该用户都看了。虽预测评分有偏差,但总体效果还是很不错的。


结语


这次由于采用的小数据集,所以没有考虑稀疏矩阵的问题,若矩阵过于稀疏,可以通过矩阵分解降维。


此文花费了不少功夫,赞赏、点赞、转发都是对作者的认可和支持。

文章有问题?点此查看未经处理的缓存