【问题标题】:different random choices on numpy.random.choicenumpy.random.choice 上的不同随机选择
【发布时间】:2021-12-28 10:21:18
【问题描述】:

我正在使用函数 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])

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

【问题讨论】:

  • 使用replace=False。请参阅documentation
  • 抱歉,我们可以替换,唯一的要求是所有条目都不同。打算明确这一点。
  • 如果可以替换(数字),那么条目并非全都不同。
  • 您还可以生成一个数组(可能带有 arange 和 tile),然后对其进行随机播放。 Shuffle 仅适用于多维数组的第一个轴,这可能是您需要的。
  • 我认为这里的意图是一行,而不是一个整数,是一个样本。所有行都必须是不同的,但个别数字应重复多次。

标签: python numpy random


【解决方案1】:

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


首先,如果您的 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),您可能会以足够的频率/确定性生成重复项,以致上述方法可能变得无效甚至无限循环。然后最好生成整个数组,将任何唯一的样本保存在一个集合中,然后生成更多你需要的样本。重复此过程,直到获得所需数量为止。

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 个样本,那么这种方法很快就会变得低效。

【讨论】:

  • 你好@Reti43,我结束了你最后一段代码的工作。确实第一个案例肯定不需要额外的检查,但我有其他案例,我可以牺牲一点速度。谢谢。
  • 对于您的第一种方法,您可以通过使用 np.unique 留在 NumPy 领域(并且可能获得一些速度):也就是说,执行 a = np.unique(np.random.choice(62, size=(samples, 8)), axis=0) 然后重复直到 a 具有正确的形状.它确实返回一个排序的结果,所以如果这不是 OP 想要的,那么之后可能需要一个额外的 shuffle
  • 在速度方面似乎并不多:在我的机器上,用a = np.random.choice(62, size=(10**6, 8)) 生成样本a 后,np.unique(a, axis=0).shape[0] 大约需要 1.1 秒,而 @ 987654336@ 大约需要 1.4 秒。
  • @MarkDickinson 这很有趣。 np.unique 在我的机器上也需要 1.1 秒,但集合理解需要 2 秒。如果您处于希望很可能没有重复的情况,这是一个更快的测试。但是,如果您必须重新滚动一些样本,我很难看到它如何以高性能的方式合并。重新滚动重复行并连接到已经唯一的样本与重新滚动所有内容一样快。但如果需要洗牌,那会很痛苦。
  • @JuanChô 我已经编辑了答案以提高代码性能。不仅可以通过逐个绘制样本来改进设置方法,还可以一次绘制尽可能多的样本。这实际上使它与 defaultlist 方法非常相似(实际上更快一点),所以我删除了后者。
猜你喜欢
  • 1970-01-01
  • 2015-06-09
  • 2014-06-05
  • 2019-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-22
相关资源
最近更新 更多