Ответ 1
В этом случае они не возвращают совершенно то же самое. a[2,1]
возвращает a numpy.float64
, а a.item((2,1))
возвращает собственный плагин python.
Скалярные vs numpy
(float
, int
и т.д.)
A numpy.float64
скаляр не совсем тождествен с нативным питоном float
(они ведут себя одинаково, однако). Простые операции над одним элементом будут быстрее с использованием собственного плавающего python, так как там меньше косвенности. Посмотрите docstring для ndarray.item
немного подробнее.
В качестве примера разницы в скорости рассмотрим следующее:
In [1]: x = 1.2
In [2]: y = np.float64(1.2)
In [3]: %timeit x + 1
10000000 loops, best of 3: 58.9 ns per loop
In [4]: %timeit y + 1
1000000 loops, best of 3: 241 ns per loop
Вначале я неправильно указал, что вторым фактором было то, что a.item(...)
был немного быстрее, чем a[...]
. Это на самом деле не так. Время, затрачиваемое на a.item
преобразование скаляра numpy в собственный скаляр python, перегружает время, необходимое для дополнительной логики в a[...]
/a.__getitem__(...)
.
Не обобщайте этот результат более чем на один элемент
Однако вы должны быть осторожны, пытаясь обобщить, что происходит с числовыми скалярами, с тем, как работают массивы numpy в целом. Если вы делаете много индексирования одного элемента в numpy, это обычно анти-шаблон.
Например, сравните:
In [5]: a = np.random.rand(1000)
In [6]: %timeit a + 1
100000 loops, best of 3: 2.32 us per loop
Независимо от того, что мы делаем, мы не сможем сопоставить скорость (или значительно меньшее использование памяти) векторизованной версии (a + 1
) выше:
In [7]: %timeit [x + 1 for x in a]
1000 loops, best of 3: 257 us per loop
In [8]: %timeit [a.item(i) + 1 for i in range(len(a))]
1000 loops, best of 3: 208 us per loop
Это связано с тем, что повторение через ndarray
происходит медленнее, чем повторение через список. Для вполне справедливого сравнения, переведите все в список собственных плавающих python:
In [9]: b = a.tolist()
In [10]: type(b[0])
Out[10]: float
In [11]: %timeit [x + 1 for x in b]
10000 loops, best of 3: 69.4 us per loop
Очевидно, что с помощью векторизованных операций (первый случай) выполняется намного быстрее, когда вы работаете с большими массивами. Это также намного эффективнее с точки зрения памяти, так как list
требует хранения указателей на каждый элемент, а ndarray
- в памяти.