什么是预分配 NumPy 数组的首选方法?

33

我刚接触NumPy/SciPy。从文档中得知,预先分配单个数组似乎比调用append/insert/concatenate更高效。

例如,要向数组添加一列1,我认为这样做:

ar0 = np.linspace(10, 20, 16).reshape(4, 4)
ar0[:,-1] = np.ones_like(ar0[:,0])

比起这个更被推荐:

ar0 = np.linspace(10, 20, 12).reshape(4, 3)
ar0 = np.insert(ar0, ar0.shape[1], np.ones_like(ar0[:,0]), axis=1)

我的第一个问题是这样做是否正确(即第一种方法更好),我的第二个问题是,目前我只是像这样预分配我的数组(我注意到在SciPy网站的几个Cookbook示例中都有这种方法):

np.zeros((8,5))

使用NumPy的首选方法是什么?

3个回答

27

使用预分配可在一次调用中分配所需的所有内存,而调整数组大小(通过 append、insert、concatenate 或 resize 调用)可能需要将数组复制到更大的内存块中。因此,您是正确的,预分配比调整大小更可取(并且应该更快)。

有许多“首选”方式来预分配 numpy 数组,具体取决于您想创建什么。有 np.zerosnp.onesnp.emptynp.zeros_likenp.ones_likenp.empty_like 等函数,以及许多其他创建有用数组的函数,例如 np.linspacenp.arange

因此,

ar0 = np.linspace(10, 20, 16).reshape(4, 4)

如果这最接近你所需的ar0,那就太好了。

然而,要使最后一列全为1,我认为最好的方法是只需说:

ar0[:,-1]=1

由于ar0[:,-1]的形状为(4,),因此数字1被广播以匹配此形状。


日期时间数组怎么办?你上面提到的任何方法都似乎不起作用。像 my_array= numpy.empty(10, dtype=numpy.datetime64) 这样的方法也不行。谢谢。 - Confounded

10
在性能十分重要的情况下,np.emptynp.zeros似乎是初始化numpy数组最快的方式。
以下是每种方法以及其他几种方法的测试结果。数值以秒为单位。
>>> timeit("np.empty(1000000)",number=1000, globals=globals())
0.033749611208094166

>>> timeit("np.zeros(1000000)",number=1000, globals=globals())
0.03421245135849915

>>> timeit("np.arange(0,1000000,1)",number=1000, globals=globals())
1.2212416112155324

>>> timeit("np.ones(1000000)",number=1000, globals=globals())
2.2877375495381145

>>> timeit("np.linspace(0,1000000,1000000)",number=1000, globals=globals())
3.0824269766860652

2
根据我的经验,numpy.empty() 是预分配巨大数组的最快方式。我所说的数组形状类似于 (80,80,300000),dtype 为 uint8
以下是代码:
%timeit  np.empty((80,80,300000),dtype='uint8')
%timeit  np.zeros((80,80,300000),dtype='uint8')
%timeit  np.ones((80,80,300000),dtype='uint8')

并且计时结果:

10000 loops, best of 3: 83.7 µs per loop  # Much faster
1 loop, best of 3: 273 ms per loop
1 loop, best of 3: 272 ms per loop

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接