Python中A/B测试三分桶用户分组代码能否保证用户概率均等?
三分桶A/B实验的随机性分析
嘿,来聊聊你这段三分桶A/B实验的代码能不能保证用户均等进入每个变体哈~先给你个明确结论:你的代码没法在所有场景下保证每个用户进入三个变体的概率完全均等,咱们一步步拆解原因,再说说更靠谱的做法。
先看你代码的核心问题
你写的代码逻辑是这样的:
NUM_USERS = int(len(all_users) * 0.33) variant1 = sample(all_users, NUM_USERS) variant2 = sample(set(all_users) - set(variant1), NUM_USERS) variant3 = set(all_users) - set(variant1) - set(variant2)
最大的问题出在用户总数不一定是3的整数倍:
- 比如总用户是100人,
NUM_USERS会被计算为33,那variant3就会剩下34人。这时候用户进入variant3的概率是34%,而前两个变体只有33%,明显不均等。 - 就算总用户刚好是3的整数倍(比如99人),表面上三个组都是33人,概率看似对等,但这种情况太理想化了,实际业务里用户数很少刚好凑成3的倍数。
另外还有个小细节:把用户列表转成set会丢失原有顺序(如果你的用户列表是有序结构的话),虽然对随机性影响不大,但可能不是你想要的结果。
更靠谱的均等分桶方法
想要保证每个用户进入任一变体的机会均等,有两种简单实用的方法:
方法1:打乱后分片(分组人数尽可能平均)
先把所有用户随机打乱,再分成三个连续分片,这样每个用户被分到任意组的概率完全均等,而且分组人数差异最多只有1个:
from random import shuffle # 复制原列表避免修改原始数据 shuffled_users = all_users.copy() shuffle(shuffled_users) # 计算分片节点 split_point1 = len(shuffled_users) // 3 split_point2 = split_point1 * 2 # 拆分三个变体组 variant1 = shuffled_users[:split_point1] variant2 = shuffled_users[split_point1:split_point2] variant3 = shuffled_users[split_point2:]
方法2:给每个用户随机分配组号(概率严格均等)
给每个用户独立生成0-2的随机数,根据数字分到对应组。这种方法下每个用户进入每个组的概率严格是1/3,唯一的小缺点是分组人数可能有小幅波动,但用户量越大,人数会越趋近于平均:
from random import randint # 初始化三个空组 groups = {0: [], 1: [], 2: []} for user in all_users: # 随机分配组号 group_id = randint(0, 2) groups[group_id].append(user) # 取出三个变体组 variant1 = groups[0] variant2 = groups[1] variant3 = groups[2]
总结
你的代码只有在用户总数刚好是3的整数倍时,才能保证概率均等,但绝大多数场景下都不满足这个条件。用上面两种方法,能更稳妥地实现你想要的「每个用户均等进入任一变体」的目标。
内容的提问来源于stack exchange,提问作者kamalbanga
相关产品推荐
相关产品推荐

