算法介绍
1.推荐算法分类
1.1协同过滤推荐算法
协同过滤推荐算法是一种常用的推荐系统算法,它基于用户行为数据(比如用户对商品的评分、点击、购买等行为)来发现用户之间的相似性,进而推荐给用户他们可能感兴趣的物品。协同过滤算法通常分为两类:基于用户的协同过滤和基于物品的协同过滤。
-
基于用户的协同过滤: 基于用户的协同过滤算法是通过计算用户之间的相似度来进行推荐。算法步骤如下:
- 计算用户相似度:通过计算用户之间的行为数据来计算用户之间的相似度,比如使用皮尔逊相关系数、余弦相似度等方法。本案例中使用欧氏距离表示相似度。
- 预测用户评分:对于目标用户未评分的物品,通过与相似用户的评分数据进行加权平均或其他算法来预测目标用户对物品的评分。
- 推荐Top-N物品:根据预测的评分值或其他排序指标为用户推荐Top-N的物品。
-
基于物品的协同过滤: 基于物品的协同过滤算法是通过计算物品之间的相似度来进行推荐。算法步骤如下:
- 计算物品相似度:通过计算物品之间的行为数据来计算物品之间的相似度,比如使用余弦相似度、Jaccard 相似度等方法。
- 预测用户评分:对于目标用户未评分的物品,通过与用户已评分的物品的相似度加权来预测用户对物品的评分。
- 推荐Top-N物品:根据预测的评分值或其他排序指标为用户推荐Top-N的物品。
协同过滤推荐算法的优点是能够根据用户行为数据动态地为用户推荐个性化的物品,但也存在一些问题,如冷启动问题(对于新用户或新物品的推荐困难)、数据稀疏问题(用户行为数据稀疏导致推荐精度下降)等。因此,在实际应用中,通常需要结合其他推荐算法或技术来提高推荐系统的性能。
1.2基于内容推荐算法
基于内容推荐算法是一种常用于推荐系统中的算法,它根据物品(如文章、音乐、电影等)的内容特征,来推荐与用户喜好相关的物品。该算法通过分析物品本身的特征和用户的历史行为数据,为用户推荐他们可能感兴趣的物品。
基于内容推荐算法的核心思想是通过计算物品之间的相似度,并根据用户对物品的喜好以及物品之间的相似度来进行推荐。具体来说,该算法会首先对每个物品进行特征提取,然后计算物品之间的相似度,最后根据用户的历史偏好和相似度来推荐新的物品。
基于内容推荐算法的优点包括推荐结果具有解释性、不需要用户的历史行为数据等优点。然而,该算法也存在着无法发现用户的潜在兴趣、易受特征表示质量影响等局限性。
基于内容推荐算法在推荐系统中有着广泛的应用,例如在新闻推荐、音乐推荐、电影推荐等领域。通过分析物品的内容特征,可以更好地为用户提供个性化的推荐服务。
1.3关联规则推荐算法
关联规则推荐算法是一种常用于推荐系统的算法,它主要用于发现物品之间的相关性和关联规则,从而为用户做出推荐。该算法基于用户购买历史或行为数据,通过分析物品之间的关联规则,来发现用户可能感兴趣的物品组合。
关联规则推荐算法的核心思想是在用户历史数据中发现物品之间的频繁关联规则,即哪些物品经常同时出现在用户的购买或浏览历史中。这些关联规则可以帮助系统预测用户的兴趣和行为,进而向用户推荐相关的物品。
关联规则推荐算法的一个经典应用是购物篮分析,例如在电商网站中根据用户购买商品的历史数据,发现买了A商品的用户更容易购买B商品,从而向用户推荐B商品。
关联规则推荐算法的优点包括简单易懂、快速计算等特点。然而,该算法也存在着忽略物品之间的顺序信息、易受数据稀疏性影响等局限性。
在实际应用中,关联规则推荐算法通常与其他推荐算法结合使用,以提高推荐系统的精确度和多样性。通过发现物品之间的关联规则,推荐系统可以更准确地为用户推荐个性化的物品。
2.欧氏距离
欧氏距离是欧几里得空间中两点之间的直线距离,也是最常用的距离度量方式之一。在二维平面上,两点 ( P(x_1, y_1) ) 和 ( Q(x_2, y_2) ) 之间的欧氏距离可以通过以下公式计算:
[ d(P, Q) = \sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2} ]
在更高维的空间中,欧氏距离的计算方式类似,只是需要将坐标差的平方和进行累加,然后取平方根。
3.计算两个用户之间的相似度
任何两个用户之间的相似度,都是基于他们都看过目评分过的电影来判断的。由于每个用户评分的电影不完全一样,因此先要找到两个用户共同评分过的电影,然后计算两者之间的相似度,此处用欧氏距离来表示相似度。首先获取用户1和用户2的电影评分信息,然后依次获取用户1评分过的电影标题,再判断用户2是否也评分过此电影,如果条件成立,则计算两者的相似度。因为不同的用户评分过的电影数量不尽相同,所以取评分差距的平均值作为用户相似度计算标准。如果用户没有对共同的电影进行评分,就认为彼此相似度为-1;如果他们所有共同爱好的电影的评分完全一样,那么相似度为1。
4.找到与某个用户最相似的前n个用户
有了相似度计算方法,就可以利用sim_Euclidean 函数找到与指定用户最相似最近邻的前n个用户(默认为10),首先遍历所有的用户;再辨别如果不是指定用户本人,则计算彼此之间的相似度;计算完所有相似度后,按相似度值进行降序排列,最后返回前n个最相似的用户数据。
5.给某个用户推荐前m部电影
根据前面的计算,已经找到与某用户最相似的n个用户下面只要找出这n个用户看过、但该用户没有看过的电影集,然后按评分的高到低排序,推荐前m部电影给该用户即可。
5.1找出最近邻用户看过的但该用户没有看过的 m 部电影
定义一个函数recommend_flms,来向用户推荐他最近邻n个用户最喜欢的前m部电影(默认是10个最近邻,推荐10部电影),首先找出指定用户的前n个最相似用户;然后遍历这n个用户;再获取每个最近邻用户评分过的所有电影,再遍历这些电影;接着判断指定用户是否没看过该电影,如果条件成立,则把没看过的电影保存到列表变量recommendations中;在整个遍历结束后,返回评分靠前的m部电影的标题及评分。
源代码
'''
任务1——合并电影基本信息和评分记录
'''
import pandas as pd
from math import *
movies = pd.read_csv(r'D:/Python/chapter6/data/movies.csv')
ratings = pd.read_csv(r'D:/Python/chapter6/data/ratings.csv')
data = pd.merge(movies, ratings, on='movieId')
data=data[['userId', 'rating', 'movieId', 'title']].sort_values('userId')
'''
任务2——找到与某个用户最相似的n个用户
'''
#统计各用户评论的电影和评分
datas = {}
for index,line in data.iterrows():
if not line['userId'] in datas.keys():
datas[line[0]] = {line[3]: line[1]}
else:
datas[line[0]][line[3]] = line[1]
def sim_Euclidean(userId1, userId2):
user1_data = datas[userId1]
user2_data = datas[userId2]
distance = 0
count=0
flag=False
for key in user1_data.keys():
if key in user2_data.keys():
flag=True
distance += pow(float(user1_data[key]) - float(user2_data[key]), 2)
count+=1
if flag:
return (1/(1 + sqrt(distance)/count))
else:
return -1
#计算与用户userId相似度最大的前n个用户
def top10_simliar(userId,n=10):
result = []
for user_Id in datas.keys():
if not user_Id == userId:
simliar = sim_Euclidean(userId, user_Id)
result.append((user_Id, simliar))
result.sort(key=lambda val: val[1],reverse=True)
return result[0:n]
users = top10_simliar(1,10)
print(users)
'''
任务3——给某个用户推荐前m部电影
'''
def recommend_films(userId,n=10,m=10):
top_sim_user_list = top10_simliar(userId,n)
users = []
for res in top_sim_user_list:
users.append(res[0])
recommendations = []
for user_id in users:
items = datas[user_id]
for item in items.keys():
if item not in datas[userId].keys():
recommendations.append((item, items[item]))
recommendations.sort(key=lambda val: val[1], reverse=True)
return recommendations[0:m]
recommend_top10films=recommend_films(2,m=8)
for item,rating in recommend_top10films:
print('{:50}{}'.format(item,rating))