【问题标题】:Pick subset from list at random and maintain equal number of picks overall in python从列表中随机选择子集并在 python 中保持相同数量的选择
【发布时间】:2014-10-21 16:58:04
【问题描述】:

给定一个这样的字符串列表(实际上我有一个更长的列表,但在这里我会保持简短):

items=['fish','headphones','wineglass','bowtie','cheese','hammer','socks']

我想从这个列表中随机选择一个子集,比如 3 个,这样项目只能被选择一次。这很容易使用以下内容:

import itertools
import random
def random_combination(iterable, r):
    "Random selection from itertools.combinations(iterable, r)"
    pool = tuple(iterable)
    n = len(pool)
    indices = sorted(random.sample(xrange(n), r))
    return tuple(pool[i] for i in indices)

items=['fish','headphones','wineglass','bowtie','cheese','hammer','socks']
randomPick=random_combination(items,3)

接下来,为了痛苦,我不想只做一次,而是几次说10次。最终产品将是 10 个仅随机选择一次的项目列表,其约束条件是,在这 10 个列表中,项目在列表中呈现相同的次数。例如,我想避免“袜子”被拿起 10 次,而“锤子”只被拿起一次。

这是我坚持的步骤,我根本不知道足够的编程或对 python 中可用函数的了解来执行这样的事情。

谁能帮忙?

【问题讨论】:

  • 如果所有内容都只选择一次,那么结果列表中的所有内容都将被选择相同的次数(即一次)。

标签: python random itertools


【解决方案1】:

以下代码可能会有所帮助。它会弹出一个随机元素,直到iterable 的(副本)为空,然后从整个列表重新开始。缺点是每个项目都被挑选一次,然后才能第二次挑选一个项目。但是,从输出中可以看出,项目的分布最终大致相等。

import random

def equal_distribution_combinations(iterable, n, csize):
    """
    Yield 'n' lists of size 'csize' containing distinct random elements
    from 'iterable.' Elements of 'iterable' are approximately evenly
    distributed across all yielded combinations.
    """
    i_copy = list(iterable)

    if csize > len(i_copy):
        raise ValueError(
            "csize cannot exceed len(iterable), as elements could not distinct."
        )

    for i in range(n):
        comb = []
        for j in range(csize):
            if not i_copy:
                i_copy = list(iterable)

            randi = random.randint(0, len(i_copy) - 1)

            # If i_coppy was reinstantiated it would be possible to have
            # duplicate elements in comb without this check.
            while i_copy[randi] in comb:
                randi = random.randint(0, len(i_copy) - 1)
            comb.append(i_copy.pop(randi))

        yield comb

编辑

对 Python 3 致歉。对 Python 2 函数的唯一更改应该是 range -> xrange

编辑 2(回答评论问题)

equal_distribution_combinations 应该导致任何ncsizeiterable 的长度均匀分布,只要csize 不超过len(iterable)(因为组合元素不能不同)。

这是使用您评论中的特定数字进行的测试:

items = range(30)
item_counts = {k: 0 for k in items}

for comb in equal_distribution_combinations(items, 10, 10):
    print(comb)
    for e in comb:
        item_counts[e] += 1

print('')
for k, v in item_counts.items():
    print('Item: {0}  Count: {1}'.format(k, v))

输出:

[19, 28, 3, 20, 2, 9, 0, 25, 27, 12]
[29, 5, 22, 10, 1, 8, 17, 21, 14, 4]
[16, 13, 26, 6, 23, 11, 15, 18, 7, 24]
[26, 14, 18, 20, 16, 0, 1, 11, 10, 2]
[27, 21, 28, 24, 25, 12, 13, 19, 22, 6]
[23, 3, 8, 4, 15, 5, 29, 9, 7, 17]
[11, 1, 8, 28, 3, 13, 7, 26, 16, 23]
[9, 29, 14, 15, 17, 21, 18, 24, 12, 10]
[19, 20, 0, 2, 25, 5, 22, 4, 27, 6]
[12, 13, 24, 28, 6, 7, 26, 17, 25, 23]

Item: 0  Count: 3
Item: 1  Count: 3
Item: 2  Count: 3
Item: 3  Count: 3
Item: 4  Count: 3
Item: 5  Count: 3
Item: 6  Count: 4
Item: 7  Count: 4
Item: 8  Count: 3
Item: 9  Count: 3
Item: 10  Count: 3
Item: 11  Count: 3
Item: 12  Count: 4
Item: 13  Count: 4
Item: 14  Count: 3
Item: 15  Count: 3
Item: 16  Count: 3
Item: 17  Count: 4
Item: 18  Count: 3
Item: 19  Count: 3
Item: 20  Count: 3
Item: 21  Count: 3
Item: 22  Count: 3
Item: 23  Count: 4
Item: 24  Count: 4
Item: 25  Count: 4
Item: 26  Count: 4
Item: 27  Count: 3
Item: 28  Count: 4
Item: 29  Count: 3

可以看出,项目是均匀分布的。

【讨论】:

  • 谢谢!这似乎很不错。只是为了检查一下:你认为如果我对 30 个项目的列表进行 say 操作并想选择 10 个(10 次)它会导致相同的近似相似分布吗?
  • 糟糕,有一个错误。函数中的一行应该是 for i in range(n) 而不是显式的 range(10)
  • 进一步改进了功能。答案已更新。
  • @Narpar1217 当您作为作者查看原始答案的第一个和第二个结果(可在编辑历史中找到)时,您就会知道在第三个结果中您将看到“bowtie”这个词.如果输入列表有 9 个项目,则第三个“随机”输出将是完全已知的。这并不是对您的代码的批评,而是对原始请求的合理性感到困惑。
  • @gboffi 你能解释一下吗?这是因为这里给出的列表非常小,还是与更大的列表不同(30 个项目被随机均匀地挑选到 10 个列表中)?
【解决方案2】:

我会这样做:

items = set(items)
res = []
for _ in xrange(10):
    r = random.sample(items, 3)
    res.append(r)
    items -= set(r)

所有这些都是抓取 3 个元素,存储它们,然后从原始列表中减去它们,这样它们就不会被再次选择。

【讨论】:

  • 好吧,这很简单,但这能保证项目在 10 次迭代中重复相同的次数吗?
【解决方案3】:

好的,最后我采取了以下措施。 这是一个更受限制的实现,我设置了我希望看到一个项目重复的次数,例如在 10 个列表中,我希望每个项目被选择 5 次:

List = ['airplane',
            'fish',
            'watch',
            'balloon',
            'headphones',
            'wineglass',
            'bowtie',
            'guitar',
            'desk',
            'bottle',
            'glove'] #there is more in my final list but keeping it short here
numIters = 5
numItems = len(List)
finalList=[]
for curList in range(numIters):
    random.shuffle(List)
    finalList.append(List[0 : numItems/2]) #append first list
    finalList.append(List[numItems/2 : -1]) #append second list

return finalList

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-28
    • 2012-02-21
    • 1970-01-01
    • 1970-01-01
    • 2012-11-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多