python - 关于 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 在这个例子中不起作用?
解决方案
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 问题,只是概率问题。
推荐阅读
- java - HTTP 状态 400 - springboot + resttemplate 的错误请求问题
- c# - 在 CV StreamReader (C#) 期间将字符串转换为 DateTime
- oracle - 如何在 Oracle JDBC 连接 url 中指定 oracle.jdbc.ReadTimeout?
- javascript - 是否可以仅使用 javascript 填写 pdf 表单?
- python - 使用 Python 格式化 JSON 文件
- c++ - 我可以在没有 Bazel 的情况下使用 Tensorflow 的 C++ API 吗?
- python - 从哪里开始学习 Kivy
- javascript - 如何在角度 6 中使用 ngFor 循环嵌套的 json 对象?
- c# - 以 C#.NET win 形式循环
- ios - Issue with printing the value of JSON data from POST request