协同过滤算法是常见的一种推荐算法,通过分析用户历史行为和对物品的偏好,从而预测用户可能喜欢或购买的物品。协同过滤算法主要分为两部分:基于用户的协同过滤(User-Based Collaborative Filtering)和基于物品的协同过滤(Item-Based Collaborative Filtering)。
基于用户的协同过滤算法
这种算法假设用户的兴趣可以由相似兴趣的其他用户来推测出来。算法的流程主要包括以下几个步骤:
-
计算用户之间的相似度。可以使用余弦相似度、皮尔逊相关系数等指标来计算用户之间的相似度。一般来说,相似度越高的用户,则他们之间的行为和偏好也越相似。
-
找到与目标用户最相似的 K 个用户。选择其中某个相似用户 U,则将该用户对其未评分过的物品按照相似度加权求和,作为对目标用户对该物品的推荐得分。
-
针对所有未被目标用户评分的物品,计算得分并进行排序,将得分最高的多个物品推荐给目标用户。
基于物品的协同过滤算法
与基于用户的协同过滤算法类似,这种算法则假设物品之间的相似度可以用来推测用户的评分和喜好。算法的流程主要包括以下几个步骤:
-
计算物品之间的相似度。可以使用余弦相似度、改进的余弦相似度等指标来计算物品之间的相似度。
-
针对目标用户评分过的物品,找出与之相似的物品作为备选推荐物品。
-
统计所有备选推荐物品的得分和,并将得分最高的多个物品推荐给目标用户。
代码示例
下面是一个基于 Python 的用户协同过滤算法示例,假设我们有如下的用户评分矩阵:
Item 1 | Item 2 | Item 3 | Item 4 | Item 5 | |
---|---|---|---|---|---|
User 1 | 5 | 3 | 2 | ||
User 2 | 4 | 2 | 4 | ||
User 3 | 5 | 4 | 2 | 1 | |
User 4 | 2 | 1 | 5 | 4 | |
User 5 | 3 | 2 | 5 |
首先,我们定义一个函数来计算两个用户之间的相似度,这里使用皮尔逊相关系数:
from math import sqrt# 计算两个用户的皮尔逊相关系数
def pearson_correlation(user1, user2, ratings):# 找到共同评价过的物品common_items = {}for item in ratings[user1]:if item in ratings[user2]:common_items[item] = 1# 如果没有共同评价过的物品,则返回 0.0if len(common_items) == 0:return 0.0# 计算每个用户对共同评价物品的评分平均值avg1 = sum([ratings[user1][item] for item in common_items]) / float(len(common_items))avg2 = sum([ratings[user2][item] for item in common_items]) / float(len(common_items))# 计算皮尔逊相关系数numerator = sum([(ratings[user1][item]-avg1)*(ratings[user2][item]-avg2) for item in common_items])denominator = sqrt(sum([(ratings[user1][item]-avg1)**2 for item in common_items])) * sqrt(sum([(ratings[user2][item]-avg2)**2 for item in common_items]))if denominator == 0:return 0.0else:return numerator / denominator
然后,我们定义一个函数来计算某个用户与其他所有用户之间的相似度,并返回一个由相似度和用户组成的元组列表:
# 找到与指定用户最相似的 top_n 个用户
def find_similar_users(user, ratings, top_n):scores = [(pearson_correlation(user, other, ratings), other)for other in ratings if other != user]scores.sort(reverse=True) # 按照相似度从高到低排序return scores[0:top_n] # 返回 top n 个相似用户
接下来,我们可以定义一个函数来预测某个用户对某个物品的评分。这个函数会基于与该用户相似度最高的 top_n 个用户的评分来进行加权平均:
# 对指定用户未评价的所有物品进行评分预测
def predict_ratings(user, ratings, top_n):# 给出一个默认值(这里设为 3.0),表示用户没看过这部电影时的评分totals = {}sim_sums = {}for other in ratings:if other == user:continuesim = pearson_correlation(user, other, ratings)if sim <= 0: # 忽略相似度为 0 或负数的用户,避免无用计算continuefor item in ratings[other]:if item not in ratings[user] or ratings[user][item] == 0:# 只对未评价的物品进行预测totals.setdefault(item, 0)totals[item] += ratings[other][item] * simsim_sums.setdefault(item, 0)sim_sums[item] += simrankings = [(total/sim_sums[item], item) for item, total in totals.items()]rankings.sort(reverse=True) # 按照评分从高到低排序return rankings
最后,我们可以调用上述函数来为某个用户推荐电影。比如,如果要为 User 1 推荐一部电影,可以这样写:
# 假设ratings是一个由用户评分组成的字典,格式为{用户:{电影1:评分1,电影2:评分2...}}
# 获取与User 1最相似的前5个用户
similar_users = find_similar_users('User 1', ratings, 5)
# 预测User 1对电影的评分
predicted_rating = predict_ratings('User 1', ratings, similar_users)
# 推荐评分最高的电影
recommendations = sorted(predicted_rating.items(), key=lambda x: x[1], reverse=True)
# 输出推荐的电影
print(recommendations[0][0])