Python 是否可以在不定义数组的情况下创建numpy文件?

Python 是否可以在不定义数组的情况下创建numpy文件?,python,python-3.x,numpy,Python,Python 3.x,Numpy,我有一些非常大的数据要处理。我希望能够使用np.load(filename,mmap_mode=“r+”)在磁盘而不是RAM上使用这些文件。我的问题是,在RAM中创建它们会导致我试图避免的问题 我已经知道np.memmap了,这是一个潜在的解决方案,但是创建一个memmap,然后使用np.save(filename,memmap)保存数组意味着我会将磁盘空间需求翻一番,即使只是短暂的,这并不总是一个选项。我主要不想使用memmaps,因为.npy文件(即shape和dtype)中的头信息非常有用

我有一些非常大的数据要处理。我希望能够使用
np.load(filename,mmap_mode=“r+”)
在磁盘而不是RAM上使用这些文件。我的问题是,在RAM中创建它们会导致我试图避免的问题

我已经知道
np.memmap
了,这是一个潜在的解决方案,但是创建一个memmap,然后使用
np.save(filename,memmap)
保存数组意味着我会将磁盘空间需求翻一番,即使只是短暂的,这并不总是一个选项。我主要不想使用memmaps,因为
.npy
文件(即shape和dtype)中的头信息非常有用

我的问题是,我可以创建一个numpy文件而不需要首先在内存中创建它吗?也就是说,我可以通过提供数据类型和形状来创建numpy文件吗?这个想法大致是
np.save(filename,np.empty((x,y,z))
但是我假设empty需要在保存之前在内存中分配它

我目前的解决办法是:

def create_empty_numpy_文件(文件名、形状、dtype=np.float64):
使用tempfile.TemporaryFile()作为tmp:
memmap=np.memmap(tmp,dtype,mode=“w+”,shape=shape)
np.save(文件名,memmap)

编辑

我的最终解决方案基于bnaeker的答案和numpy.lib.format中的一些细节:

class MockFlags:
def uuu init uuuu(self,shape,c_continuous=True):
self.c_continuous=c_continuous
self.f_continuous=(非c_continuous)或(c_continuous和len(shape)==1)
类数组:
def uu init uuu(self,shape,dtype=np.float64,c_continuous=True):
self.shape=shape
self.dtype=np.dtype(dtype)
self.flags=MockFlags(形状,c_连续)
def保存(自我,文件名):
如果self.dtype.itemsize==0:
缓冲区大小=0
其他:
#将缓冲区大小设置为16 MiB以隐藏Python循环开销。
buffersize=max(16*1024**2//self.dtype.itemsize,1)
n_块,余数=np.divmod(
np.product(self.shape)*self.dtype.itemsize,buffersize
)
将open(文件名,“wb”)作为f:
np.lib.format.write_数组_头_2_0(
f、 np.lib.format.header\u data\u来自数组\u 1\u 0(self)
)
对于范围内的块(n_块):
f、 写入(b“\x00”*缓冲区大小)
f、 写入(b“\x00”*余数)
Numpy文件格式为。您可以使用一些文档不足的函数从构建阵列所需的元数据创建所需的头字节,而无需实际构建阵列

将numpy导入为np
def创建头字节(
shape,dtype=np.float64,fortran\u order=False,format\u version=“2.0”
):
#4或2字节无符号整数,具体取决于版本
n\u大小\u字节=4如果格式\u版本[0]=“2”否则为2
magic=b“\x93NUMPY”
版本信息=(
int(每个).to_字节(1,“little”),格式为_version.split(“.”)
)
#钥匙应该按字母顺序排序
标题={
“descr”:np.lib.format.dtype_to_descr(np.dtype(dtype)),
“fortran_顺序”:fortran_顺序,
“形状”:形状
}
#Pad标头最多64字节的倍数
header_bytes=str(header).encode(“ascii”)
页眉长度=长度(页眉字节)
当前长度=标题长度+长度(魔法)+2+n大小字节,用于版本信息
所需长度=整数(np.ceil(当前长度/64.0)*64)
换行符的填充=所需长度-当前长度-1
头\u字节+=b”“*填充+b”\n
#标题dict的长度,包括填充和换行
长度=len(头字节)。到字节(n大小字节,“小”)
返回b“”。连接((魔术,*版本信息,长度,头字节))
您可以测试它是否与此代码段等效:

将numpy导入为np
输入io
x=np.零((10,3,4))
第一个=创建\u npy\u头\u字节(x.shape)
stream=io.BytesIO()
np.lib.format.write_数组_头_2_0(
流,np.lib.format.header\u data\u来自数组\u 1\u 0(x)
)
打印(f“库:{stream.getvalue()}”)
打印(f“自定义:{first}”)
您应该看到如下内容:


库:b”\x93NUMPY\x02\x00t\x00\x00\x00{'descr':'数据是否已经以某种二进制格式存储在文件中?不,数据将进行动态计算。我事先知道形状和数据类型,但不知道内容。
mmap_模式
仅是
np.load
的一个选项,而不是
np.save
。除了标题之外,
npy
文件只是文件的一个字节副本数组的数据缓冲区。@hpaulj我正在创建许多不同维度的文件,因此我不想单独跟踪这些信息。标题对我来说是其中的关键部分,这就是我在问题中提到它们的原因。这是一个令人难以置信的答案。非常感谢!
b"\x93NUMPY\x02\x00t\x00\x00\x00{'descr': '<f8', 'fortran_order': False, 'shape': (10, 3, 4), }                                                    \n"