繁体   English   中英

随机选择列表中的x个*不同*元素

[英]Efficiently choosing x *different* elements in a list at random

我有一个清单:

a = [1,2,1,1,3,5,6,2]

我想从此列表中随机选择3个元素,但它们必须全部不同

我需要保留每个元素的“权重”,因此无法从set(a)进行采样。

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

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

10分钟后运行您的代码,我不得不退出该过程,因为它仍在继续,因此无论您选择什么都将是一个重大改进。

如果您要在列表中的重复项与实际项目的比率更大,并且您想要一个非常大的样本量,那么使用洗牌会更有效,否则洗牌的成本会使其效率不如简单地使用集合和选择,

while count < sampleSize: # where sampeSize is the number of values you want
    s = random.sample(a, 1)
    filter(lambda x: x != s, a)
    mysample.append(s)
    count += 1

这可能比必要的要复杂,但是这里是一个使用修改版的油藏采样的实现

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

暂无
暂无

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

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