2016-09-22 46 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

相关问题