我正在尝试找出在Python中生成许多随机数字的最佳方法。困难的部分是在运行时之前我不知道需要多少个数字。
我有一个程序,它每次使用一个随机数,但需要多次这样做。到目前为止我尝试了以下几种方法:
- 使用random.random()逐个生成随机数
- 使用np.random.rand()逐个生成随机数
- 使用np.random.rand(N)批量生成N个随机数
- 使用np.random.rand(N)批量生成N个随机数,并在使用完第一个N个后再生成新的一批(我尝试了两种不同的实现,但都比逐个生成随机数慢)
在下面的脚本中,我比较了这三种方法的结果(对于均匀分布和正态分布的随机数)。
我不知道函数p是否真的必要,但我想在每种情况下使用相同的随机数来进行等效的操作,这似乎是最简单的方法。
这个计时脚本的输出示例如下:
前三个数字是在[0,1)上均匀分布的随机数,后三个数字是正态分布的随机数(mu=0, sigma=1)。
对于任何类型的随机变量,这三种方法中最快的方法是一次性生成所有随机数,将它们存储在数组中,并迭代该数组。问题是,在运行程序之后,我不知道需要多少这些数字。
我想做的是批量生成随机数。然后当我使用一个批次中的所有数字时,我只需重新填充存储它们的对象。问题是,我不知道有没有一个干净的方法来实现这一点。我想到的一个解决方案如下:
#!/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秒更高的精度。虽然此函数通常返回非递减值,但如果在两次调用之间系统时钟被设置回,则它可以返回低于先前调用的值。
(2) 如果你只需要移动索引以选择位置,为什么要弹出呢?不需要删除对象。 - sascharepop
和myRand
),但这比使用pop()
(使用repop2
和myRandb
)更慢。 - kevin