python - 在 O(N) 中不放回地采样 k 个随机排列

标签 python algorithm permutation

我需要高效地对列表进行一些独特的随机排列,而无需替换。我目前的做法:

total_permutations = math.factorial(len(population))
permutation_indices = random.sample(xrange(total_permutations), k)
k_permutations = [get_nth_permutation(population, x) for x in permutation_indices]

哪里get_nth_permutation确实像听起来一样高效(意思是 O(N))。但是,这仅适用于 len(population) <= 20 ,仅仅因为 21!太长了以至于xrange(math.factorial(21))不会工作:

OverflowError: Python int too large to convert to C long

是否有更好的算法可以在 O(N) 中对 k 个唯一排列进行采样而不用放回?

最佳答案

在某种程度上,没有必要使用get_nth_permutation 来获取排列。只需洗牌即可!

>>> import random
>>> l = range(21)
>>> def random_permutations(l, n):
...     while n:
...         random.shuffle(l)
...         yield list(l)
...         n -= 1
... 
>>> list(random_permutations(l, 5))
[[11, 19, 6, 10, 0, 3, 12, 7, 8, 16, 15, 5, 14, 9, 20, 2, 1, 13, 17, 18, 4], 
 [14, 8, 12, 3, 5, 20, 19, 13, 6, 18, 9, 16, 2, 10, 4, 1, 17, 15, 0, 7, 11], 
 [7, 20, 3, 8, 18, 17, 4, 11, 15, 6, 16, 1, 14, 0, 13, 5, 10, 9, 2, 19, 12], 
 [10, 14, 5, 17, 8, 15, 13, 0, 3, 16, 20, 18, 19, 11, 2, 9, 6, 12, 7, 4, 1], 
 [1, 13, 15, 18, 16, 6, 19, 8, 11, 12, 10, 20, 3, 4, 17, 0, 9, 5, 2, 7, 14]]

对于 len(l) > 15 和 n < 100000,此列表中出现重复项的几率是压倒性的,但是如果您需要保证,或者对于较低的值len(l),如果这是一个问题,只需使用 set 来记录和跳过重复项(尽管正如您在评论中观察到的那样,如果 n 接近 len(l)!,这将停止)。像这样的东西:

def random_permutations(l, n):    
    pset = set()
    while len(pset) < n:
        random.shuffle(l)
        pset.add(tuple(l))
    return pset

然而,随着 len(l) 变得越来越长,random.shuffle 变得越来越不可靠,因为列表的可能排列数增加超过了周期随机数发生器!因此,并非 l 的所有排列都可以通过这种方式生成。到那时,您不仅需要将 get_nth_permutation 映射到一系列随机数,您还需要一个能够生成 0len(l)!分布比较均匀。这可能需要您找到更强大的随机性来源。

但是,一旦有了它,解决方案就很简单 Mark Ransom的答案。

要了解为什么 random.shuffle 对于大型 len(l) 变得不可靠,请考虑以下内容。 random.shuffle 只需要在 0len(l) - 1 之间选择随机数。但它根据其内部状态选择这些数字,并且它只能采用有限(且固定)数量的状态。同样,您可以传递给它的可能种子值的数量是有限的。这意味着它可以生成的唯一数字序列集也是有限的;调用该集合 s。对于len(l)! > len(s),某些排列永远无法生成,因为与这些排列对应的序列不在 s 中。

这成为问题的确切长度是多少?我不知道。但就其值(value)而言,由 random 实现的梅森扭曲周期为 2**19937-1 . shuffle docs笼统地重申我的观点;另请参阅维基百科对此事的看法here .

关于python - 在 O(N) 中不放回地采样 k 个随机排列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10232338/

相关文章:

python - 在 Windows CMD 中更改卷时 sys.path 中的奇怪行为

c++ - 快速排序代码解释

javascript - 排列需要帮助编码

python - 算法:类(class)顺序

algorithm - 二叉树的镜像

c++ - 创建变量之间的运算符排列

python - 无论顺序如何,都生成重复列表

python - 索引范围内的模糊重复项

python - 是否可以使用正则表达式直接更改字符串而不是返回更改后的字符串版本?

python - 在 Django 项目中使用哪个动态国际化系统?