多样性是推荐系统的重要质量维度。单一追求相关性会导致信息茧房——用户总看到相似内容。多样性优化在保持相关性的同时,确保推荐列表内容丰富。
| 度量 | 定义 | 含义 |
|---|---|---|
| ILD | 列表内物品平均距离 | 内容多样性 |
| 类目覆盖 | 覆盖的类目比例 | 类目广度 |
| 熵 | 类目分布的信息熵 | 类目均匀性 |
| Gini | 类目分布的基尼系数 | 分布集中度 |
ILD = (2/|S|(|S|-1)) Σ_{i
P(Y⊂V) ∝ det(L_Y)
L = diag(q)·S·diag(q), S为相似度矩阵
λ↑: 更相关, λ↓: 更多样
import numpy as np
np.random.seed(42)
print("="*60+"\n多样性优化\n"+"="*60)
n_items=20;n_features=8
item_embs=np.random.randn(n_items,n_features)
categories=np.random.choice(["A","B","C","D"],n_items)
scores=np.random.random(n_items)*5+1
print(f"物品:{n_items} 类别:{dict(zip(*np.unique(categories,return_counts=True)))}")
# 多样性度量
def intra_list_diversity(items,embs):
if len(items)<2:return 0
div=0;n=0
for i in range(len(items)):
for j in range(i+1,len(items)):
a,b=embs[items[i]],embs[items[j]]
div+=1-np.dot(a,b)/(np.linalg.norm(a)*np.linalg.norm(b)+1e-10)
n+=1
return div/n
def category_coverage(items,cats):
return len(set(cats[i]for i in items))/len(set(cats))
def entropy_diversity(items,cats):
from collections import Counter
c=Counter(cats[i]for i in items)
total=len(items)
return -sum((cnt/total)*np.log2(cnt/total)for cnt in c.values())
# 基线(纯相关性排序)
baseline=np.argsort(-scores)[:10]
print(f"\n基线(ILD={intra_list_diversity(baseline,item_embs):.4f} 覆盖={category_coverage(baseline,categories):.2f} 熵={entropy_diversity(baseline,categories):.4f})")
# MMR
def mmr(scores,embs,lam=0.5,k=10):
sel=[];cand=list(range(len(scores)))
for _ in range(min(k,len(scores))):
best=None;best_val=-999
for i in cand:
rel=scores[i]
if sel:
max_sim=max(abs(np.dot(embs[i],embs[j])/(np.linalg.norm(embs[i])*np.linalg.norm(embs[j])+1e-10))for j in sel)
else:max_sim=0
val=lam*rel-(1-lam)*max_sim*5
if val>best_val:best_val=val;best=i
sel.append(best);cand.remove(best)
return sel
mmr_result=mmr(scores,item_embs,lam=0.5)
print(f"MMR(ILD={intra_list_diversity(mmr_result,item_embs):.4f} 覆盖={category_coverage(mmr_result,categories):.2f} 熵={entropy_diversity(mmr_result,categories):.4f})")
# DPP
print("\n--- DPP多样性 ---")
def dpp_select(scores,embs,k=10,gamma=0.5):
n=len(scores)
L=np.zeros((n,n))
for i in range(n):
for j in range(n):
sim=np.dot(embs[i],embs[j])/(np.linalg.norm(embs[i])*np.linalg.norm(embs[j])+1e-10)
L[i,j]=gamma*np.sqrt(scores[i])*sim*np.sqrt(scores[j])
# 贪心选择
sel=[]
for _ in range(min(k,n)):
best=None;best_det=0
for i in range(n):
if i in sel:continue
trial=sel+[i]
sub=L[np.ix_(trial,trial)]
det=np.linalg.det(sub+1e-10*np.eye(len(trial)))
if det>best_det:best_det=det;best=i
if best is not None:sel.append(best)
return sel
dpp_result=dpp_select(scores,item_embs,k=10,gamma=0.3)
print(f"DPP(ILD={intra_list_diversity(dpp_result,item_embs):.4f} 覆盖={category_coverage(dpp_result,categories):.2f} 熵={entropy_diversity(dpp_result,categories):.4f})")
# λ影响
print("\nMMR λ参数影响:")
for lam in [0.1,0.3,0.5,0.7,0.9]:
res=mmr(scores,item_embs,lam=lam)
avg_score=np.mean([scores[i]for i in res])
ild=intra_list_diversity(res,item_embs)
print(f" λ={lam}: 平均分={avg_score:.2f} ILD={ild:.4f}")
✅ 验证通过
本课代码涵盖了从数据生成、模型训练到效果评估的完整流程。以下是关键步骤的详细解读:
代码设计原则:简洁可读、关键步骤有注释、结果可复现(固定随机种子)。
| 组件 | 版本 | 说明 |
|---|---|---|
| Python | 3.8+ | 推荐3.10版本 |
| NumPy | 1.21+ | 核心数值计算库 |
| SciPy | 1.7+ | 统计检验(部分课程) |
本课是第16课:多样性优化,属于排序与重排阶段。我们系统学习了本课的核心概念、数学原理和代码实现,并通过实机运行验证了算法的正确性。
练习1:实现基于用户兴趣覆盖的多样性指标
练习2:实现贪心DPP的加速版本
练习3:用强化学习优化多样性-相关性权衡
练习4:实现个性化多样性(不同用户不同多样性需求)
| 公司 | 场景 | 核心技术 |
|---|---|---|
| 字节跳动 | 抖音/TikTok | 多目标排序+实时特征+双塔召回 |
| 阿里巴巴 | 淘宝推荐 | DIN/DIEN序列模型+MIND多兴趣 |
| 腾讯 | 微信看一看 | DeepFM+图神经网络召回 |
| 美团 | 本地生活推荐 | 多场景多目标+时空特征 |
| Netflix | 视频推荐 | 矩阵分解+深度学习混合 |
✅ 理解多样性的多种度量方法
✅ 掌握DPP和MMR两种优化方法
✅ 实现多样性优化并评估
✅ 理解多样性-相关性权衡的调参