推荐算法实践:UserCF计算召回率

71 阅读2分钟

1. 加载数据

  • test_user_items.json加载测试集数据,其中包含每个用户在测试集上交互的物品。
  • train_user_items.json加载训练集数据,其中包含每个用户在训练集上交互的物品。
  • user_simscore.json加载用户之间的相似度分数。

2. 获取推荐物品

  • 定义函数get_items_by_sim_user(ui, top_n=10),为用户ui生成推荐物品。
    • 获取与用户ui最相似的用户及其相似度分数。
    • 获取用户ui已经交互过的物品,避免推荐已知的物品。
    • 计算相似用户交互过的物品的推荐分数,公式为: 推荐分数=相似度×评分
    • 对推荐分数进行排序,返回分数最高的top_n个物品。

3. 计算召回率

  • 对每个用户,获取其在测试集上的物品集合test_items
  • 获取推荐系统为该用户推荐的物品集合recall_items
  • 计算推荐物品与测试集物品的交集大小,并除以测试集物品的总数,得到该用户的召回率。
  • 对所有用户的召回率求平均,得到整个推荐系统的召回率。

4. 实现逻辑

import json
from collections import defaultdict

with open('test_user_items.json', 'r') as f:
    test_user_items = json.load(f)

with open('train_user_items.json', 'r') as f:
    train_user_items = json.load(f)

with open('user_simscore.json', 'r') as f:
    user_simscore = json.load(f)

def get_items_by_sim_user(ui, top_n=10):
    # 获取用户相似用户
    ux_simscores = user_simscore.get(ui, [])
    # 获取用户历史交互过的商品,已交互过的商品不再推荐,作为过滤使用
    ui_items = train_user_items.get(ui, [])
    ui_items = set(map(lambda x : x[0], ui_items))
    
    item_score = defaultdict(float)
    # 遍历相似用户以及相似用户交互过的商品
    for uj, sim_score in ux_simscores:
        # 相似用户交互过的商品作为推荐商品
        uj_items = train_user_items.get(uj, [])
        # 计算推荐分数
        for item, rate, _ in uj_items:
            if item in ui_items:
                continue
            item_score[item] += rate * sim_score
    if not item_score:
        return None

    item_score = sorted(item_score.items(), key=lambda x: x[1], reverse=True)
    return  set(item[0] for item in item_score[:top_n])

all_users = set(test_user_items.keys())
total_recall = 0.0

for user in all_users:
    test_items = test_user_items.get(user, None)
    if not test_items:
        continue  # 跳过测试集中没有物品的用户
    test_items = set(map(lambda x : x[0], test_items))
    recall_items = get_items_by_sim_user(user, top_n=100)
    if not recall_items:
        continue
    recall_count = len(recall_items & test_items)
    total_recall += recall_count / len(test_items)

average_recall = total_recall / len(all_users)
print(f"Average Recall: {average_recall}")

最终召回率为0.28802590474991013