numpy.insert的性能取决于数组大小-解决方法?

时间:2019-03-01 13:45:43

标签: python performance numpy

使用以下代码,给人的印象是插入numpy数组取决于数组大小。

是否有针对此性能限制的基于numpy的变通办法(或基于非numpy的变通办法)?

if True:
    import numpy as np
    import datetime
    import timeit
myArray = np.empty((0, 2), dtype='object')
myString = "myArray = np.insert(myArray, myArray.shape[0], [[ds, runner]], axis=0)"
runner = 1
ds = datetime.datetime.utcfromtimestamp(runner)
% timeit myString
19.3 ns ± 0.715 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
for runner in range(30_000):
    ds = datetime.datetime.utcfromtimestamp(runner)
    myArray = np.insert(myArray, myArray.shape[0], [[ds, runner]], axis=0)
print("len(myArray):", len(myArray))
% timeit myString
len(myArray): 30000
38.1 ns ± 1.1 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

2 个答案:

答案 0 :(得分:2)

这与numpy的工作方式有关。对于每个插入操作,它将获取整个数组并将其存储在新位置。我建议使用list附加并将其转换为numpy数组。也许是this question

的副本

答案 1 :(得分:1)

您的方法:

In [18]: arr = np.array([])                                                     
In [19]: for i in range(1000): 
    ...:     arr = np.insert(arr, arr.shape[0],[1,2,3]) 
    ...:                                                                        
In [20]: arr.shape                                                              
Out[20]: (3000,)

In [21]: %%timeit  
    ...: arr = np.array([]) 
    ...: for i in range(1000): 
    ...:     arr = np.insert(arr, arr.shape[0],[1,2,3]) 
    ...:                                                                        
31.9 ms ± 194 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

将其与concatenate进行比较:

In [22]: %%timeit  
    ...: arr = np.array([]) 
    ...: for i in range(1000): 
    ...:     arr = np.concatenate((arr, [1,2,3])) 
    ...:                                                        
5.49 ms ± 20.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

并带有列表扩展名:

In [23]: %%timeit  
    ...: alist = [] 
    ...: for i in range(1000): 
    ...:     alist.extend([1,2,3]) 
    ...: arr = np.array(alist)                                                                        
384 µs ± 13.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

我们不鼓励使用concatenate(或np.append),因为它速度慢且难以初始化。列表追加或扩展更快。您对insert的使用甚至比concatenate更糟。

concatenate每次都会创建一个全新的数组。 insert也是这样做的,但是由于它被设计为将新值放在原始值的任何位置,因此它要复杂得多,因此速度也较慢。如果您不相信我,请看一下它的代码。

lists专为增长而设计;通过将简单的对象(指针)插入具有增长速度的缓冲区中,可以添加新项目。也就是说,增长发生在原地。

插入完整数组中也很不错:

In [27]: %%timeit  
    ...: arr = np.zeros((1000,3),int) 
    ...: for i in range(1000): 
    ...:     arr[i,:] = [1,2,3] 
    ...: arr = arr.ravel()                                                                      
1.69 ms ± 9.47 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)