推荐算法--基于物品的协同过滤

基于物品的协同过滤

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. 候选物品推荐

  1. 用户最近交互的物品是abc
  2. 拿abc找出相似度最高的N个物品
  3. 使用下面公司按照最后得分排序输出

$$ 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}} $$

推荐算法

我来吐槽

*