将NumPy的memmap刷新到npy文件中

8
有没有一种方法可以将numpy的memmap数组保存到.npy文件中? 显然,有一种方法可以从.npy文件中加载这样的数组,如下所示:
data = numpy.load("input.npy", mmap_mode='r')

但是刷新文件并不等同于将其存储为.npy格式。

如果刷新是唯一的选择,那么有没有一种方法可以推断出存储数组的形状?我希望动态形状能够自动存储和检索(可能再次作为memmap)在另一个脚本中。

我在各个地方搜寻过这个问题,但没有找到任何结果。我现在使用的是存储到 .npy 的方式。

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

这会破坏使用memmap的想法,但保留形状。

注意:我知道hdf5和h5py,但我想知道是否有一个纯numpy的解决方案。

2个回答

12

有没有一种方法可以推断存储数组的形状?

没有。就np.memmap而言,文件只是一个缓冲区 - 它存储了数组的内容,但没有存储其维度、数据类型等信息。除非这些信息已经包含在数组本身中,否则无法推断出这些信息。如果您已经创建了一个由简单二进制文件支持的np.memmap,则需要将其内容写入磁盘上的新的.npy文件。

您可以通过使用numpy.lib.format.open_memmap将新的.npy文件作为另一个内存映射数组来避免在内存中生成副本:

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[:]

1
这个 open_memmap 函数是一个很好的发现 - 我只需要一种方法来启动一个 .npy 支持的数组,但添加一个选项来保存可以粘贴到二进制文件中的数组更好。 - pevogam
open_memmap 真的很棒 - zhao yufei

6
使用np.save保存的数组,本质上是一个带有头部信息的memmap,它指定了dtype、形状和元素顺序。您可以在numpy文档中了解更多信息。
创建np.memmap时,您可以使用offset参数为该头部信息保留空间。 numpy文档指定头部长度应为64的倍数:
假设您为头部保留了2 * 64 = 128字节的空间(关于此后面会讲到):
import numpy as np
x = np.memmap('/tmp/x.npy', mode='w+', dtype=np.ubyte, 
              shape=(int(1E10),), offset=128)

最后,当您完成操作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) > 128,则会覆盖部分数据,并且您的文件将无法读取。头文件是一个固定长度的魔术字符串(6字节),两个版本字节,两个字节指定头文件长度,以及指定“shape”、“descr”和“order”的字典的字符串表示。如果您知道数组的形状和dtype(descr),则可以轻松计算头文件的长度(出于简单起见,我将其固定为128)。
在编写头文件后,您可以使用np.load加载数据:
y = np.load('/tmp/x.npy')

如果您保存的memmap很大,您可能希望再次将数据加载为memmap:
y = np.load('/tmp/x.npy', mmap_mode='r')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接