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

Jua*_*Chô 0 python random numpy

我正在使用函数 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])
Run Code Online (Sandbox Code Playgroud)

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

Ret*_*i43 5

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


首先,如果您的 numpy 版本>= 1.17,请避免使用np.random.choice推荐的方法

rng = np.random.default_rng()
rng.choice
Run Code Online (Sandbox Code Playgroud)

每个样本有 8 个值,max_value = 62您有 62**8 个独特的样本。根据生日问题,想要只获得 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
Run Code Online (Sandbox Code Playgroud)

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

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)
Run Code Online (Sandbox Code Playgroud)

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

  • 对于第一种方法,您可以使用“np.unique”留在 NumPy 领域(并且可能获得一些速度):也就是说,执行“a = np.unique(np.random.choice(62, size=(samples, 8)), axis=0)` 然后重复直到 `a` 具有正确的形状。它确实返回一个排序结果,所以如果这不是OP想要的结果,那么之后可能需要额外的“shuffle”。 (2认同)