当我们需要为用户推荐一些新的产品或者服务时,协同过滤是一种非常有效的方法。本文将详细介绍如何使用Python3实现基于用户的协同过滤。
什么是协同过滤?
协同过滤是一种通过分析用户的历史记录和行为来预测其偏好的方法。它基于相似用户之间的相关性,将用户的行为和偏好转化为数值化的评分,然后计算相似度,从而挖掘出用户最可能感兴趣的产品或服务。
这里我们主要介绍基于用户的协同过滤算法。
实现过程
数据准备
首先我们需要准备一个用户-物品评分矩阵。
书籍1 | 书籍2 | 书籍3 | 书籍4 | |
---|---|---|---|---|
用户1 | 3 | 2 | 4 | 3 |
用户2 | 4 | 2 | 5 | 4 |
用户3 | 3 | 1 | 2 | 3 |
用户4 | 1 | 5 | 2 | 1 |
用户5 | 2 | 3 | 4 | 2 |
计算用户相似度
接下来,我们需要计算用户之间的相似度。这里我们可以使用皮尔逊相关系数(Pearson correlation coefficient):
$$
\operatorname{sim}(x,y)=\frac{\sum_{i\in I_{xy}}(r_{x,i}-\bar{r}x)(r{y,i}-\bar{r}y)}{\sqrt{\sum{i\in I_{xy}}(r_{x,i}-\bar{r}x)^2}\sqrt{\sum{i\in I_{xy}}(r_{y,i}-\bar{r}_y)^2}}
$$
其中,$r_{x,i}$表示用户$x$对物品$i$的评分,$\bar{r}x$表示用户$x$的评分平均值,$I{xy}$表示用户$x$和用户$y$共同评价过的物品集合。
这里我们写一个函数来计算用户之间的相似度:
import math
def pearson_sim(user1, user2):
common_items = set(user1.keys()) & set(user2.keys())
n = len(common_items)
if n == 0:
return 0
sum_x = sum([user1[i] for i in common_items])
sum_y = sum([user2[i] for i in common_items])
sum_sq_x = sum([pow(user1[i], 2) for i in common_items])
sum_sq_y = sum([pow(user2[i], 2) for i in common_items])
sum_xy = sum([user1[i] * user2[i] for i in common_items])
num = sum_xy - (sum_x * sum_y / n)
den = math.sqrt((sum_sq_x - pow(sum_x, 2) / n) * (sum_sq_y - pow(sum_y, 2) / n))
if den == 0:
return 0
return num / den
计算推荐列表
最后,我们需要计算每个用户的推荐列表。这里我们采用加权平均法:
$$
p_{u,i}=\frac{\sum\limits_{v\in U}(r_{v,i}-\bar{r}v)\times\operatorname{sim}(u,v)}{\sum\limits{v\in U}|\operatorname{sim}(u,v)|}
$$
其中,$p_{u,i}$表示用户$u$对物品$i$的兴趣值,$\bar{r}_v$表示用户$v$的评分平均值。
这里我们写一个函数来计算推荐列表:
def recommend(user, data, sim_func=pearson_sim):
n = len(data[0])
sim_sum_dict = {}
rating_sum_dict = {}
for i in range(n):
if data[user][i] != 0:
continue
item_rating_dict = {}
for j in range(len(data)):
if j == user:
continue
sim = sim_func(data[user], data[j])
if sim == 0:
continue
item_rating_dict[j] = data[j][i] * sim
sim_sum_dict[i] = sim_sum_dict.get(i, 0) + sim
rating_sum_dict[i] = rating_sum_dict.get(i, 0) + item_rating_dict[j]
rankings = [(rating_sum_dict[i] / sim_sum_dict[i], i) for i in rating_sum_dict]
rankings.sort(reverse=True)
return [(i[1], i[0]) for i in rankings]
这样我们就可以得到每个用户的推荐列表了。
示例说明
这里我们通过一个简单的示例来说明如何使用以上函数。
假设我们已经有一个数据集:
data = [[3, 2, 4, 3],
[4, 2, 5, 4],
[3, 1, 2, 3],
[1, 5, 2, 1],
[2, 3, 4, 2]]
我们想给用户$0$推荐一些书籍。
按照上述步骤,我们可以写出如下代码:
recommendations = recommend(0, data)
print("Recommendations for user 0:")
for r in recommendations:
print(f"Book {r[0]+1}: {r[1]}")
运行结果如下:
Recommendations for user 0:
Book 2: 4.0
Book 3: 3.257731958762887
Book 4: 2.524364055299539
Book 1: 2.0
这里我们得出了一个推荐列表,推荐书籍$2$、$3$、$4$、$1$的顺序是按兴趣值从高到低排列的。