numpy.random.choice 上的不同随机选择

different random choices on numpy.random.choice

我正在使用函数 numpy.random.choice 一次性生成随机样本。但我希望所有样本都不同。有人知道这样做的功能吗?明确地说,我想要这个:

import numpy as np
a = np.random.choice(62, size=(1000000, 8))
assert( len(set([tuple(a[i]) for i in range(a.shape[0])])) == a.shape[0])

整数上的值可以被替换。唯一需要的是所有行条目都不同。

这个答案已经过简化。过时的方法可以在编辑历史中找到。


首先,如果你的 numpy 版本 >= 1.17,请避免使用 np.random.choice 作为 recommended method:

rng = np.random.default_rng()
rng.choice

每个样本有 8 个值,对于 max_value = 62,您有 62**8 个独特的样本。根据 birtday problem,只想得到其中的 100 万意味着 99.8% 的时间它们在一次抽奖中都是独一无二的。在这种情况下,生成整个数组并进行简单检查就足够了。

samples = 1000000
while True:
    a = np.random.choice(62, size=(samples, 8))
    # Credit to Mark Dickinson, this is faster than doing
    # `len(set(tuple(row) for row in a)) == samples`
    if np.unique(a, axis=0).shape[0] == samples:
        break

对于较低的 max_value 值(小于 30),您可能会生成具有足够 frequency/certainty 的重复项,以至于上述方法可能变得无效甚至无限循环。然后最好生成整个数组,将任何唯一样本保留在一个集合中,然后生成您需要的更多样本。重复此过程,直到您拥有所需的数量。

seen = set()
a = []
while len(a) < samples:
    draws = np.random.choice(62, size=(samples-len(a), 8))
    for draw in draws:
        if t := tuple(draw) not in seen:
            seen.add(t)
            a.append(draw)
a = np.array(a)

这假设您要绘制的样本数量远小于唯一样本的总数量。例如,如果总数是 1001 个样本,而你想抽取 1000 个,这种方法很快就会变得低效。