2016-09-22 43 views
0

我使用random.sample取決於輸入負載從一個非常大的範圍內採樣。有時樣本本身非常大,因爲它是一個列表,它佔據了大量的記憶。python是否有內置的方式來返回一個列表生成器,而不是從random.sample的列表

該應用程序不一定使用列表中的所有值。 如果random.sample可以返回列表生成器而不是列表本身,那將是非常好的。

現在我有一個包裝,它將大輸入範圍劃分成相同大小的桶,並使用randint從每個n/sample_size桶中選擇一個隨機數。

編輯:在我的情況下輸入是連續的,我有這個包裝函數來模擬random.sample作爲一個生成器,但這不是真正的複製功能,因爲它在最後跳過一些元素。

import random 
def samplegen(start, end, sample_size): 
    bktlen = (end - start)/sample_size 
    for i in xrange(sample_size): #this skips the last modulo elements 
     st = start + (i * bktlen) 
     yield random.randrange(st, st + bktlen) 
+3

要做'random.sample'作爲一個生成器,你必須跟蹤你已經放棄的項目,所以你可以避免再次使用它們。這將使用與返回列表一樣多的內存。 – kindall

+0

@ kindall這就是爲什麼我將輸入範圍拆分爲桶並從每個桶中僅選擇一個數字,並且桶的數量基於樣本大小。我應該提到輸入是連續範圍的數字,如xrange(0,1000000) – user881300

+0

@ user881300'xrange(0,1000000)'的random.sample是如何產生問題的?這並不大。 –

回答

2

既然你評論說,順序並不重要(我曾問是否必須是隨機的或可排序),這可能是一個選項:

import random 

def sample(n, k): 
    """Generate random sorted k-sample of range(n).""" 
    for i in range(n): 
     if random.randrange(n - i) < k: 
      yield i 
      k -= 1 

穿過數變並以概率
包括在樣本中的每一個numberOfNumbersStillNeeded/numberOfNumbersStillLeft。

演示:

>>> for _ in range(5): 
     print(list(sample(100, 10))) 

[7, 16, 41, 50, 55, 56, 61, 76, 89, 96] 
[5, 13, 24, 28, 34, 35, 40, 64, 80, 95] 
[9, 18, 19, 36, 38, 39, 61, 73, 84, 85] 
[23, 24, 26, 28, 40, 53, 62, 76, 77, 91] 
[2, 12, 21, 41, 60, 68, 70, 72, 90, 91] 
1

爲什麼不能像下面 - 設定seen只長到k到​​尺寸的功能,不一定:

import random 

def sample(population, k): 
    seen = set() 

    for _ in range(k): 
     element = random.randrange(population) 
     while element in seen: 
      element = random.randrange(population) 

     yield element 
     seen.add(element) 

for n in sample(1000000, 10): 
    print(n) 

另一種方法可能可以使用原來的桶設計,但使用索引本身隨機抽樣的不均勻桶:

import random 

def samplegen(start, end, sample_size): 
    random_bucket_indices = random.sample(range(start, end), sample_size) 
    sorted_bucket_indices = sorted(random_bucket_indices) + [end + 1] 
    for index in random_bucket_indices: 
     yield random.randrange(index, sorted_bucket_indices[sorted_bucket_indices.index(index) + 1]) 
+0

'而在看到:通過元素將永遠運行(如果它運行的話)。我想你想在該循環中重複賦值'element'。 – Blckknght

+0

@cdlane除了@Blckknght提到的問題之外,它使用'o(k)'內存,這是'random.sample'生成的列表所使用的內容,但是在呼叫之後,返回的'list'將存在很長時間超過設定立即清理。 – user881300

+0

我認爲這仍然是一個有用的方法(如果實現是正確的),因爲該集合使用'O(迄今爲止產生的元素的數量)'空間,如果發生器的消費者可能不是'O(k)提前退出而不會迭代大部分樣本。在最壞的情況下它確實使用'O(k)'空間,但這並不是一個很大的缺點,因爲它與'random.sample'相同。 – Blckknght

相關問題