上下文推荐(Context-Aware Recommendation)利用用户所处的上下文环境(时间、地点、设备、天气等)来调整推荐策略。同一用户在不同上下文下的需求可能完全不同。
| 类型 | 示例 | 影响 |
|---|---|---|
| 时间 | 早/午/晚/夜/工作日/周末 | 内容偏好变化 |
| 地点 | 家/公司/路上/商场 | 需求场景不同 |
| 设备 | PC/手机/平板/电视 | 内容形式偏好 |
| 社交 | 独处/聚会/办公 | 内容类型偏好 |
| 情绪 | 开心/疲惫/无聊 | 内容调性偏好 |
r̂ = f(user, item, context)
将上下文作为额外输入特征
r̂ = w^T[x_u, x_i, x_c] + Σ交叉项
捕捉用户-上下文、物品-上下文交互
import numpy as np
np.random.seed(42)
print("="*60+"\n上下文推荐系统\n"+"="*60)
n_samples=500;n_features=6;n_context=4
# 生成带上下文的数据
# 特征:[用户特征2,物品特征2,上下文特征2]
user_feat=np.random.randn(n_samples,2)
item_feat=np.random.randn(n_samples,2)
time_feat=np.random.choice(4,n_samples) # 0=早,1=午,2=晚,3=夜
device_feat=np.random.choice(2,n_samples) # 0=PC,1=移动
# 上下文影响交互
context_effect=np.array([0.5,0.8,1.2,0.3]) # 时段权重
device_effect=np.array([1.0,0.7]) # 设备权重
true_w=np.random.randn(n_features)
y=np.zeros(n_samples)
for i in range(n_samples):
base=user_feat[i]@true_w[:2]+item_feat[i]@true_w[2:4]
ctx=context_effect[time_feat[i]]+device_effect[device_feat[i]]
y[i]=base+ctx+np.random.randn()*0.3
y=(y>np.median(y)).astype(float)
print(f"样本:{n_samples} 正例率:{y.mean():.2%}")
print(f"时段分布:{dict(zip(*np.unique(time_feat,return_counts=True)))}")
print(f"设备分布:{dict(zip(*np.unique(device_feat,return_counts=True)))}")
# 无上下文基线
X_base=np.column_stack([user_feat,item_feat])
def sigmoid(x):return 1/(1+np.exp(-np.clip(x,-500,500)))
def train_lr(X,y,lr=0.01,epochs=100):
n,d=X.shape;w=np.zeros(d);b=0
for ep in range(epochs):
pred=sigmoid(X@w+b);err=pred-y
w-=lr*(X.T@err/n+0.01*w);b-=lr*np.mean(err)
return w,b
w_base,b_base=train_lr(X_base,y)
pred_base=sigmoid(X_base@w_base+b_base)
acc_base=np.mean((pred_base>0.5)==y)
auc_base=np.mean(pred_base[y==1]>pred_base[y==0])
print(f"\n无上下文基线:ACC={acc_base:.4f} AUC={auc_base:.4f}")
# 上下文增强
time_onehot=np.zeros((n_samples,4))
for i in range(n_samples):time_onehot[i,time_feat[i]]=1
device_onehot=np.zeros((n_samples,2))
for i in range(n_samples):device_onehot[i,device_feat[i]]=1
X_ctx=np.column_stack([user_feat,item_feat,time_onehot,device_onehot])
w_ctx,b_ctx=train_lr(X_ctx,y)
pred_ctx=sigmoid(X_ctx@w_ctx+b_ctx)
acc_ctx=np.mean((pred_ctx>0.5)==y)
auc_ctx=np.mean(pred_ctx[y==1]>pred_ctx[y==0])
print(f"上下文增强:ACC={acc_ctx:.4f} AUC={auc_ctx:.4f}")
# 交叉特征
print("\n--- 上下文交叉特征 ---")
cross_feats=[]
for i in range(2):
for j in range(4):
cross_feats.append(user_feat[:,i]*time_onehot[:,j])
for i in range(2):
for j in range(2):
cross_feats.append(item_feat[:,i]*device_onehot[:,j])
X_cross=np.column_stack([X_ctx]+cross_feats)
w_cross,b_cross=train_lr(X_cross,y,lr=0.005)
pred_cross=sigmoid(X_cross@w_cross+b_cross)
acc_cross=np.mean((pred_cross>0.5)==y)
auc_cross=np.mean(pred_cross[y==1]>pred_cross[y==0])
print(f"交叉特征:ACC={acc_cross:.4f} AUC={auc_cross:.4f}")
# 时段效果分析
print("\n时段效果分析:")
for t in range(4):
mask=time_feat==t
t_acc=np.mean((pred_ctx[mask]>0.5)==y[mask])
t_auc=np.mean(pred_ctx[mask&y.astype(bool)]>pred_ctx[mask&~y.astype(bool)])if mask.sum()>0 else 0
print(f" 时段{t}:样本数={mask.sum()} ACC={t_acc:.4f}")
# 对比
print(f"\n{'方法':<15}{'ACC':<10}{'AUC':<10}")
print("-"*35)
print(f"{'无上下文':<15}{acc_base:<10.4f}{auc_base:<10.4f}")
print(f"{'+上下文':<15}{acc_ctx:<10.4f}{auc_ctx:<10.4f}")
print(f"{'+交叉特征':<15}{acc_cross:<10.4f}{auc_cross:<10.4f}")
✅ 验证通过
本课代码涵盖了从数据生成、模型训练到效果评估的完整流程。以下是关键步骤的详细解读:
代码设计原则:简洁可读、关键步骤有注释、结果可复现(固定随机种子)。
| 组件 | 版本 | 说明 |
|---|---|---|
| Python | 3.8+ | 推荐3.10版本 |
| NumPy | 1.21+ | 核心数值计算库 |
| SciPy | 1.7+ | 统计检验(部分课程) |
本课是第18课:上下文推荐,属于排序与重排阶段。我们系统学习了本课的核心概念、数学原理和代码实现,并通过实机运行验证了算法的正确性。
练习1:实现基于位置(LBS)的上下文推荐
练习2:实现注意力机制自动学习上下文权重
练习3:用预过滤方法(按上下文分片训练)对比
练习4:实现天气+时间+设备的联合上下文模型
| 公司 | 场景 | 核心技术 |
|---|---|---|
| 字节跳动 | 抖音/TikTok | 多目标排序+实时特征+双塔召回 |
| 阿里巴巴 | 淘宝推荐 | DIN/DIEN序列模型+MIND多兴趣 |
| 腾讯 | 微信看一看 | DeepFM+图神经网络召回 |
| 美团 | 本地生活推荐 | 多场景多目标+时空特征 |
| Netflix | 视频推荐 | 矩阵分解+深度学习混合 |
✅ 理解上下文信息在推荐中的价值
✅ 掌握上下文感知推荐的三种方法
✅ 实现上下文特征交叉模型
✅ 理解不同上下文类型对推荐的影响