基于物品的协同过滤
Item base collaborative filtering,这个算法的核心逻辑是: 你喜欢物品A,根据其他喜欢A的用户喜欢的物品B来计算相似度,然后推荐.
ItemCF核心算法
1. 定义用户交互矩阵
U = {
"user1": {
"item1": 1,
"item2": 1,
"item3": 0,
},
"user2": {
"item1": 1,
"item2": 0,
"item3": 1,
},
"user3": {
"item1": 1,
"item2": 0,
"item3": 1,
}
}2. 计算物品相似度
实际时你应当只计算有相同交互物品的用户的其他物品相似度.
使用下面的余弦相似度公式计算:
$$ w_{ij} = \frac{C[i][j]}{\sqrt{|N(i)| \cdot |N(j)|}} $$
C[i] [j]: 物品i物品j共同交互用户数量,遍历每个用户的物品,两两配对然后加一,这就是现实了共现矩阵(统计两个或多个元素在特定上下文内同时出现频率的二维矩阵)
|N(i)|和物品i有交互的用户总数,|N(j)|一样.
# 实现共现矩阵
collective_matrix = {}
# 物品被操作计次
item_operate = {son_name: 0 for _,item in U.items() for son_name in item.keys()}
for index, v in U.items():
for ci,item in enumerate(v.keys()):
if ci == len(v.keys())-1:
break
collective_matrix[item] = {name: 0 for name in v.keys()}
break
for pk in U.keys():
for item in U[pk].keys():
if U[pk][item] != 0:
item_operate[item] +=1
for name,v in U.items():
# 获取item长度
l = len(v)
# 获取所有key
all_keys = list(v.keys())
for i in range(l):
# 如果用户没有交互此物品,跳过
if v[all_keys[i]] == 0:
continue
# user交互的物品总数减去已经遍历过的物品数
for j in range(l-i-1):
if v[all_keys[i]] == v[all_keys[i+j+1]]:
collective_matrix[all_keys[i]][all_keys[i+j+1]] += 1
# 输出
print(collective_matrix)
print(item_operate)
# 计算两个物品的相似度
similar_dict = {}
for item_parent in collective_matrix.keys():
for son_key in (collective_matrix[item_parent]).keys():
# 默认没有C[i][i]这种情况
if son_key is item_parent:
continue
# 如果没有人交互i和j两个物品,跳过
if collective_matrix[item_parent][son_key] == 0:
continue
# 开始计算不同物品的相似度
if item_parent not in similar_dict:
similar_dict[item_parent] = {}
similar_dict[item_parent] |= {
son_key: collective_matrix[item_parent][son_key]/math.sqrt(item_operate[item_parent] * item_operate[son_key])
}
print(similar_dict)
# 输出
{'item1': {'item1': 0, 'item2': 1, 'item3': 2}, 'item2': {'item1': 0, 'item2': 0, 'item3': 0}}
{'item1': 3, 'item2': 1, 'item3': 2}
{'item1': {'item2': 0.5773502691896258, 'item3': 0.8164965809277261}}用余弦相似度公式再次确认是否正确:
$$ w_{ij} = \frac{1}{\sqrt{3 \cdot 1}} \approx 0.577 $$
分子C[i] [j]取值为 1, 分母中 |N(i)| =3, |N(j)| =1. 算出item1和2的结果正确
3. 候选物品推荐
- 用户最近交互的物品是abc
- 拿abc找出相似度最高的N个物品
- 使用下面公司按照最后得分排序输出
$$ p(u, i) = \sum_{j \in N(u)} w_{ij} \cdot r_{uj} $$
- sigma(Σ)是表示求和.
- N(u)代表用户交互过的所有物品.
- wij表示物品相似度.
- ruj为用户u对物品j的的兴趣强度或者权重,可以为0
这里假设ruj为1, u为user1, 感兴趣物品(i)为item3,上面公式计算示例: p(user1,3) = w13 1 + w23 1 = 0.816
这里只有item1和item3有共同交互用户,所以其实可以直接得出0.816
皮尔逊相关系数算法
余弦相似度适用于隐式反馈场景(如点击、浏览),但在某些应用中我们还有显式评分数据(如5星评分、点赞数等)。对于这类数据,可以使用更精细的相似度计算方法。
$$ w_{ij} = \frac{\sum_{u \in U_{ij}}(r_{ui} - \bar{r}_i)(r_{uj} - \bar{r}_j)}{\sqrt{\sum_{u \in U_{ij}}(r_{ui} - \bar{r}_i)^2}\sqrt{\sum_{u \in U_{ij}}(r_{uj} - \bar{r}_j)^2}} $$
- uij表示同时评分过i和j的用户集合
- rui表示用户u对i的评分
- -ri是物品i的平均评分
基于皮尔逊系数可以预测未接触物品的评分
$$ \hat{r}_{u,j} = \bar{r}_{j} + \frac{\sum_{k \in S_j} w_{jk}\,\left( r_{u,k} - \bar{r}_{k} \right)}{\sum_{k \in S_j} w_{jk}} $$