我想用生成的值填充一个numpy数组。这些值由生成器函数生成。数组长度不是太长,通常<100,但是这个数组生成了很多次,所以我想知道它是否可以通过numpy的一些奇特用法进行优化。
到目前为止,我已经可以用vanilla python做到这一点:
def generate():
return generated_data
array = np.asarray([generate() for _ in range(array_length)])
我也尝试过使用np.full(shape, fill_value)
:
np.full((array_length, generated_data_size), generate())
但这只是调用generate()
函数一次,而不是一次调用数组中的每个索引。
我也试过np.vectorize()
,但是我无法让它生成一个适当形状的数组。
NumPy无法加速重复调用不能与NumPy交互的函数的过程。
“优雅使用numpy”优化方法是手动重写generate
函数,使用NumPy操作生成整个输出数组,而不是仅支持单个值。这就是NumPy的工作方式,以及NumPy的工作方式;任何涉及为每个阵列单元一遍又一遍地调用Python函数的解决方案都将受到Python开销的限制。 NumPy只能加速NumPy中实际发生的工作。
如果NumPy提供的操作太有限,无法根据它们重写generate
,可以选择使用Cython重写generate
,或者使用@numba.jit
。这些主要有助于计算涉及从一个循环迭代到下一个循环迭代的复杂依赖性;它们无法帮助您无法重写的外部依赖项。
如果你不能重写generate
,你所能做的就是尝试优化将返回值放入数组的过程。根据数组大小,您可以通过重用单个数组对象来节省一些时间:
In [32]: %timeit x = numpy.array([random.random() for _ in range(10)])
The slowest run took 5.13 times longer than the fastest. This could mean that an
intermediate result is being cached.
100000 loops, best of 5: 5.44 µs per loop
In [33]: %%timeit x = numpy.empty(10)
....: for i in range(10):
....: x[i] = random.random()
....:
The slowest run took 4.26 times longer than the fastest. This could mean that an
intermediate result is being cached.
100000 loops, best of 5: 2.88 µs per loop
但是大型阵列的好处消失了:
In [34]: %timeit x = numpy.array([random.random() for _ in range(100)])
10000 loops, best of 5: 21.9 µs per loop
In [35]: %%timeit x = numpy.empty(100)
....: for i in range(100):
....: x[i] = random.random()
....:
10000 loops, best of 5: 22.8 µs per loop
另一个选择是从你的ufunc
函数制作一个generate
:
gen_array = np.frompyfunc(generate, 0, 1) # takes 0 args, returns 1
array = gen_array(np.empty(array_length))
对于我而言,这比Sigve's answer的“速度需求”版本要快一些。
List comprehension,或map function都可能成为你的解决方案:
from random import random
import numpy as np
np.array(list(map(lambda idx: random(), range(10))))
np.array([random() for idx in range(10)])
也许预先分配内存将削减微秒或两秒(?)
array = np.empty(10)
for idx in range(10):
array[idx] = random()
请参阅Nathan's answer以获得更好的解决方案。
可以使用numpy“向量化”函数:
def rnd(x):
return random()
fun = np.vectorize(rnd)
array = fun(range(10))