首页 > 解决方案 > 关于 numpy.random.choice 的工作原理

问题描述

我正在尝试编写一个模拟优惠券收集器问题的程序。以下是该问题的快速参考:

给定n张优惠券,您预计在每张优惠券至少抽取一次之前需要更换多少张优惠券。

我想出了两段代码:

(1)

n = 50
coupon = np.arange(0, n)
def collect(coupon):
    number = 49
    collection = np.array([])
    while len(set(collection)) != n:
          number +=1
          collection = np.random.choice(coupon, replace = True, size = number)
    return number

并得到 10 次 collect(coupon) 迭代的结果,平均值为:

[175. 151. 128. 132. 169. 118. 134. 138. 150. 135.]
143.0

(2)

n = 50
coupon = np.arange(0,n)
def collect(coupon):
    collection = set()
    number = 0
    while len(collection) != n:
          number +=1
          got = np.random.choice(coupon)
          collection.add(got)
    return number

以平均值运行 10 次 collect(coupon) 迭代的结果是:

[184, 119, 286, 196, 172, 370, 163, 267, 238, 199]
219.4

我已经尝试了大量的交互,代码(1)和代码(2)产生了非常不同的结果。

我知道收集所有 50 张优惠券的期望值的正确答案是 225,代码 (2) 是正确的答案。另一方面,我找不到为什么代码 (1) 失败的合理解释?为什么 numpy.random.choice 在这个例子中不起作用?

标签: pythonpython-3.xnumpyprobability

解决方案


Numpy 问题(或没有)

您的代码看起来不错,包括您对np.random.choice. 您可能遇到的一个混淆点与replace参数的默认值有关。replace默认为True,因此您无需在代码块 (1) 中显式传递replace = True给。choice

除了这个非常小的问题之外,您的代码没有明显的问题。因此,问题可能出在数学和概率上。

概率问题

225 是绘制大小为 1 时的预期值。在您的代码 (1) 中,绘制大小随着每次迭代而增加。这样想:随着抽奖规模的增加,在一次抽奖中获得所有优惠券的几率开始变得相当大。我不知道确切的数字(编辑:我找到了一些确切的数字。他们现在在下面的“深入调查”部分),但是说在一次抽奖 100 中获得所有 50 张优惠券的概率是 0.01 . 到您抽到 143 时,至少一次获得所有优惠券的累积几率应该至少为 0.4(并且可能更大)。

深入调查

通过一些调整,您的代码可用于估计在一次大小为 x 的抽奖中看到所有 50 张优惠券的几率:

def collectx(coupon, x, reps):
    x = np.asarray(x)
    n = coupon.size

    counts = np.zeros((x.size, reps), dtype=int)
    for i,xsub in enumerate(x):
        for j in range(reps):
            count = 1
            while np.unique(np.random.choice(coupon, size=xsub)).size < n:
                count += 1
            counts[i, j] = count

    return counts

x通过传入一个序列,可以一次估计许多不同值的概率。现在,要估计所有绘制尺寸 120-143 的概率,您可以运行:

n = 50
coupon = np.arange(0, n)
counts = collectx(coupon, np.arange(120,144), 100)

这产生counts了一个形状数组(24, 100)。绘制大小随行而变化,估计的重复 ID 随列而变化。您可以通过在估计重复中取平均值并将结果除以 1 来获得“在一次抽奖中查看每张优惠券”的概率:

probx = (1/counts.mean(axis=1))

看起来像:

[0.00418971 0.00563    0.00661288 0.00694493 0.00690799 0.00854774
 0.00909339 0.01050531 0.01207875 0.01344086 0.01485222 0.0155642
 0.02004008 0.02115059 0.02015723 0.02377556 0.02639916 0.02379819
 0.02856327 0.03941663 0.04145937 0.03162555 0.03601008 0.04821601]

对于 120 的抽奖大小,概率仍低于 0.005,但它迅速增加,在 143 的抽奖大小时,看到每张优惠券的概率接近 0.05。由于低于 120 的抽奖大小的概率很小,将 120-143 的抽奖大小的概率相加可以合理估计代码块 (1) 在一次抽奖中看到所有优惠券完成时的累积概率绘制尺寸 143:

print('%.3f' % probx.sum())

输出:

0.475

因此,您的代码块 (1) 很可能在 时没有看到每张优惠券n==143。这与您观察到的结果完全一致。所以没有 Numpy 问题,只是概率问题。


推荐阅读