繁体   English   中英

从带有排除项的 Python 列表中随机抽取 N 个元素的最快方法

[英]Fastest way to randomly sample N elements from a Python list with exclusions

假设我有一个包含 20 个唯一数字的列表,我想从列表中随机抽取N = 3数字。 对于每个数字,存在一个限制,即它不能与字典exclusions中给出的其他数字一起出现在最终样本中。

lst = list(range(20))
N = 3
exclusions = {0: [5], 1: [3, 13], 2: [10], 3: [1, 4, 18],
              4: [3, 15, 17, 19], 5: [0], 6: [12], 7: [13, 15],
              8: [10], 9: [16], 10: [2, 8, 12], 11: [15],
              12: [6, 10], 13: [1, 7], 14: [], 15: [4, 7, 11],
              16: [9], 17: [4], 18: [3], 19: [4]}

现在我正在使用试错法:

import random
sample = {random.choice(lst)}
n_sample = 1
while n_sample < N:
    s = random.choice([x for x in lst if x not in sample])
    if not set(exclusions[s]).isdisjoint(sample):
        sample.add(s)
        n_sample += 1

print(sample)
# {10, 2, 12}

但是,这是非常低效的,并且无法捕捉到根本没有解决方案的情况,尤其是当N很大时。 谁能在 Python 中提出一种有效的方法来做到这一点?

如果排除是预先计算的,您还可以预先计算满足排除约束的允许集。 您可以按照@Sembei Norimaki's建议执行此操作:

用所有数字制作一组,然后选择第一个数字。 然后查看限制字典并从您的集合中删除限制。 对其他 N-1 个数字重复其余元素

然后在运行时,您可以随机选择一个允许的集合,并从该集合中采样您的 N 个数字。

注意:此处采样值的结果分布将不均匀。 这是因为具有更多排除项的元素将因此被排除在更多允许的集合之外。 采样时,给定大量样本,您的分布将收敛到您从中采样的分布。

正如已经建议的那样,集合是解决这些问题的好伴侣:

如果您需要随机选择

[x for x in lst if x not in sample]

可以使用集合改进

candidates = set(sample) - set(last)

无论如何,您必须避免在 while 循环中使用 random :

暗示

我不清楚如何处理“无解决方案”的情况:

lst = set(range(20))
N = 3
exclusions = {0: [5], 1: [3, 13], 2: [10], 3: [1, 4, 18],
              4: [3, 15, 17, 19], 5: [0], 6: [12], 7: [13, 15],
              8: [10], 9: [16], 10: [2, 8, 12], 11: [15],
              12: [6, 10], 13: [1, 7], 14: [], 15: [4, 7, 11],
              16: [9], 17: [4], 18: [3], 19: [4]}
exclusions = {k:set(v) for k,v in exclusions.items()}
sample = {random.choice(list(lst))}
n_sample = 1
while n_sample < N:
    found = False
    for s in lst-sample:
        if not exclusions[s].isdisjoint(sample):
            sample.add(s)
            n_sample += 1
            found = True
            break
    if not found:
        print('No solution')
        break
    
print(sample)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM