R:runif 的问题:在不到 100 000 步后生成的数字重复(比预期的要多)

机器算法验证 r 均匀分布 随机生成
2022-02-07 02:11:23

执行代码后

RNGkind(kind="Mersenne-Twister")  # the default anyway
set.seed(123)
n = 10^5
x = runif(n)
print(x[22662] == x[97974])

TRUE是输出!

例如,如果我使用RNGkind(kind="Knuth-TAOCP-2002")类似的情况:我在x. 鉴于两个随机发生器的周期,结果似乎极不可能。

难道我做错了什么?我需要生成至少一百万个随机数。

我正在使用带有 R 版本 3.6.2 的 Windows 8.1;平台:x86_64-w64-mingw32/x64(64 位)和 RStudio 1.2.5033。


其他发现:

  1. 有一个包n不同的球,我们选择一个球m次并每次都放回去。概率pn,m所有选择的球都不同等于(nm)/(nmm!).
  2. R 文档指向一个链接,其中提供了用于 64 位机器的 Mersenne-Twister 实现:http: //www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt64.html

均匀抽样[0,1]间隔是通过首先选择一个随机的 64 位整数获得的,所以我计算了 64 位的上述概率和(当p264,105结果相当低)32位案例:

p264,1050.9999999999972...p232,1050.3121...

然后,我尝试了 1000 个随机种子,并计算了所有生成的数字不同时的案例比例:0.303。

所以,目前,我假设由于某种原因,实际使用了 32 位整数。

4个回答

R关于随机数生成的文档末尾有几句话,证实了您对使用 32 位整数的期望,并可能解释您所观察到的内容:

不要依赖来自 RNG 的低阶位的随机性。大多数提供的统一生成器返回转换为双精度的 32 位整数值,因此它们最多采用 2^32 个不同的值,长时间运行将返回重复值(Wichmann-Hill 是例外,并且都给出至少 30 个不同的值位。)

因此,R 中的实现似乎与 Mersenne Twister 的作者网站上的解释不同。可能将其与生日悖论结合起来,您会期望只有 2^16 个数字的重复项的概率为 0.5,并且 10^5 > 2^16。按照文档中的建议尝试 Wichmann-Hill 算法:

RNGkind(kind="Wichmann-Hill") 
set.seed(123)
n = 10^8
x = runif(n)
length(unique(x))
# 1e8

请注意,原始 Wichmann-Hill 随机数生成器具有其下一个数字可以由其前一个数字预测的属性,因此不满足有效 PRNG 的不可预测性要求。参见Dutang 和 Wuertz 的这份文件,2009 年(第 3 节)

只是为了强调的算术232就潜在不同值的数量而言:如果您采样105次从232替换值,你会期望平均232(1(11232)105)1051.1634不同的值,注意到(105)22×2321.1642接近这个赤字

所以你会期待很多更早的例子。有两对set.seed(1)

n = 10^5
set.seed(1)
x = runif(n)
x[21101] == x[56190]
x[33322] == x[50637]

如果你做与第一个类似的事情2000R中的种子默认runif你得到平均值1051.169唯一值,接近计算的期望值。仅有的30.8%这些种子的样本中没有重复105

样本106次,您会期望问题会严重一百倍,并且确实是第一个唯一值的平均数量2000种子是106116.602这些种子都没有产生重复

还有另一种方法可以减少重叠的可能性,同时仍然具有均匀分布:尝试pnorm(rnorm(n))

  set.seed(123)
  n = 10^8
  x = runif(n) 
  length(unique(x))
  # 98845390
  y = pnorm(rnorm(n))
  length(unique(y))
  # 100000000

尽管它违反直觉,但有充分的理由可以解释这种现象,主要是因为计算机使用有限的精度。刚刚在 ArXiv 上发布了一个预印本(2020 年 3 月)(顺便说一下,正如讨论中已经提到的那样)并彻底处理了这个问题。它由一位经验丰富的计算统计研究人员(不是我也不是我的朋友)编写并使用 R。所有代码都是可重现的,您可以轻松地自行检查代码和声明。只是引用似乎回答了您的问题的结论的几行(结论的第一行):

相当不直观(但事实证明,并非出乎意料),生成随机数会导致平局。用于生成na 上的随机数k位架构,我们表明预期的联系数是n2k(1(12k)n). 此外,我们推导出了一个数值稳健的公式来计算这个数字。对于仍然在随机数生成器中使用的 32 位架构(无论是出于历史原因、可重复性还是由于运行时间),生成一百万个随机数时的预期关联数为 116。

引用的版本是 2020 年 3 月 18 日发布的版本。

https://arxiv.org/abs/2003.08009

这里有两个问题。第一个在其他答案中得到了很好的介绍,也就是说:为什么输入参数的某些配置会出现重复项。

另一个很重要:“随机替换”和“已知集合的随机排列”之间存在很大差异。在数学上,随机整数序列包含例如6,6,6,6,6是完全有效的. 大多数 PRNG 无法在其算法中进行完整的“替换”,因此我们最终得到的结果更接近(但不完全是,如已发布问题中的示例所示)一组值的随机排列。事实上,由于大多数 PRNG 根据当前(可能还有几个先前的)值生成下一个值,它们几乎是马尔可夫过程。我们称它们为“随机”,因为我们同意外部观察者无法确定生成器算法,因此下一个出现的数字对于观察者来说是不可预测的。

runif 然后考虑和 之间的区别 sample,后者有一个参数明确指示是否选择有替换或没有替换。