构建电影推荐引擎
简介
推荐引擎是一个能预测用户兴趣点的模型。将推荐引擎应用于电影语境时,便成了一个电影 推荐引擎。我们通过预测当前用户可能会喜欢的内容,将相应的东西从数据库中筛选出来,这样的推荐引擎可以有助于将用户和数据集中的合适内容连接起来。
为什么推荐引擎这么重要?设想 你有一个很庞大的商品目录,而用户可能或者不可能查找所有的相关内容。通过推荐合适的内容, 可以增加用户消费。
推荐引擎通常用协同过滤(collaborative filtering)或基于内容的过滤(content-based filtering)来产生一组推荐。两种过滤方法的不同之处在于挖掘推荐的方式。协同过滤从当前用户过去的行 为和其他用户对当前用户的评分来构建模型,然后使用这个模型来预测这个用户可能感兴趣的内容;而基于内容的过滤用商品本身的特征来给用户推荐更多的商品,商品间的相似度是模型主要的关注点。本章将重点介绍协同过滤。
主要步骤
编写一个程序用来计算欧式距离分数
# 创建一个Python文件,导入以下程序包:
import json
import numpy as np
# 计算user1和user2的欧氏距离分数,第一步先判断用户是否在数据
# 库中出现:
def euclidean_score(dataset, user1, user2):
if user1 not in dataset:
raise TypeError('User ' + user1 + ' not present in the dataset')
if user2 not in dataset:
raise TypeError('User ' + user2 + ' not present in the dataset')
# 提取两个用户均评过分的电影
rated_by_both = {}
for item in dataset[user1]:
if item in dataset[user2]:
rated_by_both[item] = 1
# 如果两个用户都没评分过,得分为0,则说明这两个用户之间没有相似度
if len(rated_by_both) == 0:
return 0
# 对于每个共同评分,只计算平方和的平方根,并将该值归一化,使得评分取值在0到1之间:
squared_differences = []
for item in dataset[user1]:
if item in dataset[user2]:
squared_differences.append(np.square(dataset[user1][item] - dataset[user2][item]))
return 1 / (1 + np.sqrt(np.sum(squared_differences)))
# 如果评分相似,那么平方和的差别就会很小,因此评分就会变得很高,这也是我们希望指标
# 达到的效果。
# if __name__ == '__main__':
# # 加载数据文件中的movie_ratings.json文件:
# data_file = 'movie_ratings.json'
#
# with open(data_file, 'r') as f:
# data = json.loads(f.read())
#
# # 假定两个随机用户,计算其欧氏距离分数:
# user1 = 'John Carson'
# user2 = 'Michelle Peterson'
#
# # 运行该代码,可以看到欧氏距离分数显示在命令行工具中
# print("\nEuclidean score:")
# print(euclidean_score(data, user1, user2))
编写一个程序用来计算皮尔逊相关系数
import numpy as np
# 计算user1和user2的皮尔逊相关系数
def pearson_score(dataset, user1, user2):
if user1 not in dataset:
raise TypeError('User ' + user1 + ' not present in the dataset')
if user2 not in dataset:
raise TypeError('User ' + user2 + ' not present in the dataset')
# 提取两个用户均评过分的电影
rated_by_both = {}
for item in dataset[user1]:
if item in dataset[user2]:
rated_by_both[item] = 1
num_ratings = len(rated_by_both)
# 如果两个用户都没有评分,得分为0
if num_ratings == 0:
return 0
# 计算相同评分电影的平方值之和
user1_sum = np.sum([dataset[user1][item] for item in rated_by_both])
user2_sum = np.sum([dataset[user2][item] for item in rated_by_both])
# 计算所有相同评分电影的评分的平方和
user1_squared_sum = np.sum([np.square(dataset[user1][item]) for item in rated_by_both])
user2_squared_sum = np.sum([np.square(dataset[user2][item]) for item in rated_by_both])
# 计算数据集的乘积之和
product_sum = np.sum([dataset[user1][item] * dataset[user2][item] for item in rated_by_both])
# 计算皮尔逊相关度
Sxy = product_sum - (user1_sum * user2_sum / num_ratings)
Sxx = user1_squared_sum - np.square(user1_sum) / num_ratings
Syy = user2_squared_sum - np.square(user2_sum) / num_ratings
# 考虑分母为0的情况:
if Sxx * Syy == 0:
return 0
# 如果一切正常,返回皮尔逊相关系数:
return Sxy / np.sqrt(Sxx * Syy)
# 定义main函数并计算两个用户之间的皮尔逊相关系数
# if __name__ == '__main__':
# data_file = 'movie_ratings.json'
#
# with open(data_file, 'r') as f:
# data = json.loads(f.read())
#
# user1 = 'John Carson'
# user2 = 'Michelle Peterson'
#
# print("\nPearson score:")
# print(pearson_score(data, user1, user2))
编写一个程序用来寻找数据集中的相似用户
# import json
import numpy as np
from TestsOfPythonBook.Chapter05.movie_recomm.pearson_score import pearson_score
# 寻找特定数量的与输入用户相似的用户
def find_similar_users(dataset, user, num_users):
if user not in dataset:
raise TypeError('User ' + user + ' not present in the dataset')
# 计算所有用户的皮尔逊相关度
scores = np.array([[x, pearson_score(dataset, user, x)] for x in dataset if user != x])
# 评分按照第二列排序
scores_sorted = np.argsort(scores[:, 1])
# 评分按照降序排列
scored_sorted_dec = scores_sorted[::-1]
# 提取出k个最高分
top_k = scored_sorted_dec[0:num_users]
return scores[top_k]
# if __name__=='__main__':
# data_file = 'movie_ratings.json'
#
# with open(data_file, 'r') as f:
# data = json.loads(f.read())
#
# user = 'John Carson'
# print("\nUsers similar to " + user + ":\n")
# similar_users = find_similar_users(data, user, 3)
# print("User\t\t\tSimilarity score\n")
# for item in similar_users:
# print(item[0], '\t\t', round(float(item[1]), 2))
结合上述三个程序构建电影推荐引擎
import json
import numpy as np
from TestsOfPythonBook.Chapter05.movie_recomm.pearson_score import pearson_score
# 为给定用户生成电影推荐
def generate_recommendations(dataset, user):
if user not in dataset:
raise TypeError('User ' + user + ' not present in the dataset')
# 计算该用户与数据库中其他用户的皮尔逊相关系数:
total_scores = {}
similarity_sums = {}
for u in [x for x in dataset if x != user]:
similarity_score = pearson_score(dataset, user, u)
if similarity_score <= 0:
continue
# 找到还未被该用户评分的电影
for item in [x for x in dataset[u] if x not in dataset[user] or dataset[user][x] == 0]:
total_scores.update({item: dataset[u][item] * similarity_score})
similarity_sums.update({item: similarity_score})
# 如果该用户看过数据库中所有的电影,那就不能为用户推荐电影。对该条件做如下处理:
if len(total_scores) == 0:
return ['No recommendations possible']
# 生成一个电影评分标准化列表
movie_ranks = np.array([[total / similarity_sums[item], item]
for item, total in total_scores.items()])
# 根据第一列对皮尔逊相关系数进行降序排列
movie_ranks = movie_ranks[np.argsort(movie_ranks[:, 0])[::-1]]
# 提取出推荐的电影
recommendations = [movie for _, movie in movie_ranks]
return recommendations
if __name__ == '__main__':
data_file = 'movie_ratings.json'
with open(data_file, 'r') as f:
data = json.loads(f.read())
user = 'Michael Henry'
print("\nRecommendations for " + user + ":")
movies = generate_recommendations(data, user)
for i, movie in enumerate(movies):
print(str(i + 1) + '. ' + movie)
user = 'John Carson'
print("\nRecommendations for " + user + ":")
movies = generate_recommendations(data, user)
for i, movie in enumerate(movies):
print(str(i + 1) + '. ' + movie)
源代码+数据集
链接:https://pan.baidu.com/s/1rQRPW9zX4v7J3wBMwYE0Ug
提取码:na93
复制这段内容后打开百度网盘手机App,操作更方便哦
实验结果
结果分析
在为Michael Henry生成推荐时,通过计算皮尔逊系数,根据相关性进行排序,最终返回3个相关性最高的电影。
用户John Carson看过所有电影,因此在为他推荐电影时,应该显示0推荐。