【问题标题】:Can I increase randomness by changing my algorithm?我可以通过更改算法来增加随机性吗?
【发布时间】:2017-10-03 22:22:48
【问题描述】:

这是我目前正在使用的生成器:

from random import Random

def shuffle(size):
    """Yield random items from range(size) without replacement."""
    pool = list(range(size))
    rng = Random()
    while pool:
        yield pool.pop(rng.randrange(len(pool)))

当我使用这个生成器时,它的随机性似乎没有那么大。例如,前 4 项通常都出现在结果的前半部分或后半部分。

我正在考虑进行此更改:

def shuffle(size):
    """Yield random items from range(size) without replacement."""
    pool = list(range(size))
    rng = Random()
    while pool:
        i = rng.randrange(len(pool))
        yield pool[i]
        pool[i] = pool[-1]
        del pool[-1]

这类似于random.sample(第 326 行)所做的事情。我不知道这是为了速度还是因为它在不牺牲速度的情况下让它更加随机。

为了简单起见,我更喜欢第一个示例,但第二个示例更加复杂,我不知道 PRNG 是否符合真正的随机性。有没有办法证明第二个例子是否更随机,也许是通过引用 Mersenne Twister 算法(Python 使用的)的弱点?

如果无法以一种或另一种方式证明任何事情,我将如何测试这两种算法的随机性?我知道我需要编写一个包含许多试验的测试,但我不知道如何分析结果。

我不想使用random.sample,因为我希望我的最终列表是部分排序的,我认为生成器会更好。

【问题讨论】:

  • “例如,前 4 项通常都出现在结果的前半部分或后半部分”——这是完全正常的。
  • 第一个版本很好。你的第二个版本除了浪费时间什么都没做。不,你所做的任何事情都不可能对直接使用 MT 有所改善,而且你很可能会使情况变得更糟。不要滚动你自己的加密货币,也不要滚动你自己的 RNG,除非你是一个严肃的数学极客。
  • 编辑澄清我为什么考虑第二个版本。我不是想推出自己的 RNG。

标签: python algorithm random


【解决方案1】:

假设您有一个 list(range(10)) 列表,并且您正在跟踪号码 5 何时返回。

在随机场景中,如果算法运行 100 次,则数字 5 将作为第一个数字返回,与最后一个数字相同。因此,如果您按频率跟踪返回位置的地图,您可能会看到如下内容:

[{0: 10, 1: 11, 
2: 8, 3: 12, 
4: 10, 5: 10, 
6: 9, 7: 10, 
8: 10, 9: 10] 

您也许可以使用 Kolmogorov–Smirnov 检验之类的方法来证明分布不同或相同。

【讨论】:

    【解决方案2】:

    这是一个快速测试:

    - Chi-square distribution
    - Incomplete gamma function
    - Kolmogorov-Smirnov test
    

    如果您不熟悉所有这些数学概念,请不要乱用 RNG。任何“混淆”Python 的内置 MT 都不会让它变得更好,而且有成千上万种方法可以让它变得更糟。提供的工具非常好。保持简单,遵守规则。

    【讨论】:

      【解决方案3】:

      random.py 的私有 _randbelow() 在从 N 个可能性中进行伪随机选择时提供一致性。从randrange()shuffle() 的所有内容构建。除了用更好的底层基础 PRNG 替换 Twister 之外,您无法对其进行任何改进。

      sample() 的编码是为了速度,而不是“提高随机性”。从列表的“中间”弹出(就像您的第一种方法一样)平均需要 O(len(pool)) 时间,因此如果运行到筋疲力尽,您的第一种方法在 size 中需要二次方的时间。从列表的右端弹出需要恒定的时间,因此如果运行到筋疲力尽,您的第二种方法具有更好的O(size) 渐近时间行为。 Python 的sample() 根本不会弹出,因为它不是解决问题的必要费用。

      但请注意,除非列表很长,否则渐近线并不重要。例如,如果size 少于几百,您可能不会注意到两种方法之间在速度上的任何实际差异。但是,如果 size 可以,例如,数百万,您就会这样做。

      我不知道“我不想使用random.sample,因为我希望我的最终列表被部分排序”可能意味着什么。在您展示的任何内容中都没有“最终列表”,并且 任何 随机选择元素而不替换的方法将纯粹偶然地产生“部分排序”的结果。

      这是量化洗牌方法是否“似乎随机”的一种合理可行的方法:

      http://gregbee.ch/blog/determining-the-bias-of-a-shuffle-algorithm

      该(或任何其他可行的方法)基于数千次试运行计算统计数据。

      【讨论】:

      • 当我使用random.sample 时,我不得不对列表中需要排序的部分进行重新排序。当我在我想要排序的部分时,使用生成器可以让我插入带有bisect.insort 的项目。我之所以提到它,是因为我相信人们会问“你为什么不直接使用random.sample?”这实际上与问题无关。
      猜你喜欢
      • 2014-03-14
      • 2012-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-05
      • 1970-01-01
      相关资源
      最近更新 更多