选择无需替换 - 通过改变列表

时间:2015-03-14 18:33:57

标签: python algorithm sampling

我正在寻找Python中的高效函数,它可以在不进行替换的情况下进行样本选择,而是通过实际改变原始列表。也就是说,替代方案:

random.sample(population, k)

在选择样本时从原始列表中删除元素。 列表可以是数百万个项目,并且可能会对样本函数进行数十次后续调用。

理想情况下,我想做类似的事情:

sample_size_1 = 5   
sample_size_2 = 200   
sample_size_3 = 100   
population = range(10000000)  

sample_1 = select_sample(population, sample_size_1)  #population is shrunk  
sample_2 = select_sample(population, sample_size_2)  #population is shrunk again     
sample_3 = select_sample(population, sample_size_3)  #and population is shrunk again

其中population在每次调用select_sample之间有效缩小。

我有一些代码,我可以在这里展示,但我希望已有的东西,或更多" pythonic"比我的while循环。

2 个答案:

答案 0 :(得分:5)

一种简单的方法是shuffle your population,所以初始排序是随机的(如果它不是随机的)。然后从末尾获取元素并将其删除。

您可以通过切片population[-sample_size:]来获取元素,然后使用population[-sample_size:] = []将其删除。

import random

population = list(range(100))

# Shuffle population so the ordering is random.
random.shuffle(population)

for sample_size in [1, 5, 10]:
    sample = population[-sample_size:]
    population[-sample_size:] = []
    print(sample)
    # [79]
    # [66, 89, 81, 0, 38]
    # [18, 39, 90, 36, 11, 32, 63, 65, 72, 67]

如果您只想一次删除一个元素(例如,如果population.pop()为1),您也可以使用sample_size

这样做的功能就是(假设您的人口已经洗牌):

def select_sample(pop, size):
    x = pop[-size:]
    pop[-size:] = []
    return x

答案 1 :(得分:2)

问题是弹出列表的中间确实很慢;最后删除是Ffisegydd's answer中的一个选项,当然很快。作为另一种选择,您可以使用heapq中的堆数据结构。

一开始,您将数据整理到heapq作为元组(random, value);然后使用heappop首先弹出具有最低随机数的值:

import heapq
import random

heap = [ (random.random(), v) for v in samples ]
heapq.heapify(heap)

def select_sample(size):
    return [ heapq.heappop(heap)[1] for _ in range(size) ]

在这种情况下,您应该选择在此列表中弹出列表的末尾,因为它可以更快地保证;但heapq擅长选择固定大小的样本而不是未知大小的人群。