本次写的构建推荐引擎是一个晓得project,依赖于三个源文件:
find_similar_user.py pearson_score.py euclidean_score.py
以及最后的实现部分。
一个json数据文件,格式如下:
"John Carson":
{
"Inception": 2.5,
"Pulp Fiction": 3.5,
"Anger Management": 3.0,
"Fracture": 3.5,
"Serendipity": 2.5,
"Jerry Maguire": 3.0
},
"Michelle Peterson":
{
"Inception": 3.0,
"Pulp Fiction": 3.5,
"Anger Management": 1.5,
"Fracture": 5.0,
"Jerry Maguire": 3.0,
"Serendipity": 3.5
1.计算欧式距离分数
为了构建一个推荐引擎,需要定义相似度指标,以便找到与数据库中特定用户相似的用户,欧式距离分数为两个数据点之间的欧几里得距离,可以作为指标。
首先定义一个用于计算两个用户之间的欧几里得分数的函数,第一步首先判断用户是否在数据库中出现,如果没有则输出无
def euclidean_score(dataset,user1,user2):
if user1 not in dataset:
raise TypeError('User' + user1 + 'not persent in the dataset')
if user2 not in dataset:
raise TypeError('User' + user2 + 'not persent in the dataset')
为了计算分数,需要提取两个用户均评分过的电影,并赋予值1:传入用户实参,遍历这两个用户看过的所有电影,然后寻找两个用户都评分过的电影
rated_by_both = {}
for item in dataset[user1]:
if item in dataset[user2]:
rated_by_both[item]=1
如果没有两个用户共同评分过的电影,则说明这两个用户之间没有相似度,得分为0
if rated_by_both ==0:
return 0
对于每个共同评分,只计算平方和的平方根,并将该值归一化,使得评分值在0到1之间
squared_difference = []
for item in dataset[user1]:
if item in dataset[user2]:
squared_difference.append(np.square(dataset[user1][item]-dataset[user2][item]))
return 1/(1+np.sqrt(np.sum(squared_difference)))
如果评分相似,那么平方和的差别就会很小,因此评分就会变得很高
定义主函数,加载文件,传入两个随机用户计算分数
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("\nEuclidean score:")
print(euclidean_score(data,user1,user2))
2.计算皮尔逊相关系数
我们之后的推荐引擎主要用皮尔逊系数来做
首先定义一个用于计算两个用户之间皮尔逊相关度系数的函数
第一步同样是判断是都都在数据库中出现,第二部是提取两个用户均评分过的电影,此处和1计算欧几里得分数类似:
def pearson_score(dataset,user1,user2):
if user1 not in dataset:
raise TypeError('User' + user1 + 'not persent in the dataset')
if user2 not in dataset:
raise TypeError('User' + user2 + 'not persent 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)
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])
计算皮尔逊相关系数需要的各种元素并考虑坟墓为0的情况,如果正常就返回皮尔逊相关系数
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
if Sxx *Syy ==0:
return 0
定义主函数并计算两个用户之间的皮尔逊相关系数
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,user1))
3.寻找相似用户
第一步导入已有的皮尔逊函数
import json
import numpy as np
from pearson_score import pearson_score
定义一个函数,用于寻找与输入用户相似的用户,该函数有三个输入参数:数据库、输入用户和寻找的相似用户个数,首先查看该用户是否包含在数据库中,如果存在需要计算与其他所有用户的皮尔逊相关系数。
def find_similar_user(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])
将计算好的皮尔逊系数的分数按照降序排列,提取出k个最高分并返回
#将这些得分按照第二列排列
scores_sorted = np.argsort(scores[:,1])
#评分按照降序排列
scores_sorted_dec = scores_sorted[::-1]
#提取出k个最高分并返回
top_k = scores_sorted_dec[0:num_users]
return scores[top_k]
定义主函数,家在输入数据库,输入实参,定义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_user(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))
4。生成电影推荐
首先引入依赖的三个函数
import json
import numpy as np
from euclidean_score import euclidean_score
from pearson_score import pearson_score
from find_similar_user import find_similar_user
定义一个为给定用户生成电影推荐的函数,首先检查该用户是否存在于数据库中,然后计算皮尔逊系数
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 ['Not 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())
#为Michael Henry 生成推荐
user = 'Michael Henry'
print("\nRecommendations for "+user +":")
movies = generate_recommendations(data,user)
for i, movie in enumerate(movies):
print(str(i+1)+'.'+movie)
#为John Carson 生成推荐
user = 'John Carson'
print("\nRecommendations for "+user +":")
movies = generate_recommendations(data,user)
for i, movie in enumerate(movies):
print(str(i+1)+'.'+movie)
最后的总结:
这个小project用到了是皮尔逊系数和欧几里得分数的计算,然后用了一些基本的数据结构的知识,没有考虑当数据量过大的时候如何释放内存,函数还需要重构。