📑 本页目录(点开跳转)
11 · 重排与多样性
⏱ 20 分钟 | ⭐ 核心
🎯 一句话
精排告诉你「每个物品单独有多好」,但用户看到的是一个列表。 重排解决的是:「这十个放在一起,好不好?」
💥 问题:为什么「每个都最好」≠「列表最好」
精排的输出(按分数排):
1. 篮球集锦 0.92
2. 篮球教学 0.91
3. 篮球比赛 0.90
4. 篮球新闻 0.89
5. 篮球鞋测评 0.88
...
10. 篮球训练 0.83
😐 用户的感受:「怎么全是篮球?我又不是只看篮球」
→ 划走、退出、明天不来了
三个具体的伤害:
| 问题 | 后果 |
|---|---|
| 边际效用递减 | 第 5 个篮球视频的价值远低于第 1 个 |
| 兴趣覆盖不足 | 用户还有其他兴趣没被满足 |
| 无法探索 | 系统永远学不到用户的新兴趣 → 越推越窄 |
🔑 核心命题:准确性 vs 多样性的权衡(Accuracy-Diversity Tradeoff) 这是推荐系统里没有标准答案、必须靠 A/B 实验定夺的经典权衡。
🧰 重排要做的事(一张清单)
精排给了 50 个候选,重排要在 10ms 内做完这些:
【硬性过滤】必须做,不然出事故
☐ 已读/已购去重
☐ 黑名单、违规内容过滤
☐ 频次控制(同一物品一天最多曝光 3 次)
☐ 用户主动屏蔽的作者/话题
【多样性】
☐ 类目打散(不能连续 3 个同类目)
☐ 作者打散(同一作者一屏最多 2 条)
☐ 内容相似度打散(标题/封面太像的分开)
【业务规则】
☐ 广告插入(第 4、12、20 位)
☐ 运营位强插
☐ 新内容/新作者流量扶持(生态调控)
☐ 时效性内容加权(突发新闻)
【体验优化】
☐ 首位保护(第 1 个必须是高置信度的)
☐ 避免开头连续低质
⚙️ 多样性算法一:MMR(最简单,最常用)
Maximal Marginal Relevance —— 边选边看「和已选的重不重」。
$$\text{MMR} = \arg\max_{i \in R \setminus S} \left[ \lambda \cdot \text{rel}(i) - (1-\lambda) \cdot \max_{j \in S} \text{sim}(i, j) \right]$$
💡 人话翻译:
每次挑下一个时,算两笔账: 加分 = 它本身有多好(精排分) 扣分 = 它和已经选中的东西有多像
λ是旋钮:λ=1 完全不管多样性,λ=0 只管多样性。实践中 0.7–0.9 常见。
import numpy as np
def mmr(scores, sim_matrix, k=10, lam=0.8):
"""
scores: (N,) 精排分数
sim_matrix: (N,N) 物品两两相似度
lam: 0~1,越大越看重相关性
"""
selected = []
candidates = list(range(len(scores)))
for _ in range(k):
best, best_val = None, -np.inf
for i in candidates:
if not selected:
val = scores[i]
else:
redundancy = max(sim_matrix[i][j] for j in selected)
val = lam * scores[i] - (1 - lam) * redundancy
if val > best_val:
best, best_val = i, val
selected.append(best)
candidates.remove(best)
return selected
优点:简单、快、可解释、λ 一个旋钮可调。 缺点:贪心策略,只看「和最像的那个有多像」,不看整体分布。
⚙️ 多样性算法二:DPP(更强,工业界在用)
Determinantal Point Process(行列式点过程) —— 数学上更优雅。
核心直觉:把每个物品看成一个向量,一组物品的「多样性」= 它们张成的空间体积。
两个向量很像(夹角小) 两个向量不像(接近垂直)
↗ ↗ ↑
/ / │ →
/__/ └────
面积小 → 多样性低 面积大 → 多样性高
数学上,这个「体积」就是核矩阵的行列式。DPP 的目标:
$$\max_{S} \det(L_S), \quad L_{ij} = \underbrace{q_i q_j}_{\text{质量}} \cdot \underbrace{\langle \phi_i, \phi_j\rangle}_{\text{相似度}}$$
💡 人话:「既要每个都好(q 大),又要它们互相不像(行列式大)」——两个目标被一个行列式统一了。
实践:用贪心 MAP 近似(Chen et al. 2018 的快速算法),复杂度 O(k²N),能在 10ms 内跑完几百个候选。
📌 快手、YouTube 等都公开发表过 DPP 在重排中的应用。这是目前多样性的工业标准解法之一。
⚙️ 多样性算法三:打散规则(最土,但最有效)
别小看规则。很多公司的重排 80% 是规则。
def scatter(items, key_fn, min_gap=3, max_per_window=2, window=5):
"""
通用打散:保证同一 key(类目/作者)的物品不要太密集
这段逻辑的变体在几乎所有推荐系统里都存在
"""
result, pool = [], list(items)
while pool:
placed = False
for idx, item in enumerate(pool):
k = key_fn(item)
# 检查1:最近 min_gap 个里有没有同 key 的
recent = [key_fn(x) for x in result[-min_gap:]]
# 检查2:最近 window 个里同 key 的数量
win = [key_fn(x) for x in result[-window:]]
if k not in recent and win.count(k) < max_per_window:
result.append(pool.pop(idx))
placed = True
break
if not placed: # 打散不了就按原序放,别死循环
result.append(pool.pop(0))
return result
⚠️ 打散的隐藏代价:把高分物品往后挪 = 牺牲了短期 CTR。 必须用 A/B 实验验证长期留存是否上升,否则你只是在无谓地降低指标。
🤖 现代做法:让模型学重排
PRM(Personalized Re-ranking,阿里 2019)
思想:用 Transformer 处理整个候选列表,让每个物品「看到」其他物品。
精排输出的 50 个候选 ↓
- 每个物品能 attend 到所有其他物品
它能学到什么规则学不到的: - 「这个物品排在一堆同类里会被淹没,单独出现效果好」 - 「A 和 B 放一起有互补效应,用户更容易连着看」
生成式重排
不是「打分再排序」,而是直接生成一个序列,用一个 Evaluator 评估「整个列表的期望收益」。 代表:Seq2Slate、GRN、PIER。
📏 多样性怎么量化
| 指标 | 定义 | 怎么用 |
|---|---|---|
| Intra-List Diversity (ILD) | 列表内两两不相似度的平均 | 最常用 |
| Coverage | 推荐结果覆盖了多少比例的物品库 | 看长尾是否被挖掘 |
| Gini / Entropy | 曝光分布的不平等程度 | 看是否被爆款垄断 |
| Category Count | 一屏内出现几个不同类目 | 最直观,产品经理能懂 ⭐ |
| Serendipity(惊喜度) | 推荐的东西「意外但相关」的程度 | 难量化,但最贴近用户感受 |
| Novelty(新颖度) | 推荐物品的平均流行度(越低越新颖) | 反热门偏置 |
def intra_list_diversity(item_vecs):
"""ILD:列表内两两余弦距离的平均"""
n = len(item_vecs)
if n < 2: return 0.0
v = item_vecs / (np.linalg.norm(item_vecs, axis=1, keepdims=True) + 1e-9)
sim = v @ v.T
# 只取上三角(不含对角)
iu = np.triu_indices(n, k=1)
return float(1 - sim[iu].mean())
⚖️ 一个必须理解的现实:多样性是「长期指标」
上线多样性策略后的典型曲线:
CTR
▲
│ ─────╲
│ ╲___________________ ← 短期 CTR 下降 1-2%
└──────────────────────────► 时间
7日留存
▲
│ ___________
│ ────────────╱ ← 长期留存上升
└──────────────────────────► 时间
↑上线
这意味着: - 只看 1 天的 A/B 实验,多样性策略一定是负向的 - 必须做长周期实验(2–4 周),看留存、看使用时长、看用户流失率 - 这也是为什么多样性优化在很多公司推不动——它和短期 KPI 冲突
🔑 给未来的你的忠告:如果你要推多样性优化,先和产品/老板对齐实验周期和成功指标,否则第 3 天就会被叫停。
🌐 更大的问题:信息茧房
多样性不只是「体验优化」,它涉及产品伦理。
| 现象 | 机制 |
|---|---|
| Filter Bubble(过滤气泡) | 系统只推你喜欢的 → 你的信息世界越来越窄 |
| Echo Chamber(回音室) | 只看到同类观点 → 观点极化 |
| 反馈循环放大 | 推荐 → 点击 → 训练 → 更极端的推荐 → …… |
工业界的部分对策: - 强制探索配额(每 N 个位置留 1 个探索位) - 兴趣多样性约束(一屏必须覆盖 ≥3 个类目) - 长期价值建模(用强化学习优化累计收益而非单次点击) - 对争议性/极端内容的排序降权
但这是个未解决的问题。 作为从业者,知道这个代价存在,比假装它不存在重要。
🔗 这一章连到哪里
| 去哪 | 为什么 |
|---|---|
| 上线之后 15 | CTR 只是代理指标:多样性短期负、长期正,正是代理指标与真实目标的帕累托前沿问题 |
| 上线之后 12 | 2–4 周长周期实验怎么做、新奇效应怎么排除,否则多样性策略第 3 天就被叫停 |
| 强化学习 07 | 强制探索配额、信息茧房的反馈循环,本质就是只「利用」不「探索」的后果 |
| 博弈论 09 | ⭐ 「帕累托」这个词的定义处。⚠️ 本章正文其实一次都没用过这个词,但你整章在做的事就是它 —— 「准确性 vs 多样性」那条取舍曲线就是一条二维帕累托前沿(λ 一变推出来的东西完全不同,短期 CTR 降 1–2%、长期留存上升)。它到底怎么定义、为什么不能把两个目标的分数加起来比大小(答案:效用是序数的,两把尺子不通用),在那一章第五节。⚠️ 顺带纠正一个常见误解:帕累托最优完全不管公平——「准确性拉满、多样性归零」也是帕累托最优的 |
✅ 检查点
- 为什么「每个物品都最好」不等于「列表最好」?
- MMR 的 λ 调小会发生什么?
- DPP 用什么数学量表示「多样性」?
- 多样性策略上线后,短期 CTR 通常会怎样?该怎么评估它?
- 列举 3 个多样性的量化指标。
- 什么是信息茧房?推荐系统的哪个机制在放大它?
👀 答案
1. 边际效用递减(第5个同类物品价值远低于第1个)+ 兴趣覆盖不足 + 无法探索新兴趣。 2. λ 小 = 更看重多样性、更不看重精排分 → 推荐更杂,短期 CTR 下降。 3. 核矩阵的行列式 —— 几何上等于物品向量张成空间的体积,向量越不相似体积越大。 4. 短期 CTR 通常下降 1-2%,长期留存/时长上升。必须做 2-4 周的长周期实验,看留存类指标。 5. ILD(列表内多样性)、Coverage(物品库覆盖率)、Gini/Entropy(曝光分布不平等度)、Category Count、Novelty。 6. 只推你喜欢的导致信息世界收窄。放大机制是反馈循环:推荐→点击→用这些点击训练→推得更窄。🛑 可以停在这里
⚡ 走神救援
重排解决「列表整体好不好」。要做:硬过滤(去重/频控/黑名单) + 多样性(MMR用λ调, DPP用行列式=向量体积, 打散规则) + 业务规则(广告/扶持)。现代做法 PRM 用 Transformer 建模整个列表。多样性会短期降 CTR、长期升留存,必须做 2-4 周长周期实验。信息茧房是未解决的伦理问题。⭐ MMR 和 DPP 的分界值得记住:MMR 是贪心,每一步在「与 query 的相关性」和「与已选集合的最大相似度」之间用 λ 权衡,十几行就能写完;DPP 用行列式 = 向量张成的体积来度量整个集合的多样性,把「两两比较」升级成「集合级别」,效果更好但也更贵。⚠️ 最土的打散规则(同作者、同类目至少间隔 N 位)在工业界反而用得最多——可解释、可调、出事能立刻关掉,别看不起它。⭐ 量化多样性别只盯 ILD:Coverage 看长尾有没有被挖出来,Gini / Entropy 看曝光是不是被爆款垄断,Serendipity 最贴近用户感受却最难量化,而产品经理真正听得懂的是「一屏出现了几个类目」。⚠️ 推多样性最现实的一条忠告:先和产品、老板对齐实验周期和成功指标,因为短期 CTR 必跌,指标没谈好就撑不到第二周。
下一节 👉 12-评估与AB实验.md