Python 有效地随机选择列表中的x*个不同*元素

Python 有效地随机选择列表中的x*个不同*元素,python,list,select,random,weighted,Python,List,Select,Random,Weighted,我有一份清单: a = [1,2,1,1,3,5,6,2] 我想从这个列表中随机选择3个元素,但它们必须都不同 我需要保留每个元素的“重量”,所以从seta取样是不可能的 到目前为止,我的解决方案是: while condition == False: mysample = random.sample(a, 3) if len(set(mysample)) - len(mysample) !=0: condition = False else:

我有一份清单:

a = [1,2,1,1,3,5,6,2]
我想从这个列表中随机选择3个元素,但它们必须都不同

我需要保留每个元素的“重量”,所以从seta取样是不可能的

到目前为止,我的解决方案是:

while condition == False:
    mysample = random.sample(a, 3)
    if len(set(mysample)) - len(mysample) !=0:
        condition = False
    else:
        condition = True

但这迫使我尽可能多次地重新采样,以使元素完全不同。这对于小采样很有效,但是对于大采样,我的代码会变得非常低效…

您可以洗牌并获取前三个不重复的元素:

import random
random.shuffle(your_list)
three_elements = set()
for v in your_list:
  if len(three_elements) == 3: break
  three_elements.add(v)
根据实际不同数量与元素的比率,不同的方法将具有不同的优势:

In [7]: a = [choice(range(10000)) for _ in range(100000)]

In [6]: import random

In [7]: a = [choice(range(10000)) for _ in range(100000)]

In [8]: %%timeit
random.shuffle(a)
three_elements = set()
for v in a:
    if len(three_elements) == 5000:
        break
    if not v in three_elements:
        three_elements.add(v)
   ...: 
10 loops, best of 3: 36.5 ms per loop

In [9]: %%timeit                          
l = []
seen = set()
while len(l) < 5000:
    ch = choice(a)
    if ch not in seen:
        l.append(ch)
        seen.add(ch)
   ...: 
100 loops, best of 3: 5.16 ms per loop
运行代码10分钟后,我不得不退出进程,因为它仍然在运行,所以无论您选择什么都将是一个重大改进


如果列表中的重复项与实际项的比率更大,并且您需要非常大的样本量,则使用洗牌将更有效率,否则洗牌的成本将使其效率低于简单使用集合和选项的效率,

这可能比必要的更复杂,但这里有一个使用修改版本的实现


如果您给它一个包含重复项的列表,它可以返回重复项。OP想要一个没有重复项的列表,但该列表仍然具有权重,以便更常见的元素比不常见的元素更容易出现。@Aruistante random.samam辩诉,3在我的机器上生成[1,1,6]。它返回列表中三个1中的两个。示例1,然后删除原始列表中出现的所有1。重复此操作,直到获得所需数量的图元。看看这里:@JohnKugelman啊,等等,他们后来确实说它是基于索引的唯一性,而不是基于值。它们没有那么好地突出显示。我的坏。最高效和优雅!对于小列表。
l = []
seen = set()
while len(l) < 3:
    ch = choice(a)
    if ch not in seen:
        l.append(ch)
        seen.add(ch)
print(l)
In [7]: a = [choice(range(10000)) for _ in range(100000)]

In [6]: import random

In [7]: a = [choice(range(10000)) for _ in range(100000)]

In [8]: %%timeit
random.shuffle(a)
three_elements = set()
for v in a:
    if len(three_elements) == 5000:
        break
    if not v in three_elements:
        three_elements.add(v)
   ...: 
10 loops, best of 3: 36.5 ms per loop

In [9]: %%timeit                          
l = []
seen = set()
while len(l) < 5000:
    ch = choice(a)
    if ch not in seen:
        l.append(ch)
        seen.add(ch)
   ...: 
100 loops, best of 3: 5.16 ms per loop
import itertools
import random

def element_at(iterable, index, default=None):
    return next(itertools.islice(iterable, index, None), default)

def sample_unique(iterable, size):
    S = set()
    for index, item in enumerate(iterable):
        if len(S) < size:
            S.add(item)
        else:
            r = random.randint(0, index)
            if r < size:
                other = element_at(S, r)
                if item not in S:
                    S.remove(other)
                    S.add(item)
    return S