#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. Да, это использует больше памяти. Теперь я отмечаю это и предоставляю вариант использования, где это необходимо.