假设我想生成两个随机变量X
和Y
,它们在[0,1]
中不相关且均匀分布。
生成这样的非常天真的代码如下,它将random
函数调用两次:
import random
xT=0
yT=0
xyT=0
for i in range(20000):
x = random.random()
y = random.random()
xT += x
yT += y
xyT += x*y
xyT/20000-xT/20000*yT/20000
然而,随机数实际上是由公式生成的伪随机数,因此它们是相关的。
如何生成两个不相关的(或尽可能少的相关)随机变量?
答案 0 :(得分:7)
关于RNG的数学是可靠的。现在最流行的实现也是如此。因此,您的猜想
由公式生成,因此它们是相关的。
不正确。
但如果你真的非常深思这么想,那就有了:hardware random number generators。 random.org的网站长期以来一直在提供硬件RNG“即服务”。这是一个例子(在R中,我使用了更多,但有is an official Python client):
R> library(random)
R> randomNumbers(min=1, max=20000) # your range, default number
V1 V2 V3 V4 V5
[1,] 532 19452 5203 13646 5462
[2,] 4611 10814 3694 12731 566
[3,] 11884 19897 1601 10652 791
[4,] 17427 9524 7522 1051 9432
[5,] 5426 5079 2232 2517 4883
[6,] 13807 9194 19980 1706 9205
[7,] 13043 16250 12827 2161 10789
[8,] 7060 6008 9110 8388 1102
[9,] 12042 19342 2001 17780 3100
[10,] 11690 4986 4389 14187 17191
[11,] 19574 13615 3129 17176 5590
[12,] 11104 5361 8000 5260 343
[13,] 7518 7484 7359 16840 12213
[14,] 14914 1991 19952 10127 14981
[15,] 13528 18602 10182 1075 16480
[16,] 9631 17160 19808 11662 10514
[17,] 4827 13960 17003 864 11159
[18,] 8939 7095 16102 19836 15490
[19,] 8321 6007 1787 6113 17948
[20,] 9751 7060 8355 19065 15180
R>
编辑: OP似乎不相信,所以有一个快速可重现的模拟(再次,在R中,因为这是我使用的):
R> set.seed(42) # set seed for RNG
R> mean(replicate(10, cor(runif(100), runif(100))))
[1] -0.0358398
R> mean(replicate(100, cor(runif(100), runif(100))))
[1] 0.0191165
R> mean(replicate(1000, cor(runif(100), runif(100))))
[1] -0.00117392
R>
所以你看到,当我们从10到100再到1000次重复只有100 U(0,1)时,相关性估计变为零。
我们可以通过绘图,恢复相同的数据以及更多内容来使这一点变得更好:
R> set.seed(42)
R> x <- 10^(1:5) # powers of ten from 1 to 5, driving 10^1 to 10^5 sims
R> y <- sapply(x, function(n) mean(replicate(n, cor(runif(100), runif(100)))))
R> y # same first numbers as seed reset to same start
[1] -0.035839756 0.019116460 -0.001173916 -0.000588006 -0.000290494
R> plot(x, y, type='b', main="Illustration of convergence towards zero", log="x")
R> abline(h=0, col="grey", lty="dotted")
答案 1 :(得分:3)
简答:在随机种子上使用Bays-Durham shuffle。
更长的回答:
我确定你知道计算机算法给出的伪随机数不是真正随机的 - 它们只是为了通过大多数随机化测试,因此足够好&#34;对于大多数用途。对于不相关的随机变量也是如此:你永远不会得到真正不相关的随机变量,但你的目标应该是让它们通过尽可能多的相关性测试,并且足够好&#34;为了你的目的。
标准线性同余调制器失败相关性测试的主要方式是当您查看由数字生成的2空间的小区域时。成对的数字在绘制时显示出明显的线条,因此不是真正不相关的。这仅在您查看所有生成的数字对的非常小的区域时才重要。这是你需要做的吗?请注意,Python的random()
函数使用&#34; Mersenne Twister&#34;而不是线性同余调制器,因此不太可能失败这样的测试。请参阅Wikipedia's list of the disadvantages of the Mersenne Twister,了解Python的随机数生成器是否适合您的目的。请注意,Python的实现详细显示了later in the page。
我在Borland Delphi(Object Pascal和x86汇编程序)中编写例程以避免相关性。我已经切换到Python但尚未重写这些例程。 Bays-Durham shuffle的想法是使用内置的随机数生成器为您提供一个随机整数(用于生成0到1之间的浮点数的整数)。然后使用该整数指向先前生成的随机整数数组。您可以选择指向的整数,并使用新生成的整数将其替换为数组。返回以前在数组中的整数,如果需要将其转换为0到1之间的数字。
我使用32个整数数组实现了这个并测试了这个新的生成器。这现在通过了Delphi的随机数发生器失败的相关性测试。我再说一遍,这不会通过所有相关性测试,但它确实传递的不仅仅是标准的生成器,而且它对我的使用来说绝对够用。
如果您需要查看Python的实现,请询问并且我将尝试花时间编写一个。在那之前,查看&#34; Bays-Durham shuffle&#34;。我从书中找到了它 Numerical Recipes 。该章的Here is a Fortran version。 Empanel格式的Here is the entire 2nd edition in C和here it is in PDF - 查找第7章第7.1节。过时版本的源代码有多种语言版本,包括Fortran(我认为),C和Pascal。几年前我下载了第2版C版文本和第1版Pascal代码,并在Pascal中使用了我自己编写的代码。