[英]Am i miss-using numpy random number generator for bootstrapping?
我试图编写一些代码来创建引导分发,尽管它可以编译,但我不确定它是否可以正常工作。 一些背景:我所教学校的一名学生一直在系统地找到计算机实验室中笔记本电脑锁的组合,以便与我们的计算机老师(很幸运,不是我)搞砸。 每个锁具有三个条目,编号为0-9。 我计算出每个锁有10 ^ 3种可能的组合。 他保留了已为每种锁尝试过的组合的详细列表,因此,每次连续尝试都会对一个组合进行采样,而无需替换。 我正在尝试对此进行模拟,以了解他为解锁所有这些计算机(实验室中有12台计算机)进行了多少次尝试,方法是找到一次解锁所需的期望值。 对我来说,这听起来像是超几何分布。 我写的代码是:
import numpy as np
def lock_hg(N):
final_counts = []
for i in range(N):
count = 1
combs = list(np.arange(1,1001,1))
guess = np.random.randint(1,1000)
for k in range(1000):
a = np.random.choice(combs, 1)
if a == guess:
final_counts.append(count)
break
else:
count = count + 1
combs.remove(a)
return(final_counts)
调用lock_hg(1000)时的直方图plt.hist(final_counts)看起来相当均匀,尝试40或50次与900或950次相同。我认为它看起来更像是以500为中心的正态分布。确定代码是否有问题,或者我只是误解了数学。 此代码适合该问题吗? 如果没有,我该如何解决? 如果工作正常,是否有更有效的方法来完成此操作?
想象一下生成一个组合网格,其中每一行代表一个锁,每一列值是该锁的可能组合。 例如,假设有10个锁,每个锁只有5种可能的组合。 您可以按以下任意顺序生成它们:
In [42]: np.random.seed(2018) # to make the example reproducible
In [43]: grid = np.random.random((10,5)).argsort(axis=1); grid
Out[43]:
array([[1, 3, 4, 0, 2],
[4, 0, 2, 3, 1],
[3, 4, 2, 0, 1],
[2, 1, 3, 4, 0],
[1, 3, 0, 4, 2],
[1, 0, 4, 3, 2],
[2, 0, 1, 3, 4],
[2, 0, 3, 4, 1],
[2, 3, 1, 0, 4],
[2, 4, 0, 3, 1]])
接下来,让我们为10个锁中的每个锁选择一个随机组合:
In [48]: combo = np.random.choice(5, size=10, replace=True); combo
Out[48]: array([3, 2, 3, 3, 4, 4, 4, 3, 2, 3])
我们可以将grid
视为指示每个锁尝试组合的顺序。 我们可以将combo
用作每个锁的实际组合。
我们还可以使用以下方式可视化比赛的位置:
plt.imshow((grid == combo[:, None])[::-1], origin='upper')
我们可以使用argmax
找到每个成功匹配在网格中的argmax
:
In [73]: (grid == combo[:, None]).argmax(axis=1)
Out[73]: array([1, 2, 0, 2, 3, 2, 4, 2, 0, 3])
argmax
返回每一行的匹配项的索引(位置)。 这些索引号还指示找到每个匹配项所需的尝试次数。 好吧,差不多。 由于Python是基于0索引的, argmax
如果首次尝试匹配, argmax
将返回0。 因此,我们需要向(grid == combo[:, None]).argmax(axis=1)
加(grid == combo[:, None]).argmax(axis=1)
以获得真实的尝试次数。
因此,我们正在寻找(grid == combo[:, None]).argmax(axis=1) + 1
。 现在我们已经计算出10个锁和5个组合的计算量,现在很容易将其增加到10000个锁和1000个组合:
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(2018)
num_locks = 10000
num_combos = 1000
grid = np.random.random((num_locks, num_combos)).argsort(axis=1)
combo = np.random.choice(num_combos, size=num_locks, replace=True)
attempts = (grid == combo[:, None]).argmax(axis=1) + 1
plt.hist(attempts, density=True)
plt.show()
这种在网格中随机选择位置的方法清楚地表明了分布应该是均匀的-正确的组合很可能出现在开头,结尾或中间的任何位置。
是的,期望分布均匀。 代码很好。
一种可能的优化方法是,在删除所选密钥之前,将其与列表中的最后一个交换。 这样可以避免碰到两者之间的所有内容。
您可以进行两项改进:
import random
for i in range(5):
print(random.randint(0, 100))
10
38
53
83
23
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.