Python有一种内置的方式来返回一个列表生成器,而不是random.sample中的列表



我使用random.sample从一个非常大的范围内采样,这取决于输入负载。有时样本本身非常大,由于它是一个列表,它占用了大量内存。

应用程序不一定使用列表中的所有值。如果random.sample可以返回一个列表生成器而不是列表本身,那就太好了。

现在我有一个包装器,它将大的输入范围分成大小相等的桶,并使用randint从每个n / sample_size桶中选择一个随机数。

编辑:在我的情况下,输入是连续的,我有这个包装函数来模拟随机。示例作为生成器,但这并不能真正复制功能,因为它在最后跳过了一些元素。

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 )

既然您评论说顺序无关紧要(我已经问过它是否必须是随机的还是可以排序),这可能是一个选项:

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]

为什么不像下面这样——set seen只增长到k的函数,而不一定增长到population的大小:

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])

最新更新