【发布时间】:2017-06-12 13:28:49
【问题描述】:
我正在尝试找出在 python 中生成许多随机数的最佳方法。困难的部分是我不知道在运行之前我需要多少个数字
我有一个程序一次使用一个随机数,但它需要多次这样做。
到目前为止我尝试过的事情是:
- 使用
random.random()一次生成一个随机数 - 使用
np.random.rand()一次生成一个随机数 - 使用
np.random.rand(N)在一批N中生成随机数 - 使用
np.random.rand(N)在一批 N 中生成随机数,并在第一个 N 全部使用后创建一个新批次(我尝试了两种不同的实现,两者都比一次只生成一个数字慢)
在下面的脚本中,我比较了前三种方法(对于均匀分布和正态分布的随机数)。
我不知道p 函数是否真的有必要,但我想在每种情况下用随机数做等效的事情,这似乎是最简单的方法。
#!/bin/python3
import time
import random
import numpy as np
def p(x):
pass
def gRand(n):
for i in range(n):
p(random.gauss(0,1))
def gRandnp1(n):
for i in range(n):
p(np.random.randn())
def gRandnpN(n):
rr=np.random.randn(n)
for i in rr:
p(i)
def uRand(n):
for i in range(n):
p(random.random())
def uRandnp1(n):
for i in range(n):
p(np.random.rand())
def uRandnpN(n):
rr=np.random.rand(n)
for i in rr:
p(i)
tStart=[]
tEnd=[]
N=1000000
for f in [uRand, uRandnp1, uRandnpN]:
tStart.append(time.time())
f(N)
tEnd.append(time.time())
for f in [gRand, gRandnp1, gRandnpN]:
tStart.append(time.time())
f(N)
tEnd.append(time.time())
print(np.array(tEnd)-np.array(tStart))
这个计时脚本输出的一个代表例子是:[ 0.26499939 0.45400381 0.19900227 1.57501364 0.49000382 0.23000193]
前三个数字用于 [0,1) 上的均匀随机数,接下来的三个数字用于正态分布数字(mu=0,sigma=1)。
对于任何一种类型的随机变量,最快的方法(这三种)是一次生成所有随机数,将它们存储在一个数组中,然后遍历数组。问题是在我运行程序之前我不知道我需要多少这些数字。
我想做的是大批量生成随机数。然后,当我在一批中使用所有数字时,我将重新填充存储它们的对象。问题是我不知道实现这一点的干净方法。我想出的一种解决方案如下:
N=1000000
numRepop=4
N1=N//numRepop
__rands__=[]
irand=-1
def repop():
global __rands__
__rands__=np.random.rand(N1)
repop()
def myRand():
global irand
try:
irand += 1
return __rands__[irand]
except:
irand=1
repop()
return __rands__[0]
但这实际上比任何其他选项都慢。
如果我将 numpy 数组转换为列表,然后弹出元素,我将获得类似于使用 numpy 一次生成一个随机变量的性能:
__r2__=[]
def repop2():
global __r2__
rr=np.random.rand(N1)
__r2__=rr.tolist()
repop2()
def myRandb():
try:
return __r2__.pop()
except:
repop2()
return __r2__.pop()
有没有更好的方法来做到这一点?
编辑:“更好”是指更快。我也更喜欢确定性(伪)随机数
【问题讨论】:
-
(1) 小心那种基准测试
Return the time in seconds since the epoch as a floating point number. Note that even though the time is always returned as a floating point number, not all systems provide time with a better precision than 1 second. While this function normally returns non-decreasing values, it can return a lower value than a previous call if the system clock has been set back between the two calls.(2) 为什么要弹出,如果你只需要移动一个索引来选择位置。无需移除对象。 -
“更好的方法”是什么意思?除了性能,您还有其他要求吗?出于某些目的,您需要加密安全的随机数,或者您可能需要超过默认的 32 位随机数。
-
@Håken Lid 所说的“更好”我的意思是更快
-
@sascha (1) 这是一个我没有意识到的好点,但我所做的时间安排给出了相当一致的结果,所以我现在并不太担心。 (2) 起初我尝试过索引(使用
repop和myRand),但这比pop()(使用repop2和myRandb)慢。 -
在 *nix 上,您可以阅读
/dev/random或/dev/urandom,具体取决于您是否想要更多随机或更快...
标签: python performance numpy random