簡體   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