Сброс numpy memmap в файл npy

Есть ли способ сохранить массив Numpy Memmap в .npy файл? Судя по всему, есть способ загрузить такой массив из .npy файл следующим образом

data = numpy.load("input.npy", mmap_mode='r')

но очистка файла не эквивалентна хранению его в .npy формат.

Если очистка - единственный путь, есть ли способ определить форму хранимого массива? Я бы предпочел иметь динамическую форму, которая автоматически сохраняется и извлекается (возможно, снова как memmap) в другом скрипте.

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

numpy.save(output.filename, output.copy())

который побеждает идею использования memmap, но сохраняет форму.

ПРИМЕЧАНИЕ: я знаю о hdf5 и h5py, но мне было интересно, есть ли для этого чисто тупое решение.

2 ответа

Решение

Есть ли способ вывести форму хранимого массива?

Нет Так далеко как np.memmap Дело в том, что файл является просто буфером - он хранит содержимое массива, но не размеры, dtype и т. д. Невозможно вывести эту информацию, если она каким-то образом не содержится в самом массиве. Если вы уже создали np.memmap опираясь на простой двоичный файл, вам нужно будет записать его содержимое в новый .npy файл на диске.

Вы можете избежать создания копии в памяти, открыв новый .npy файл как другой отображенный в память массив с помощью numpy.lib.format.open_memmap:

import numpy as np
from numpy.lib.format import open_memmap

# a 10GB memory-mapped array
x = np.memmap('/tmp/x.mm', mode='w+', dtype=np.ubyte, shape=(int(1E10),))

# create a memory-mapped .npy file with the same dimensions and dtype
y = open_memmap('/tmp/y.npy', mode='w+', dtype=x.dtype, shape=x.shape)

# copy the array contents
y[:] = x[:]

Отказ от ответственности: следующее работает с numpy версией 1.11.2 (и позже, я полагаю), но более ранняя версия, которую я попробовал (1.8.2), выдавала ошибку

Массив сохранен с np.save по сути, это memmap с заголовком, определяющим dtype, shape и порядок элементов. Вы можете прочитать больше об этом в numy документации.

Когда вы создаете свой np.memmap, вы можете зарезервировать место для этого заголовка с offset параметр. Примечание. В документации указано, что длина заголовка должна быть кратна 16:

Допустим, вы резервируете 5 * 16 = 80 байт для заголовка (подробнее об этом ниже):

import numpy as np
x = np.memmap('/tmp/x.npy', mode='w+', dtype=np.ubyte, shape=(int(1E10),), offset=80)

Затем, когда вы закончите манипулировать memmap, вы создадите и напишите заголовок, используя np.lib.format:

header = np.lib.format.header_data_from_array_1_0(x)

with open('/tmp/x.npy', 'r+b') as f:
    np.lib.format.write_array_header_1_0(f, header)

Обратите внимание, что это записывает заголовок с начала файла memmap, так что если len(header) > 80, тогда он перезапишет часть данных, и ваш файл не будет читаемым. Заголовок представляет собой магическую строку фиксированной длины, два байта версии, два байта, определяющие длину заголовка, и строковое представление словаря, задающего "shape", "descr" и "order". Если вы знаете форму и dtype (descr) вашего массива, вы можете легко вычислить длину заголовка (я установил это на 80 выше, для простоты).

После написания заголовка вы можете загрузить данные, используя np.load:

y = np.load('/tmp/x.npy')
Другие вопросы по тегам