我有一个包含大约3900个元素的列表,我需要随机置换以生成统计分布。我环顾四周,发现这个Maximal Length of List to Shuffle with Python random.shuffle解释了Python中PRNG的周期是2**19937-1
,这导致列表的最大长度为2080
,然后才能生成全部可能的排列。我只生成300-1000个列表的排列,因此我不太可能产生重复的排列,但是,由于这产生了统计分布,我希望将所有可能的排列作为潜在样本。
答案 0 :(得分:2)
有比MT更长的PRNG,但很难找到它们。
获得所有3090!组合,你需要40,905位的熵。那大概是5kb。你应该能够从random.org这样的地方抓取一大块字节,没有任何问题。要获得精确平衡,您必须添加一些并进行拒绝采样。即,一次抓取12位(0..4095),并拒绝高于当前循环索引的数字。这可能会增加所需的位数,但可能不会超过8kb。
答案 1 :(得分:1)
我同意@ user2357112它不太可能是一个真正的问题 - 但似乎你应该能够使用标准的random
模块,使所有的排列至少成为可能。< / p>
你可以做一个分而治之的方法。使用初始种子将列表分成2个列表,每个列表大约2000个。此类分区的数量大约为C(4000,2000)
,大约为1.66 x 10^1202
。这比周期少,这表明至少可以使用random.sample()
生成所有此类分区。然后 - 重新设置随机数发生器并置换上半部分。然后 - 第二次重新训练并将下半场置换。也许在重新设定之前几乎没有时间延迟,因此您不会遇到涉及系统时钟分辨率的问题。您还可以尝试将初始列表随机分区为更大数量的较小列表。
在数学上,很容易看出,如果您将列表随机分区为子列表,以便每个分区具有相同的可能性,然后以这样的方式置换每个子列表,使得所有子列表排列具有相同的可能性,并将这些子列表排列粘合在一起为了得到一个完整列表排列,那么所有整列排列都是可能的。
这是一个实现:
import random, time
def permuted(items, pieces = 2):
sublists = [[] for i in range(pieces)]
for x in items:
sublists[random.randint(0,pieces-1)].append(x)
permutedList = []
for i in range(pieces):
time.sleep(0.01)
random.seed()
random.shuffle(sublists[i])
permutedList.extend(sublists[i])
return permutedList
我不确定time.sleep(0.01)
是否真的需要。我担心的是,如果种植在一毫秒内发生,那么在某些系统上可能会使用相同的种子。
作为最后的评论,仅仅因为上述函数(适当选择pieces
)不能通过简单的计数参数显示错过某些排列(比较排列的数量与初始状态的数量)这本身并不构成所有排列实际上都是可能的证明。这将需要对随机数生成器,播种它的散列函数以及混洗算法进行更详细的分析。