python - 产生大量随机变量

标签 python performance numpy random

我正在尝试找出在 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()

有更好的方法吗?

编辑:“更好”只是指更快。我也更喜欢确定性(伪)随机数

最佳答案

如果一次生成大量数字更快,您可以制作一个缓存批处理的生成器。这适用于 python 3.5

def randoms(batchsize=10000):
    while True:
        yield from numpy.random.rand(batchsize)

不知道它是否比您的其他实现更快,但它是一个永无止境的生成器。

您可以像使用任何迭代器一样使用它:

prng = randoms()
for _ in range(1000000):
    foo(next(prng))

或者像这样(但是循环永远不会退出):

for x in randoms():
    foo(x)

编辑:

我自己尝试对此进行基准测试,我认为差异主要是因为 python 中函数调用的额外成本。我试图通过在所有情况下遍历 range 来使基准测试更具可比性,并且使用预生成数组的优势较小。

通过使用将 numpy.random.rand 分配给局部变量的微优化技巧,我几乎获得了同样好的速度,这大大加快了函数调用的速度。

我还包括用于比较的生成器方法。

def randoms(batchsize):
    rand = numpy.random.rand
    while True:
        yield from rand(batchsize)
​
def test_generator(times):
    rand = randoms(1000).__next__
    for n in range(times):
        rand()

def test_rand(times):
    for n in range(times):
        numpy.random.rand() 

def test_rand_micro_opt(times):
    rand = numpy.random.rand
    for n in range(times):
        rand()

def test_array(times):
    array = numpy.random.rand(times)
    for n in range(times):
        array[n]
​
# ipython / jupyter magic %timeit command        
%timeit -n 1000 test_generator(10000)
%timeit -n 1000 test_rand(10000)
%timeit -n 1000 test_rand_micro_opt(10000)
%timeit -n 1000 test_array(10000)
​
1000 loops, best of 3: 2.09 ms per loop
1000 loops, best of 3: 2.93 ms per loop
1000 loops, best of 3: 1.74 ms per loop
1000 loops, best of 3: 1.57 ms per loop

关于python - 产生大量随机变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41884259/

相关文章:

python - 自动格式化 python 代码 : dictionaries

python - 如何配置 Apache 2 以使用 %x{} 从 Ruby CGI 应用程序运行 Python 脚本

python - 如何在 Python 的另一个函数中找出特定函数参数的默认值?

python - 垂直箱中 y 值的平均值

python - 在函数内修改字典

android - 防止隐藏状态栏的重新布局(伪造 SYSTEM_UI_FLAG_LAYOUT_STABLE)

performance - 可分配数组性能

c - 在 OpenMP 并行代码中,并行运行 memset 会有什么好处吗?

numpy - 为什么矩阵乘法会根据它们的分组方式给出不同的结果?

python - 从列表中选择一个函数并应用它来生成一个数组