Python3实现基于用户的协同过滤
协同过滤是推荐系统中应用广泛的一种算法,其中基于用户的协同过滤是其中的一种常见方法。对于一个用户来说,根据他之前观看的电影或听过的歌曲,我们可以发现他喜欢哪些类型的电影或歌曲。对于相似的用户,我们可以基于他们相同或类似的偏好来推荐他们喜欢的电影或歌曲。下面是一个实现基于用户的协同过滤推荐系统的完整攻略。
数据集准备
在实现协同过滤算法之前,需要准备好一个数据集。以下是一个简单的例子,其中包含了5个用户以及他们的偏好值。
电影1 | 电影2 | 电影3 | 电影4 | 电影5 | |
---|---|---|---|---|---|
A | 5 | 3 | 2 | 4 | 1 |
B | 2 | 1 | 4 | 2 | 5 |
C | 3 | 4 | 4 | 5 | 2 |
D | 1 | 2 | 4 | 3 | 3 |
E | 4 | 5 | 1 | 2 | 1 |
计算用户之间的相似度
计算用户之间的相似度是协同过滤算法的核心。我们可以使用“皮尔逊相关系数”或“余弦相似度”等方法计算用户之间的相似度。下面我们使用余弦相似度计算用户之间的相似度。
首先,我们需要对数据进行“归一化”,将偏好值从0到1之间的值。这里我们假设每个用户的偏好值均为非负整数。对于用户A,假设他总共评价了n部电影,$p_{i, A}$表示用户A对电影i的偏好值,$w_{i,A}$表示用户A对电影i的归一化偏好值,我们可以使用下面的公式将$p_{i, A}$转换为$w_{i,A}$:
$$w_{i,A}=\frac{p_{i,A}}{\sqrt{\sum_{k=1}^np_{k,A}^2}}$$
接下来,我们可以计算用户与用户之间的余弦相似度。假设用户A和用户B分别评价了n部电影,$w_{i,A}$表示用户A给电影i的归一化偏好值,$w_{i,B}$表示用户B给电影i的归一化偏好值,$s_{A,B}$表示用户A和用户B之间的相似度,则有以下公式:
$$s_{A,B}=\frac{\sum_{i=1}^{n}w_{i,A}w_{i,B}}{\sqrt{\sum_{i=1}^{n}(w_{i,A})^2}\sqrt{\sum_{i=1}^{n}(w_{i,B})^2}}$$
通过上面的公式,我们可以计算出每对用户之间的相似度。下面是一个示例代码:
import math
def cos_sim(pref1, pref2):
"""
计算两个用户的余弦相似度
:param pref1: 用户1的偏好字典
:param pref2: 用户2的偏好字典
:return: 余弦相似度
"""
shared_items = set(pref1.keys()) & set(pref2.keys())
if len(shared_items) == 0:
return 0
# 计算偏好向量的长度
length1 = math.sqrt(sum([pow(pref1[item], 2) for item in shared_items]))
length2 = math.sqrt(sum([pow(pref2[item], 2) for item in shared_items]))
# 计算余弦相似度
dot_product = sum([pref1[item] * pref2[item] for item in shared_items])
return dot_product / (length1 * length2)
生成推荐结果
有了用户之间的相似度,我们就可以开始为每个用户生成推荐结果了。对于每个用户,我们可以找到与他相似度最高的K个用户,并从这K个用户中选出他没有评价过的电影作为推荐结果。
下面是一个示例代码:
def recommend(user, data, sim_func=cos_sim, k=3):
"""
为用户推荐电影
:param user: 用户
:param data: 数据集
:param sim_func: 相似度计算函数
:param k: 取Top K个相似用户
:return: 推荐结果
"""
scores = {}
total_sim = {}
# 遍历所有用户
for other in data.keys():
if other == user:
continue
sim = sim_func(data[user], data[other])
# 相似度小于等于0的用户不考虑
if sim <= 0:
continue
# 遍历与用户其他相似的用户
for item in data[other]:
# 如果该用户已经评价过该电影,则不考虑
if item in data[user]:
continue
# 计算评分总和和相似度总和
scores.setdefault(item, 0)
scores[item] += data[other][item] * sim
total_sim.setdefault(item, 0)
total_sim[item] += sim
# 归一化评分
rankings = [(item, round(score / total_sim[item], 2)) for item, score in scores.items()]
# 按评分从高到低排序
rankings.sort(key=lambda x: -x[1])
# 选出前k个电影作为推荐结果
return rankings[:k]
示例
下面是一个基于上述代码实现的简单示例。
data = {"A": {"电影1": 5, "电影2": 3, "电影3": 2, "电影4": 4, "电影5": 1},
"B": {"电影1": 2, "电影2": 1, "电影3": 4, "电影4": 2, "电影5": 5},
"C": {"电影1": 3, "电影2": 4, "电影3": 4, "电影4": 5, "电影5": 2},
"D": {"电影1": 1, "电影2": 2, "电影3": 4, "电影4": 3, "电影5": 3},
"E": {"电影1": 4, "电影2": 5, "电影3": 1, "电影4": 2, "电影5": 1}}
print(recommend("A", data, k=2))
# 输出 [('电影3', 0.94), ('电影2', 0.81)]
上述代码中,我们传入了数据集以及要查询的用户A,并设置了k=2,表示要返回Top2的推荐结果。程序运行后,会返回评分最高的两个电影,即“电影3”和“电影2”,以及他们的预测分值。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:python3实现基于用户的协同过滤 - Python技术站