np.array arr.itemsize vs sys.getsizeof (arr [0]) - PullRequest
0 голосов
/ 04 ноября 2018

с учетом массива

arr = array([  9.93418544e+00,   1.17237323e+01,   1.34554537e+01,
         2.43598467e+01,   2.72818286e+01,   3.11868750e+01,...])

При выполнении следующих команд я получаю некоторый вывод:

arr.itemsize # 8
type(arr[0]) # numpy.float64
sys.getsizeof(np.float64()) # 32
sys.getsizeof(arr[0]) # 32
arr.dtype # dtype('float64')

Кажется, что itemsize не работает должным образом. Мне интересно, почему это происходит?

Я работаю с

print(sys.version)
3.5.5 | packaged by conda-forge | (default, Jul 24 2018, 01:52:17) [MSC v.1900 64 bit (AMD64)]
numpy==1.10.4

1 Ответ

0 голосов
/ 04 ноября 2018

Кажется, что itemsize не работает должным образом.

Да, разные результаты связаны с тем, что объект Python отличается от элемента в numpy.

В Python все является объектом. Данные «в штучной упаковке». Это означает, что, например, для int мы получаем:

>>> sys.getsizeof(2)
28

Это 28 байтов. Это много. В большинстве языков программирования int занимает от двух до восьми байтов. Если это 32-битный int, то это занимает 4 байта.

Но в Python у объекта много "контекста". Например, некоторые байты используются для обозначения типа объекта и т. Д.

Numpy, однако, не реализован в Python, это не библиотека, которая сама использует объекты Python. Это больше библиотека, реализованная на C, с приятным интерфейсом для Python. Таким образом, это означает, что список [1, 4, 2, 5] хранится не в Python как список с четырьмя ссылками на объекты int, а как массив, как правило, с "распакованными" элементами. Таким образом, вышеприведенное займет, учитывая, что int s занимает 32 бита каждый, 4 * 32 бита и некоторое дополнительное пространство для «контекста» вокруг массива.

Таким образом, элементы хранятся более эффективным способом. Это облегчает обработку значений, поскольку мы здесь не следуем указателям, а непосредственно непосредственно значениям (существуют способы хранения ссылок в массивном массиве, но пока будем это игнорировать). Более того, массив numpy занимает намного меньше памяти, чем эквивалентный список Python (вместе с элементами, которые он содержит).

Однако, если вы выбираете элемент из массива, для этого нужно создать объект Python. Таким образом, это означает, что здесь будет создан объект numpy.float64, который содержит значение, но опять же много «контекста» вокруг этого значения. Это приводит к использованию большего количества памяти.

Тот факт, что numpy создает массив объектов определенного типа, также имеет некоторые последствия. Например, если вы используете numpy.int16, то это означает, что нельзя хранить в них значения, превышающие 32767, так как это значение не может быть представлено 16-битным представлением с двумя дополнениями:

>>> np.int16(32767)
32767
>>> np.int16(32768)
-32768

Кроме того, нельзя - без использования ссылок на объекты Python или каких-либо других «хитростей» - создать массив, содержащий объекты разных типов. Numpy создает, например, массив int16, что означает, что он интерпретирует 160 бит как 10 16-битных чисел. В Python список сам содержит ссылку на объекты, а объект Python знает, какой это тип, что означает, что мы можем установить ссылку на другой объект, другого типа.

...