1. 实验分桶概述:为什么需要分桶?分桶在推荐系统中的核心作用
大家好,我是你们这堂课的主讲。做了这么多年推荐系统,我见过太多「拍脑袋上线、哭着回滚」的案例了。今天咱们聊聊实验分桶——这个看似基础、实则决定你实验结论生死的关键环节。
1.1 一个血淋淋的教训:没有分桶的后果
先讲个我亲身经历的事。几年前我负责一个短视频推荐项目,团队急着验证一个新召回模型。当时觉得「就改个召回逻辑,影响不大」,直接全量上线了。结果呢?
- 次日留存掉了 0.8%
- 人均观看时长跌了 12%
- 用户投诉量翻了三倍
更可怕的是——我们花了整整两周才定位到问题。因为线上同时有多个策略在调整,根本分不清是哪个改动导致的。说白了,没有分桶,你连「锅该甩给谁」都不知道。
3. 分桶的核心作用:它到底解决了什么问题?
分桶,说白了就是把用户随机切分成多个互斥的组。每组看到不同的推荐策略,然后对比效果。它的核心作用我归纳为四点:
| 作用 | 解释 | 我见过的反面案例 |
|---|---|---|
| 因果推断 | 确保实验组和对照组只有策略不同,其他因素一致 | 某团队用新老用户做对比,结果偏差巨大 |
| 风险隔离 | 坏策略只影响小部分用户,不会炸全量 | 我见过一个排序 bug 只影响了 5% 用户,轻松回滚 |
| 并行实验 | 多个团队同时跑实验,互不干扰 | 某司 3 个实验共用同一批用户,指标全乱了 |
| 统计置信 | 保证样本量足够,实验结果可量化 | 分桶太小,跑了两周 p 值还是 0.3 |
1.3 分桶的底层逻辑:随机性与一致性
分桶听起来简单——把用户随机分到不同组就行。但这里有两个关键点,我当年也是吃了亏才搞明白的。
1.3.1 随机性:不是「看起来随机」就行
你想想看,如果分桶算法有偏差,比如某个桶里全是高活用户,那实验结果能信吗?我建议用 Hash 取模 或 Fisher-Yates 洗牌 来保证均匀分布。
// 一个简单的 Hash 分桶示例(伪代码)
def assign_bucket(user_id, experiment_id, num_buckets=100):
hash_key = hash(f"{user_id}:{experiment_id}")
bucket = hash_key % num_buckets
return bucket
1.3.2 一致性:同一个用户不能反复跳桶
这个坑我踩过。早期我们用随机数分桶,结果用户每次刷新都进不同桶。实验组和对照组的用户一直在「串门」,指标根本没法看。
正确的做法是:用用户 ID 做确定性 Hash。同一个用户,在同一个实验里,永远进同一个桶。
1.4 分桶的常见分层模型
实际生产中,我们不会只有一个实验在跑。可能有推荐算法实验、UI 实验、推送实验……它们怎么共存?
我常用的分层模型长这样:
这个图我建议你存下来。每次设计实验分桶方案时,先画这么一张图,把「流量怎么分、实验怎么放、数据怎么流」理清楚。
1.5 分桶的常见误区
最后,我总结几个新手最容易踩的坑:
- 桶数太少:比如只分 2 个桶,实验组和对照组各 50%。这样一旦实验有问题,影响面太大。我建议至少分 10 个桶,灰度时先放 1 个桶(10%)。
- 忽略用户重叠:同一个用户在不同设备上登录,可能被分到不同桶。要用「用户 ID + 设备 ID」联合 Hash。
- 实验周期太短:分桶后至少要跑满一个完整的用户行为周期(比如一周),才能看到稳定的指标变化。
- 只看均值不看分布:分桶实验的结论不能只看平均指标,还要看分位线。我见过一个实验均值涨了 5%,但 P50 跌了 10%——说明只对头部用户有效,对普通用户是伤害。
一句话总结: 分桶不是「把用户随便分一分」那么简单。它是推荐系统实验的基石,决定了你的实验结论是否可信、风险是否可控、团队协作是否高效。
我个人习惯是:每个新项目启动前,先花半天把分桶方案画清楚。磨刀不误砍柴工,这个时间省不得。