【问题标题】:Independent random shuffling within a loop循环内的独立随机改组
【发布时间】:2015-02-17 07:21:18
【问题描述】:

我正在使用模块 random 来洗牌 n 元素的数组。我需要这样做m 次,我不完全确定每次发生的洗牌是独立的。

请看下面的示例:

for i in range(10):
    a = list(range(1,20))
    random.shuffle(a)
    print("\n\nSequence of numbers ")
    for item in a:
        print(item)

我可以完全确定我第二次shuffle list a 将完全独立于第一次吗?

查看结果我的印象是输出不是独立的。但也许这只是我的印象。

例如,我得到 4 个数字和 4 个重复的输出如下 [1, 3, 2, 4], [1, 3, 2,4], [4, 1, 3, 2] 和[1、4、3、2]。这是偶然发生的吗?可能是。但我想确定。

上下文:可能是我想订购我要给 m 个学生的考试的第 n 个问题。但我希望这个过程对每个学生都是独立完成的。

【问题讨论】:

  • 什么输出?你为什么会从中得到这种印象?
  • 人类在评估随机性方面是notoriously bad。您需要多大程度地确定洗牌是“独立的”?独立是什么意思 - 请注意,完全相同的顺序可能会随机再次出现。你考虑过urandom,如果它那么重要吗?
  • 是的,我知道人类不擅长评估随机性。但我只是想知道我是否需要在我的代码中采取一些额外的措施(例如重置种子),或者这样是否可以。我对这个python模块不熟悉。
  • 例如,我得到的输出如下
  • 偶然发生吗?当然,你每次都会得到[1, 2, 3, 4],这并不意味着它不是随机的。 是偶然发生的吗?不,random 是严格的 psuedorandom,而不是真正随机的。这有关系吗?几乎可以肯定不是!如果两个学生以相同的顺序(或与a process they know little about 有某种关联的顺序)回答问题,为什么这很重要?

标签: python loops random shuffle


【解决方案1】:

你可以测试一下。请注意,数字 1,2,3,4 恰好有 4!=24 个排列。您应该期望在随机抽样中,这些排列中的每一个都同样可能出现。为了向自己证明这会导致您正在寻找的均匀分布,请对序列进行采样:

import random, math
from collections import Counter

samples = 1000000

a = list(range(1,5))
C = Counter()

for _ in xrange(samples):
    random.shuffle(a)
    C[tuple(a)] += 1

import pylab as plt
permutations = math.factorial(4)
expected = float(samples)/permutations
plt.plot(C.values())
plt.plot([0,permutations],[expected,expected],'r--')
plt.ylim(0,expected*2.01)   
plt.show()

请注意,红色虚线是理论预期值,蓝线是我们从采样中获得的值。由此我非常有信心我们得到了一个统一的分布,但我们总是可以使用Kolmogorov Smirnov test 来量化它。 测试的是序列之间的相关性。可以再次使用具有一定时间延迟生成的序列对来测试这一点,但是 python random.shuffle 使用的 Fisher-Yates shuffle 在防止这种情况方面做得很好。

【讨论】:

    【解决方案2】:

    出于实际目的,对 random.shuffle 的连续调用是独立的。它需要 log(N!)/log(2) 位状态来描述元素的唯一顺序,并且对 random.getstate() 的快速检查表明默认的伪随机数生成器实际上使用了 20000 位状态。为了达到有意义的重叠,我们需要消耗所有这些熵。

    所以我们需要 M*log(N!)/log(2)>=20000 来获得已知的(但很难预测)相关性。这不是不可能想象的。 200 名学生大约有 28 个问题。然而,这种相关性超过它们有 304888344611713860501504000000 个可能的排序这一事实的可能性很小。

    【讨论】:

      【解决方案3】:

      这是来自 Python 的 random 模块的实际代码:

      for i in reversed(xrange(1, len(x))):
          # pick an element in x[:i+1] with which to exchange x[i]
          j = _int(random() * (i+1))
          x[i], x[j] = x[j], x[i]
      

      在我看来像一个合适的 Fisher-Yates,并且完全独立于 任何以前的运行。

      【讨论】:

        猜你喜欢
        • 2018-06-27
        • 1970-01-01
        • 2012-05-20
        • 1970-01-01
        • 2013-05-02
        • 1970-01-01
        • 1970-01-01
        • 2018-03-30
        • 1970-01-01
        相关资源
        最近更新 更多