4、用户冷启动实战:构建新用户兴趣探索机制
好,咱们进入实战环节了。
前面讲了那么多理论,现在该动手了。用户冷启动,说白了就是:一个刚注册的用户,你对他一无所知,该怎么给他推荐内容?
我当年在电商平台做推荐系统时,最头疼的就是这个。新用户来了,没有点击记录,没有购买历史,连搜索词都没有。你给他推什么?推爆款?推新品?还是随机推?
嗯,这里有个核心矛盾:你想尽快了解他,就得让他多尝试不同内容。但尝试太多,他又可能因为推荐不精准而流失。
这就是冷启动阶段的探索与利用平衡问题。
4.1 冷启动的核心挑战
先理清问题本质。新用户冷启动,我们面临三个难题:
- 数据稀疏:用户画像几乎是空的,只有注册时填的性别、年龄等基础信息
- 反馈延迟:用户点不点击、看不看完,这些信号需要时间积累
- 兴趣漂移:用户今天想买书,明天想买鞋,你没法用一次行为定终身
我见过不少团队,一上来就用协同过滤给新用户推东西。结果呢?推荐列表全是热门商品,用户觉得「这平台没什么特别的」,就走了。
4.2 多臂老虎机算法:解决探索与利用的利器
多臂老虎机(Multi-Armed Bandit,MAB)这个名字挺有意思。想象一下,你面前有N台老虎机,每台的中奖概率不同。你只有有限的钱,怎么玩才能赢最多?
这就是探索与利用的经典场景:你既要尝试新机器(探索),又要多玩已知高回报的机器(利用)。
在推荐系统里,每台老虎机就是一个候选推荐策略或一个商品类别。新用户来了,我们就像赌徒一样,要决定给他展示哪个策略。
常用的MAB算法有三种,我一个个说。
4.2.1 Epsilon-Greedy:最简单的探索策略
这个算法思路很直白:以概率ε进行随机探索,以概率1-ε选择当前最优。
举个例子。假设我们有三个商品类别:A(图书)、B(电子产品)、C(服装)。新用户来了,我们设置ε=0.2。
- 80%的概率:选择当前点击率最高的类别
- 20%的概率:随机选一个类别
代码实现也很简单:
import random
import numpy as np
class EpsilonGreedy:
def __init__(self, n_arms, epsilon=0.1):
self.n_arms = n_arms
self.epsilon = epsilon
self.counts = [0] * n_arms # 每个臂被选择的次数
self.values = [0.0] * n_arms # 每个臂的平均回报
def select_arm(self):
if random.random() < self.epsilon:
# 探索:随机选一个
return random.randint(0, self.n_arms - 1)
else:
# 利用:选当前均值最高的
return np.argmax(self.values)
def update(self, chosen_arm, reward):
self.counts[chosen_arm] += 1
n = self.counts[chosen_arm]
value = self.values[chosen_arm]
# 增量更新均值
self.values[chosen_arm] = ((n - 1) * value + reward) / n
这个算法有个问题:ε是固定的。 刚开始探索多点没问题,但用户已经积累了100次点击后,你还用20%的概率去随机探索,就有点浪费了。
我个人的习惯是:让ε随时间衰减。 比如ε = 1 / sqrt(t+1),这样前期探索多,后期逐渐收敛到利用。
4.2.2 UCB(Upper Confidence Bound):更聪明的探索
UCB的思路是:对每个臂,不仅看它的平均回报,还要看它的「潜力」。
公式是这样的:
UCB = 平均回报 + sqrt(2 * ln(总尝试次数) / 该臂尝试次数)
你想想看,如果一个臂尝试次数很少,那么第二项就会很大。这意味着它虽然当前平均回报低,但「不确定性高」,值得再试一次。
代码实现:
class UCB:
def __init__(self, n_arms):
self.n_arms = n_arms
self.counts = [0] * n_arms
self.values = [0.0] * n_arms
def select_arm(self):
total_counts = sum(self.counts)
# 每个臂至少尝试一次
for arm in range(self.n_arms):
if self.counts[arm] == 0:
return arm
ucb_values = []
for arm in range(self.n_arms):
bonus = np.sqrt(2 * np.log(total_counts) / self.counts[arm])
ucb_values.append(self.values[arm] + bonus)
return np.argmax(ucb_values)
def update(self, chosen_arm, reward):
self.counts[chosen_arm] += 1
n = self.counts[chosen_arm]
value = self.values[chosen_arm]
self.values[chosen_arm] = ((n - 1) * value + reward) / n
UCB的好处是不需要设置ε,探索是自动进行的。但要注意,它假设回报是稳定的。如果用户兴趣变化很快,UCB可能反应不过来。
4.2.3 Thompson Sampling:贝叶斯视角的探索
Thompson Sampling是我个人最喜欢的算法。它从贝叶斯角度出发,对每个臂维护一个回报概率的分布,然后从分布中采样,选采样值最大的臂。
说白了,就是:我不确定每个臂的真实回报率,但我有个「信念」。每次选择时,我根据信念随机抽一个值,选最大的那个。
对于二分类问题(点击/不点击),我们通常用Beta分布来表示信念:
class ThompsonSampling:
def __init__(self, n_arms):
self.n_arms = n_arms
# Beta分布参数:alpha = 成功次数+1, beta = 失败次数+1
self.alphas = [1] * n_arms
self.betas = [1] * n_arms
def select_arm(self):
samples = []
for arm in range(self.n_arms):
# 从Beta分布中采样
sample = np.random.beta(self.alphas[arm], self.betas[arm])
samples.append(sample)
return np.argmax(samples)
def update(self, chosen_arm, reward):
if reward == 1:
self.alphas[chosen_arm] += 1
else:
self.betas[chosen_arm] += 1
Thompson Sampling有个天然优势:不确定性越高的臂,采样值的方差越大,被选中的概率也越大。 这正好符合「探索」的需求。
我记得有一次做AB测试,Thompson Sampling的冷启动效果比UCB好了15%。为什么?因为UCB的探索是确定性的(选上界最高的),而Thompson Sampling是随机采样的,天然带有随机性,能更均匀地探索各个臂。
4.3 冷启动阶段的探索与利用平衡策略
光有算法还不够,你得知道什么时候用哪种策略。我一般把冷启动分为三个阶段:
| 阶段 | 用户行为数 | 推荐策略 | 探索比例 |
|---|---|---|---|
| 纯冷启动 | 0-5次 | 基于人口统计 + 随机探索 | 80% |
| 弱冷启动 | 5-30次 | MAB算法(推荐Thompson Sampling) | 30%-50% |
| 温启动 | 30次以上 | 协同过滤 + MAB混合 | 10%-20% |
这里有个关键点:探索不是盲目的。 你不能真的给新用户随机推东西。我一般会先根据用户注册信息(年龄、性别、地域)做一个粗粒度的兴趣预测,然后在这个「候选池」里做MAB探索。
举个例子。一个25岁男性用户注册,我猜他可能对电子产品、运动户外感兴趣。那我就把候选类别缩小到5-10个,然后用Thompson Sampling在这几个类别里探索。这样既保证了探索效率,又不会推荐太离谱的内容。
4.4 实战中的坑与解决方案
最后分享几个我踩过的坑:
- 坑1:冷启动阶段用全局热门。结果新用户看到的全是爆款,觉得平台没个性。解决方案:用分层热门,按用户画像分群,每个群有自己的热门列表。
- 坑2:MAB算法不区分用户。所有新用户共享一个MAB模型。结果呢?喜欢看书的用户被推了电子产品。解决方案:按用户画像分桶,每个桶独立维护MAB。
- 坑3:只关注点击率。用户点了,但没转化,或者点了就关。解决方案:用多目标奖励,比如点击+停留时长+转化,加权求和作为MAB的reward。
嗯,说到这里,我想起一个项目。当时我们给新用户推了10个商品类别,用UCB算法。结果发现有个类别「家居用品」一直没人点,UCB就再也不推了。但后来我们分析发现,不是用户不喜欢家居,而是推荐位太靠后,用户根本没看到。
所以,位置偏差一定要处理。 我后来在reward里加了位置惩罚项,曝光位置越靠后,reward打折越多。这样算法就不会因为位置问题而误判某个类别的真实价值。
好了,这一章的内容就到这里。下一章我们会讲物品冷启动,也就是新商品上架后,怎么在没有用户行为的情况下做推荐。到时候会讲到内容特征提取、图神经网络等方法,敬请期待。