繁体   English   中英

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

[英]different random choices on numpy.random.choice

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

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作为推荐方法

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

具有讽刺意味的是,做你所做的事情是go 关于它的最佳方式。 只需生成所有数字并检查它是否满足您的限制。

samples = 1000000
while True:
    a = np.random.choice(62, size=(samples, 8))
    if len(set(tuple(row) for row in a)) == samples:
        break

原因是每个样本都有 8 个值,其中每个值最多可以取 62 个不同的值。 所以有效地你有 62**8 个独特的样本。 与您要绘制的 100 万个样本相比,这是一个巨大的数字,考虑到生日问题,它们在 99.8% 的时间里都是唯一的。 如果他们不是,第二次抽签几乎可以保证这一点。 您不会发现自己陷入无限循环。

通常,您对 go 的处理方式是在循环中绘制每个样本并检查之前是否遇到过。

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

由于 python 循环和对np.random.choice的大量调用,这结果要慢得多。 在我的机器上,这需要 15 秒,而上面的方法只需要 2 秒。 现在,如果第一种方法如此频繁地创建重复样本,以至于您将在该循环中进行超过 7-8 次迭代,则第二种方法会变得更有效。 但由于上述原因,这不是你的情况。

编辑

一种混合方法是像第一种方法一样生成所有数字,但不是创建一组样本,而是使用 dict 来跟踪每个样本在哪一行遇到。 然后,如果有任何重复,您不必生成一个全新的数组,而只需替换几个单独的样本。

from collections import defaultdict
import numpy as np

value = 20
samples = 1000000
length = 8

a = np.random.choice(value, size=(samples, length))
d = defaultdict(list)
for i, row in enumerate(a):
    d[tuple(row)].append(i)
if len(d) < samples:
    print(f'Found {samples - len(d)} duplicates')
    idx = []
    for rows in d.values():
        if len(rows) > 1:
            idx.extend(rows[1:])
            del rows[1:]
    while idx:
        draw = np.random.choice(value, size=length)
        if t := tuple(draw) not in d:
            d[t].append(idx[-1])
            a[idx.pop()] = draw
print('Done')

同样,对于value = 62 ,您很可能只需一次平局即可。 但是对于value = 20 ,它几乎可以肯定地平均生成 20 个重复项。 因此,用新的独特样本替换这几个样本比使用上面的第二种方法更快。 当您将值增加到value = 30时,无论您是否会得到重复,这几乎是 50-50。 虽然这种方法有更多的代码,但它保留了很多速度优势,只需在一个 go 中生成整个数组。

在您的情况下,我仍然会使用建议的最佳方法,因为它不太可能生成任何重复项,以至于您甚至花费一行进行完整性检查的唯一原因只是为了不可思议。 没有必要让事情变得更复杂。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM