10 连抽保底的概率模型
这篇文章是看到云风 云风的 BLOG: 10 连抽保底的概率模型 所想到的。
在云风的文章里面,这个10连抽保底模型最后转换为:
- 在两次抽取橙卡之间,可能要抽取N张白卡
- 为了做10连抽保底,N最大值是9.
- N服从指数分布
将[0.0, 1.0)之间均匀分布的随机数,转换成为指数分布的随机数,在 这里 可以找到答案:
- 假设我们有均匀分布随机数p, 然后希望转换成为目标分布f(x)的随机数
- 先求解出这个目标分布f(x)的CDF,也就是累积分布函数F(x),这个累积分布函数的值域是[0.0, 1.0)
- 然后令F(x) = p, x = F'(p), 其中F'就是F的逆函数
以指数分布为例,它的CDF(x) = (1 - e ^ (-lam * x)) (x >= 0). 令CDF(x) = p, 那么 x = ln(1-p) / (-lam). ️
然后问题就是如何选择这个lam. 指数分布的期望是E = 1 / lam. 比如lam = 0.1, E = 10,也就是平均需要抽取到10张白卡。 E(也就是lam的选择)直接影响到最终的分布,选择任意的E其实都没有问题(云风在文章里面选择rate=10) 基本上E很大(比如20)的话,那么0-9的分布就更均匀一些,E很小(比如5)的话,那么都会集中在小数字上。
np.random.seed(42) def gen(E=9): while True: p = np.random.random() x = int(np.log(1-p) * -E) assert x >= 0 if x < 10: break return x Es = [5,9,15,20] df = pd.DataFrame() for E in Es: xs = pd.Series([gen(E) for i in range(10000)]) df['E={}'.format(E)] = xs _ = df.hist(bins = 10, figsize=(20, 10))
但是无论如何,最终得到的分布肯定都不再是指数分布了,因为长尾没有了。粗略估计,如果真正要满足指数分布的话,那么应该给予N=9无穷大的概率,E应该是大约在4.5左右才符合指数分布。
让如何让最终分布满足指数分布呢?是否还有更简单的做法呢? 我觉得可以倒退:
- 首先分布还是指数分布
- N=9的时候必须给予很大的概率(这个概率不好估计,可以从0.99开始试)
- P(0) + .. P(9) = 1.0
def est_lam(x, p): lam = - np.log(1-p) / x return lam lam = est_lam(9, 0.869) # 这个是多次测试的结果 print('E = {}, lam = {}'.format(1/lam, lam)) v = 0 for i in range(10): p = lam * np.exp(-lam * i) print('p({}) = {}'.format(i, p)) v += p print(v) """ Output E = 4.427918020444273, lam = 0.22583977286455395 p(0) = 0.22583977286455395 p(1) = 0.18018534315870097 p(2) = 0.1437601423230733 p(3) = 0.11469844416006433 p(4) = 0.09151168662016494 p(5) = 0.07301222653361038 p(6) = 0.058252507633495834 p(7) = 0.046476526010727784 p(8) = 0.03708110702488957 p(9) = 0.029585010245256563 1.0004027665745376 """
数据有这些含义:
- p(0) = 0.2258 表示抽取一张橙色牌之后,下次有22.58%概率立刻抽取到橙色牌
- E = 4.4279 表示抽取一张橙色牌之后,平均需要抽取4.4279张白色牌才能再次抽取橙色牌
- 橙牌:白牌比例是1: 4.4279 = 18.4%