Производительность numpy.insert зависит от размера массива - обходной путь? - PullRequest
0 голосов
/ 01 марта 2019

Используя следующий код, у меня складывается впечатление, что вставка в массив 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 голосов
/ 01 марта 2019

Ваш подход:

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)
0 голосов
/ 01 марта 2019

Это связано с тем, как работает numpy.Для каждой операции вставки он берет весь массив и сохраняет его в новом месте.Я бы рекомендовал использовать list append и затем преобразовать его в массив numpy.Может быть, дубликат этот вопрос

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...