Я пытаюсь переупаковать подмножество строк и полей из большого структурированного массива numpy.
Когда я использую ломтик, я могу использовать repack_fields
, но когда я использую range
, я не могу. Вызов
range
до того, как repack_fields
, кажется, выделяет всю память, необходимую исходному массиву.
Ниже приведен пример, в котором я ограничиваю доступную память, чтобы ввести ошибку, которую я наблюдаю в своем варианте использования.
import numpy as np
from numpy.lib.recfunctions import repack_fields
import resource
resource.setrlimit(resource.RLIMIT_AS, (int(1.5e9), int(1.5e9)))
H = np.zeros(100, dtype=[('f1', int), ('f2', int), ('large', float, 1000000)])
print('Using slicing: ')
repack_fields(H[['f1', 'f2']][0:50])
print('Using range: ')
repack_fields(H[['f1', 'f2']][range(0, 50)])
производит вывод:
Using slicing:
Using range:
Traceback (most recent call last):
File "test.py", line 12, in <module>
repack_fields(H[['f1', 'f2']][range(0, 50)])
MemoryError: Unable to allocate 381. MiB for an array with shape (50,) and data type {'names':['f1','f2'], 'formats':['<i8','<i8'], 'offsets':[0,8], 'itemsize':8000016}
Почему поведение range(0, 50)
отличается от поведения 0:50
? (Список также не работает.) Я знаю, что в приведенном выше примере можно сначала переупаковать поля, а затем ссылаться на строки. (То есть repack_fields(H[['f1', 'f2']])[range(0, 50)]
работает.) Но я не хочу знать, лучше ли сначала получить строки или сначала поля.
Как правильно взять подмножество строк/полей из большого структурированного массива numpy? (даже если строки не являются последовательными)?
repack_fields(H[['f1', 'f2']][0:50])
И [['f1', 'f2']]
, и [0:50]
производят view
, один потому, что это индекс с несколькими полями, а другой, потому что это срез (базовое индексирование). Так что не требует новой памяти. repack_fields
создает новый массив с местом только для этих 2 полей и 50 записей и копирует значения из view
.
repack_fields(H[['f1', 'f2']][range(0, 50)])
Опять же, индекс полей — это view
, ссылающийся на всю структуру, включая поле large
. [range...]
— это расширенное индексирование, создание копии, включающей 50 записей «крупного размера».
Посмотрите на ошибку:
Unable to allocate 381. MiB for an array with shape (50,) and data type
{'names':['f1','f2'], 'formats':['<i8','<i8'], 'offsets':[0,8], 'itemsize':8000016}
In [336]: 50*8000016/1e6
Out[336]: 400.0008
Это 381 МБ, которые он пытается выделить. Ошибка возникает при индексации [range(50)]
. До репака еще не дошло.
Итак, вы должны понять две вещи.
Индексирование с помощью среза создает view
, который не потребляет дополнительную память. Индексирование с помощью range
или списка (или массива) является «расширенным индексированием» и создает копию.
индексация с несколькими полями делает view
. Даже если поля являются подмножеством источника, размер элемента остается исходным. Целью repack
является создание нового массива с новым dtype и новым размером элемента, содержащего только значения для выбранных полей.
Нет ни одного. Представление возможно только тогда, когда память является последовательной или может быть идентифицирована шагами (как в случае среза с шагом). Это касается всех массивов.
Знаете ли вы, как правильно получить подмножество (непоследовательных) строк в виде представления?