Is There Any Way To Generate Uncorrelated Random Variables Using Python?
Solution 1:
The math on RNGs is solid. These days most popular implementations are too. As such, your conjecture of
is generated by a formula, therefore they are correlated.
is incorrect.
But if you really truly deeply think that way, there is an out: hardware random number generators. The site at random.org has been providing hardware RNG draws "as a service" for a long time. Here is an example (in R, which I use more, but there is an official Python client):
R>library(random)R>randomNumbers(min=1,max=20000)# your range, default numberV1V2V3V4V5
[1,] 532194525203 136465462
[2,] 4611 108143694 12731566
[3,] 11884198971601 10652791
[4,] 174279524 7522 1051 9432
[5,] 5426 5079 2232 2517 4883
[6,] 138079194 199801706 9205
[7,] 1304316250128272161 10789
[8,] 7060 6008 9110 8388 1102
[9,] 12042193422001 177803100
[10,] 116904986 4389 1418717191
[11,] 19574136153129 171765590
[12,] 111045361 8000 5260 343
[13,] 7518 7484 7359 1684012213
[14,] 149141991 199521012714981
[15,] 1352818602101821075 16480
[16,] 9631 17160198081166210514
[17,] 4827 139601700386411159
[18,] 8939 7095 161021983615490
[19,] 8321 6007 1787 6113 17948
[20,] 9751 7060 8355 1906515180R>
Edit: The OP seems unconvinced, so there is a quick reproducible simulation (again, in R because that is what I use):
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>
So you see that as we go from 10 to 100 to 1000 replications of just 100 U(0,1), the correlations estimate goes to zero.
We can make this a little nice with a plot, recovering the same data and some more:
R> set.seed(42)R> x <- 10^(1:5) # powers of ten from 1 to 5, driving 10^1 to 10^5 simsR> 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")
Solution 2:
Short answer: Use a Bays-Durham shuffle on your random seeds.
Longer answer:
I'm sure you know that the pseudo-random numbers given by computer algorithms are not truly random--they are just meant to pass most tests for randomization and thus be "good enough" for most uses. The same is true for uncorrelated random variables: you will never get truly uncorrelated ones, but your goal should be to get them to pass as many correlation tests as possible and be "good enough" for your purposes.
The main way that the standard, linear congruential modulators fail correlation tests is when you look at a small region of the 2-space generated by the numbers. The pairs of numbers show obvious lines when graphed and thus are not truly uncorrelated. This only matters when you look at a very small region of all the generated number pairs. Is this what you need to do? Note that Python's random()
function uses the "Mersenne Twister" rather than a linear congruential modulator, so it is less likely to fail such a test. See Wikipedia's list of the disadvantages of the Mersenne Twister to see if Python's random number generator is or is not good enough for your purposes. Note that Python's implementation is shown in detail later in the page.
I wrote routines in Borland Delphi (Object Pascal and x86 assembler) to avoid correlation. I have switched to Python but have not yet rewritten those routines. The idea of a Bays-Durham shuffle is to use the built-in random number generator to give you a random integer (the one that is used to make a floating-point number between 0 and 1). You then use that integer to point into an array of previously-generated random integers. You pick the integer pointed to and replace it in the array with your newly generated integer. Return the integer that used to be in the array, and if need be convert that to a number between 0 and 1.
I implemented this with an array of 32 integers and tested this new generator. This now passed the correlation test that Delphi's random number generator failed. I repeat, this would not pass all correlation tests, but it did pass more than the standard generator, and it was definitely good enough for my uses.
If you need to see a Python implementation of this, ask and I'll try to make the time to write one. Until then, look up "Bays-Durham shuffle". I learned of it from the book Numerical Recipes. Here is a Fortran version of that chapter. Here is the entire 2nd edition in C in Empanel format and here it is in PDF--find Chapter 7 Section 7.1. Source code for out-of-date editions is available in a variety of languages, including Fortran (I think), C, and Pascal. I downloaded the 2nd edition C version text and 1st edition Pascal code some years ago and used those for my own coding in Pascal.
Post a Comment for "Is There Any Way To Generate Uncorrelated Random Variables Using Python?"