簡體   English   中英

python,從(1,n)中選擇隨機的#k數字,但列表中的數字除外

[英]python, select random #k numbers from (1, n) excluding numbers in list

對於給定的exclude_list = [3,5,8],n = 30,k = 5

我想選擇1到30之間的5(k)個隨機數。但是我不應該在exclude_list中選擇數字

假設exclude_list,n可能很大。

當不需要排除時,很容易獲得k個隨機樣本

rand_numbers = sample(range(1, n), k)

所以要得到答案,我可以

sample(set(range(1, n)) - set(exclude_numbers), k)

我讀到該范圍一次在內存中保留一個數字。 我不太確定它如何影響上述兩行。

第一個問題是,以下代碼是否將所有n個數字都放入內存中,還是一次將每個數字都放入?

rand_numbers = sample(range(1, n), k)

第二個問題是,如果上述代碼確實確實一次在內存中放入一個數字,我是否可以對排除列表的附加約束進行類似操作?

樣本筆記sample的文檔字符串

要選擇整數范圍內的樣本,請使用range作為參數。 這對於從大量人口中采樣特別快速且節省空間:sample(range(10000000),60)

我可以在我的機器上測試:

In [11]: sample(range(100000000), 3)
Out[11]: [70147105, 27647494, 41615897]

In [12]: list(range(100000000))  # crash/takes a long time

有效地使用排除列表采樣的一種方法是使用相同的范圍技巧,但使用bisect模塊 “跳過”排除(我們可以在O(k * log( len(exclude_list) ))中進行此操作)):

import bisect
import random

def sample_excluding(n, k, excluding):
    # if we assume excluding is unique and sorted we can avoid the set usage...
    skips = [j - i for i, j in enumerate(sorted(set(excluding)))]
    s = random.sample(range(n - len(skips)), k)
    return [i + bisect.bisect_right(skips, i) for i in s]

我們可以看到它的工作原理:

In [21]: sample_excluding(10, 3, [2, 4, 7])
Out[21]: [6, 3, 9]

In [22]: sample_excluding(10, 3, [1, 2, 8])
Out[22]: [0, 4, 3]

In [23]: sample_excluding(10, 6, [1, 2, 8])
Out[23]: [0, 7, 9, 6, 3, 5]

具體來說,我們無需使用O(n)內存即可完成此操作:

In [24]: sample_excluding(10000000, 6, [1, 2, 8])
Out[24]: [1495143, 270716, 9490477, 2570599, 8450517, 8283229]

暫無
暫無

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

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