电影推荐引擎核心算法
''' 推荐引擎 (用户画像):把最需要的推荐给用户。 在不同的机器学习场景中通常需要分析相似样本。而统计相似样本的方式可以基于欧氏距离分数,也可基于皮氏距离分数。 欧氏距离分数 : 欧氏距离分数 = 1/(1+欧式距离) ----计算所得欧氏距离分数区间处于:(0, 1],越趋于0样本间的欧氏距离越远,样本越不相似; 越趋于1,样本间的欧氏距离越近,越相似。 皮尔逊相关系数: A = [1,2,3,1,2] B = [3,4,5,3,4] m = np.corrcoef(A, B) 皮尔逊相关系数 = 协方差 / 标准差之积 相关系数处于[-1, 1]区间。越靠近-1代表两组样本反相关,越靠近1代表两组样本正相关 生成推荐清单: 1.找到所有皮尔逊系数正相关的用户 2.遍历当前用户的每个相似用户,拿到相似用户看过但是当前用户没有看过的电影作为推荐电影 3.多个相似用户有可能推荐同一部电影,则取每个相似用户对该电影的评分得均值作为推荐度。 案例:解析ratings.json,根据每个用户对已观看电影的打分计算样本间的欧氏距离,输出欧氏距离得分矩阵。 ''' import json import numpy as np with open('./ml_data/ratings.json', 'r') as f: ratings = json.loads(f.read()) print(ratings) # 整理用户之的相似度得分矩阵 users, scmat = list(ratings.keys()), [] for user1 in users: scrow = [] for user2 in users: # 计算user1与user2的相似度 添加到scrow movies = set() for movie in ratings[user1]: if movie in ratings[user2]: movies.add(movie) if len(movies) == 0: score = 0 else: A, B = [], [] for movie in movies: A.append(ratings[user1][movie]) B.append(ratings[user2][movie]) A = np.array(A) B = np.array(B) # 计算A与B的相似度---欧式距离 # score = 1 / (1 + np.sqrt(((A - B) ** 2)).sum()) # 计算A与B的相似度---皮尔逊相关系数 score = np.corrcoef(A, B)[0, 1] scrow.append(score) scmat.append(scrow) users = np.array(users) scmat = np.array(scmat) for scrow in scmat: print(' '.join(['{:.2f}'.format(score) for score in scrow])) # 按照相似度从高到低排列每个用户的相似用户 for i, user in enumerate(users): # 获取所有相似用户得分,去掉自己,排序 sorted_indices = scmat[i].argsort()[::-1] sorted_indices = sorted_indices[sorted_indices != i] # 剔除自己 # user的所有相似用户 sim_users = users[sorted_indices] # user所有相似用户的相似度得分 sim_scores = scmat[i, sorted_indices] # print(user, sim_users, sim_scores, sep='\n') # 生成推荐清单 # 正相关得分的掩码 positive_mask = sim_scores > 0 # 获取所有正相关用户的用户名 sim_users = sim_users[positive_mask] # 为user构建推荐清单,找到每个sim_user看过,但是当前用户没有看过的电影,存入字典结构 # 存储推荐清单:{'电影1':[4.0,5.0],'电影2':[3.0,4.0]} reco_movies = {} for j, sim_user in enumerate(sim_users): for movie, score in ratings[sim_user].items(): # 相似用户看过但是当前用户没有看过 if movie not in ratings[user].keys(): if movie not in reco_movies: reco_movies[movie] = [score] else: reco_movies[movie].append(score) # print(user, reco_movies, sep=' ') # 对推荐清单进行排序 movie_list = sorted(reco_movies.items(), key=lambda x: np.average(x[1]), reverse=True) print(user, movie_list, sep=' ')
输出结果:
{'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}, 'William Reynolds': {'Inception': 2.5, 'Pulp Fiction': 3.0, 'Fracture': 3.5, 'Jerry Maguire': 4.0}, 'Jillian Hobart': {'Pulp Fiction': 3.5, 'Anger Management': 3.0, 'Jerry Maguire': 4.5, 'Fracture': 4.0, 'Serendipity': 2.5}, 'Melissa Jones': {'Inception': 3.0, 'Pulp Fiction': 4.0, 'Anger Management': 2.0, 'Fracture': 3.0, 'Jerry Maguire': 3.0, 'Serendipity': 2.0}, 'Alex Roberts': {'Inception': 3.0, 'Pulp Fiction': 4.0, 'Jerry Maguire': 3.0, 'Fracture': 5.0, 'Serendipity': 3.5}, 'Michael Henry': {'Pulp Fiction': 4.5, 'Serendipity': 1.0, 'Fracture': 4.0}}
1.00 0.40 0.40 0.57 0.59 0.75 0.99
0.40 1.00 0.20 0.31 0.41 0.96 0.38
0.40 0.20 1.00 1.00 -0.26 0.13 -1.00
0.57 0.31 1.00 1.00 0.57 0.03 0.89
0.59 0.41 -0.26 0.57 1.00 0.21 0.92
0.75 0.96 0.13 0.03 0.21 1.00 0.66
0.99 0.38 -1.00 0.89 0.92 0.66 1.00
John Carson []
Michelle Peterson []
William Reynolds [('Serendipity', [2.5, 2.5, 3.5, 3.5]), ('Anger Management', [3.0, 3.0, 1.5])]
Jillian Hobart [('Inception', [2.5, 3.0, 2.5, 3.0, 3.0])]
Melissa Jones []
Alex Roberts [('Anger Management', [1.5, 3.0, 2.0, 3.0])]
Michael Henry [('Jerry Maguire', [3.0, 3.0, 4.5, 3.0, 3.0]), ('Inception', [2.5, 3.0, 3.0, 3.0]), ('Anger Management', [3.0, 2.0, 3.0, 1.5])]