我需要生成大量随机数。我尝试过使用random.random
,但这个功能很慢。因此我切换到numpy.random.random
,这更快!到现在为止还挺好。生成的随机数实际上用于计算某些事物(基于数字)。因此,我enumerate
超过每个数字并替换值。这似乎杀死了我之前获得的所有加速。以下是使用timeit()
:
test_random - no enumerate
0.133111953735
test_np_random - no enumerate
0.0177130699158
test_random - enumerate
0.269361019135
test_np_random - enumerate
1.22525310516
正如您所看到的,使用numpy生成数字的速度几乎快10倍,但枚举这些数字会让我的运行时间相等。
以下是我正在使用的代码:
import numpy as np
import timeit
import random
NBR_TIMES = 10
NBR_ELEMENTS = 100000
def test_random(do_enumerate=False):
y = [random.random() for i in range(NBR_ELEMENTS)]
if do_enumerate:
for index, item in enumerate(y):
# overwrite the y value, in reality this will be some function of 'item'
y[index] = 1 + item
def test_np_random(do_enumerate=False):
y = np.random.random(NBR_ELEMENTS)
if do_enumerate:
for index, item in enumerate(y):
# overwrite the y value, in reality this will be some function of 'item'
y[index] = 1 + item
if __name__ == '__main__':
from timeit import Timer
t = Timer("test_random()", "from __main__ import test_random")
print "test_random - no enumerate"
print t.timeit(NBR_TIMES)
t = Timer("test_np_random()", "from __main__ import test_np_random")
print "test_np_random - no enumerate"
print t.timeit(NBR_TIMES)
t = Timer("test_random(True)", "from __main__ import test_random")
print "test_random - enumerate"
print t.timeit(NBR_TIMES)
t = Timer("test_np_random(True)", "from __main__ import test_np_random")
print "test_np_random - enumerate"
print t.timeit(NBR_TIMES)
加快这一过程的最佳方法是什么?为什么enumerate
会大幅减缓这种情况?
编辑:我使用enumerate
的原因是因为我需要索引和当前元素的值。
答案 0 :(得分:6)
要充分利用numpy的速度,您希望尽可能创建ufuncs。将vectorize
应用于函数mgibsonbr建议是一种方法,但如果可能的话,更好的方法是构造一个利用numpy的内置ufunc的函数。所以像这样:
>>> import numpy
>>> a = numpy.random.random(10)
>>> a + 1
array([ 1.29738145, 1.33004628, 1.45825441, 1.46171177, 1.56863326,
1.58502855, 1.06693054, 1.93304272, 1.66056379, 1.91418473])
>>> (a + 1) * 0.25 / 4
array([ 0.08108634, 0.08312789, 0.0911409 , 0.09135699, 0.09803958,
0.09906428, 0.06668316, 0.12081517, 0.10378524, 0.11963655])
要在numpy数组中应用的函数的性质是什么?如果你告诉我们,也许我们可以帮你提出一个只使用numpy ufuncs的版本。
也可以在不使用enumerate
的情况下生成索引数组。 Numpy提供ndenumerate
,它是一个迭代器,可能更慢,但它也提供indices
,这是一种非常快速的方法来生成与数组中的值对应的索引。所以......
>>> numpy.indices(a.shape)
array([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]])
因此,为了更明确,您可以使用上述内容并使用numpy.rec.fromarrays
组合它们:
>>> a = numpy.random.random(10)
>>> ind = numpy.indices(a.shape)
>>> numpy.rec.fromarrays([ind[0], a])
rec.array([(0, 0.092473494150913438), (1, 0.20853257641948986),
(2, 0.35141455604686067), (3, 0.12212258656960817),
(4, 0.50986868372639049), (5, 0.0011439325711705139),
(6, 0.50412473457942508), (7, 0.28973489788728601),
(8, 0.20078799423168536), (9, 0.34527678271856999)],
dtype=[('f0', '<i8'), ('f1', '<f8')])
这开始听起来像你主要担心的是就地执行操作。使用vectorize
更难做到,但使用ufunc方法很容易:
>>> def somefunc(a):
... a += 1
... a /= 15
...
>>> a = numpy.random.random(10)
>>> b = a
>>> somefunc(a)
>>> a
array([ 0.07158446, 0.07052393, 0.07276768, 0.09813235, 0.09429439,
0.08561703, 0.11204622, 0.10773558, 0.11878885, 0.10969279])
>>> b
array([ 0.07158446, 0.07052393, 0.07276768, 0.09813235, 0.09429439,
0.08561703, 0.11204622, 0.10773558, 0.11878885, 0.10969279])
如您所见,numpy就地执行这些操作。
答案 1 :(得分:3)
检查numpy.vectorize,它应该允许你将任意函数应用于numpy数组。举个简单的例子,你可以这样做:
vecFunc = vectorize(lambda x: x + 1)
vecFunc(y)
但是,这将创建一个新的numpy数组,而不是就地修改它(在您的特定情况下可能会或可能不会出现问题)。
一般来说,使用numpy函数操作numpy结构总是比使用python函数迭代更好,因为前者不仅经过优化而且在C中实现,而后者将始终被解释。