Ссылка на поле в структурированном массиве numpy имеет тот же размер, что и весь массив

#python #numpy #structured-array

#python #numpy #structured-array

Вопрос:

Проблема

У меня есть numpy структурированный массив, и я хочу взять два небольших поля. Когда я это делаю, я получаю элемент размером с оригинал

Пример

 >>> A = np.zeros(100, dtype=[('f',float),('x',float,2),('large',float,500000)])
>>> A.itemsize
4000024
>>> A['f'].itemsize
8
>>> A['x'].itemsize
8
>>> A[['x','f']].itemsize
4000024
>>> A[['x']].itemsize
4000024
  

Вопрос

Почему при использовании фрагмента полей в массиве numpy создается массив размером с исходный? (Я использую python3.8 и numpy версии 1.18.3)

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

1. Можете ли вы уточнить, что вы подразумеваете под размером ?

Ответ №1:

Создайте массив, достаточно маленький для фактического отображения:

 In [151]: A = np.zeros(3, dtype=[('f',float),('x',float,2),('large',float,10)])
In [152]: A
Out[152]: 
array([(0., [0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]),
       (0., [0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]),
       (0., [0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])],
      dtype=[('f', '<f8'), ('x', '<f8', (2,)), ('large', '<f8', (10,))])
  

Выберите одно поле:

 In [153]: A['f']
Out[153]: array([0., 0., 0.])
  

Выберите список полей:

 In [154]: A[['f']]
Out[154]: 
array([(0.,), (0.,), (0.,)],
      dtype={'names':['f'], 'formats':['<f8'], 'offsets':[0], 'itemsize':104})
  

Начиная с версии 1.17, индексирование с помощью списка полей возвращает a view . Таким образом itemsize , совпадает с оригиналом.

 In [155]: A.itemsize
Out[155]: 104
In [156]: A[['x']].itemsize
Out[156]: 104
  

Разница между индексацией списком и именем поля может быть более ясной при просмотре последнего поля. Один по-прежнему является структурированным массивом, другой — 2d-массивом.

 In [159]: A[['large']].dtype
Out[159]: dtype({'names':['large'], 'formats':[('<f8', (10,))], 'offsets':[24], 'itemsize':104})

In [160]: A[['large']].shape
Out[160]: (3,)
In [161]: A['large'].shape
Out[161]: (3, 10)
  

https://numpy.org/doc/stable/user/basics.rec.html#accessing-multiple-fields

Обратите внимание, что в отличие от индексации с одним полем, dtype представления имеет тот же itemsize, что и исходный массив, и имеет поля с теми же смещениями, что и в исходном массиве, а неиндексированные поля просто отсутствуют.

Ответ №2:

Необходимая функция numpy — repack_fields . Затем пример становится:

 >>> from numpy.lib.recfunctions import repack_fields
>>> A = np.zeros(100, dtype=[('f',float),('x',float,2),('large',float,500000)])
>>> A[['x']].itemsize
4000024
>>> repack_fields(A[['x']]).itemsize
16
  

Обратите внимание, что переупаковка полей A обязательно потребует больше памяти. Это может быть желательно, например, при использовании mpi4py для связи A[['x']] между рангами (и все A они слишком велики для связи).

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

1. Да, это использует больше памяти. Теперь я отмечаю это и предоставляю вариант использования, где это необходимо.