簡體   English   中英

從 python 生成器中隨機抽取樣本

[英]Taking random samples from a python generator

for pair in itertools.combinations(bug_map.keys(), 2):使用函數for pair in itertools.combinations(bug_map.keys(), 2):來生成我的數據庫中的所有元素對。 問題是元素的數量約為 6.6 K,因此組合數為 21.7 M。此外,組合按字典排序順序發出。

假設我會從生成器中獲取隨機對而不“產生”所有對(只是 n 維的一個子集),我該怎么辦?

如果允許將所有6K元素作為列表獲取,則首先獲取所有元素,然后使用標准 python 的random.choices()生成一批帶有替換的樣本。 然后應用排序(因為組合已排序)。 然后刪除兩次或更多內部具有相同元素的元組和相等的元組。 重復批量生成,直到我們得到足夠的n元組的數量。

您可以將任何k指定為要在我的代碼中生成的所需元組的長度,並將n指定為要生成的 k 長度元組的數量。

該算法生成類似於創建k長度的所有組合然后選擇大小為n隨機子集的概率分布模式。

在線試試吧!

import random

#random.seed(0) # Do this only for testing to have reproducible random results

l = list(range(1000, 1000 + 6600)) # Example list of all input elements

k = 2 # Length of each tuple to generate
n = 30 # Number of tuples to generate

batch = max(1, n // 4) # Number of k-tuples to sample at once
maybe_sort = lambda x: sorted(x) if is_sorted else x

res = []

while True:
    if len(res) >= n:
        res = res[:n]
        break
    a = random.choices(range(len(l)), k = k * batch) # Generate random samples from inputs with replacement
    a = sorted(res + [tuple(sorted(a[i * k + j] for j in range(k))) for i in range(batch)])
    res = [a[0]]
    for e in a[1:]:
        if all(e0 != e1 for e0, e1 in zip(e[:-1], e[1:])) and res[-1] != e:
            res.append(e)

print([tuple(l[i] for i in tup) for tup in res])

這可能看起來微不足道,但是如果您想要的樣本數量遠小於可能的組合總數 (21.8 M),那么您可以重復生成ramdom.sample直到您擁有足夠多的ramdom.sample 可能會發生沖突,但(同樣,如果所需的樣本數量相對較少)發生沖突的概率可以忽略不計,不會導致減速。

import random

lst = range(6000)
n = 1000000
k = 2

samples = set()
while len(samples) < n:
    samples.add(tuple(random.sample(lst, k)))

即使對於 1,000,000 個隨機樣本,這也僅產生了大約 12k 次碰撞,即大約 1% 的“浪費”迭代,這可能不是什么大問題。

請注意,除了combinationsramdom.sample返回的對沒有排序(第一個元素可以大於第二個),因此您可能需要使用tuple(sorted(...))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM