题目:推荐/搜索算法迭代时常用离线指标评估模型效果。给定 N 个用户的真实点击列表(ground truth)和模型给出的推荐列表,实现函数 evaluate,返回 (HitRate@K, MRR)。
规则:
- 每个用户只评估模型输出的前 K 个推荐位,不足 K 个按实际长度算;
- HitRate@K = 至少命中一个真实点击项的用户数 / 总用户数;
- MRR = 各用户「第一个命中位置倒数」之和 / 总用户数,位置从 1 开始,未命中记 0;
- 真实点击为空的用户按未命中处理;用户数为 0 时返回
(0.0, 0.0)。
def evaluate(topk: list, truth: list, k: int) -> tuple:
"""
推荐系统离线评估。
:param topk: N 个用户的推荐 item 列表,如 [["a","b","c"], ["d","e","f"]]
:param truth: N 个用户的真实点击 item 列表,如 [["c","x"], ["d"]]
:param k: 只评估每个用户前 k 个推荐位
:return: (HitRate@k, MRR),均为 float;无用户时返回 (0.0, 0.0)
"""
pass
if __name__ == "__main__":
topk = [["a", "b", "c"], ["d", "e", "f"], ["x", "y", "z"]]
truth = [["c", "q"], ["d"], ["m", "n"]]
hr, mrr = evaluate(topk, truth, 3)
assert round(hr, 4) == 0.6667 # 2/3 用户命中
assert round(mrr, 4) == 0.4444 # (1/3 + 1 + 0) / 3
assert evaluate([["a", "z"]], [["z"]], 1) == (0.0, 0.0) # 命中位被 k 截断
hr, mrr = evaluate([["a", "b", "c"]], [["b"]], 3)
assert round(hr, 4) == 1.0 and round(mrr, 4) == 0.5 # 唯一命中在第 2 位
hr, mrr = evaluate([["p", "q", "r"]], [["q", "p"]], 3)
assert round(hr, 4) == 1.0 and round(mrr, 4) == 1.0 # 多命中取最靠前位置
hr, mrr = evaluate([["a"], ["b"]], [[], ["b"]], 1)
assert round(hr, 4) == 0.5 and round(mrr, 4) == 0.5 # 空真实点击按未命中算
assert evaluate([], [], 5) == (0.0, 0.0)
难度:中级
题型:笔试(编程题)