назначение массива numpy выполняется медленнее, чем python list

#python #numpy #benchmarking

#python #numpy #сравнительный анализ

Вопрос:

numpy-

 arr = np.array([[1, 2, 3, 4]])
row = np.array([1, 2, 3, 4])
%timeit arr[0] = row
  
 466 ns ± 12.3 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
  

список python —

 arr = [[1, 2, 3, 4]]
row = [1, 2, 3, 4]
%timeit arr[0] = row
  
 59.3 ns ± 2.94 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each
  

Разве numpy не должен быть здесь более быстрой версией?


Вот что я собираюсь сделать —

 arr = np.empty((150, 4))

while True:
     row = get_row_from_api() 
     arr[-1] = row
  

Комментарии:

1. Ну, здесь список переназначает один элемент, тогда как в вашем numpy.array примере он назначает 4 элемента. Чтобы получить справедливое сравнение, вам понадобится что-то вроде for i, x in enumerate(row): arr[0][i] = x

2. @DevAggarwal нет, зачем тебе это нужно ? Вы могли бы использовать numpy.ndarray объект с dtype=object , но тогда вы, по сути, работаете с плохим списком. Так что в этот момент просто используйте a list вместо a numpy.ndarray

3. Потому что я хочу, чтобы моя программа работала быстрее? И я определил это как критическую часть моего кода?

4. Можете ли вы привести более конкретный пример с более реалистичным контекстом? Опять же, между a list и a есть довольно существенные различия numpy.ndarray . И не сразу понятно, что именно вы делаете со своим массивом numpy.

5. arr[-1] = row повторно присваивает значение одной и той же последней строке arr . Он не выполняет пошаговое прохождение строк,

Ответ №1:

Да, использование списков python таким образом определенно было бы быстрее, потому что, когда вы назначаете что-то элементу списка python, оно не копируется, просто некоторые ссылки переназначаются (https://developers.google.com/edu/python/lists ). Вместо этого Numpy копирует все элементы из исходного контейнера в целевой. Я не уверен, нужны ли вам здесь массивы numpy, потому что их создание не является бесплатным, а списки python не такие медленные при создании (и, как мы видим, при назначении).

Комментарии:

1. Ах, в цепочке есть немного кода, который использует numpy, не уверен, стоит ли каждый раз выполнять преобразование из list -> numpy

2. Я думаю, что лучше проверить всю последовательность операций на общую производительность. Трудно сказать априори, что будет работать быстрее (если вы не умножаете матрицы [1000, 1000] или делаете что-то подобное).

3. @DevAggarwal Может быть, пора обрезать всю цепочку, а не только numpy против списка, и посмотреть, что работает лучше всего. Numpy должен быть быстрее при вычислениях . Насколько сложны ваши цепочки?

Ответ №2:

Базовая семантика этих двух операций сильно отличается. Списки Python — это массивы ссылок. Массивы Numpy — это массивы самих данных.

Строка row = get_row_from_api() подразумевает, что новый список уже выделен.

Назначение списку as lst[-1] = row просто записывает адрес lst . Обычно это 4 или 8 байт.

Размещение в массиве как arr[i] = row копирование данных. Это сокращение для arr[i, :] = row . Каждый элемент of row копируется в буфер of arr . Если row это был список, это влечет дополнительные накладные расходы на преобразование объектов python в собственные числовые типы.

Помните, что преждевременная оптимизация бессмысленна. Ваша экономия времени для одного метода по сравнению с другим, вероятно, будет незначительной. В то же время, если вам все равно понадобится массив позже по строке, скорее всего, быстрее выполнить предварительное выделение и получить небольшую скорость, а не вызывать np.array конечный список. В первом случае вы выделяете буфер заданного размера и dtype. В последнем случае вы просто отложили накладные расходы на копирование данных, но также понесли накладные расходы на определение размера массива и dtype.