如何读取超内存的大型Numpy数组文件并正确提取1/4数据?
Numpy大体积npy文件部分读取解决方案
错误原因分析
- 直接调用
np.memmap读取npy文件的方式是错误的:标准npy文件包含固定长度的文件头,存储了原数组的shape、dtype、存储顺序等元信息,你手动指定shape和dtype读取时,会把文件头内容当做数组数据解析,自然会出现数值异常、形状不匹配的问题。 - 修改
dtype后数值变化是正常现象:不同dtype对应的单元素字节长度、解析规则完全不同,比如原数组是单字节的uint8类型,你用4字节的int32读取时,会把连续4个uint8的字节拼接为1个int32数值,结果必然和原数据不符。
正确操作步骤
方法1:使用np.load自带的内存映射模式(推荐)
Numpy原生的np.load接口支持直接以内存映射模式加载npy文件,会自动解析文件头,不需要手动指定元信息,用法最简单:
# 以只读内存映射模式加载文件,不会将全量数据读入内存 arr = np.load("dataset/b.npy", mmap_mode='r') # 查看原数组的实际形状、数据类型,确认无误 print(arr.shape, arr.dtype) # 提取1/4数据,示例沿第一维(样本维度)取前1/4,按需读取不会加载全量数据 # 可根据需求自行调整切片规则 subset = arr[: arr.shape[0] // 4] # 如果需要保存提取的子集到新文件 np.save("dataset/subset_b.npy", subset)
方法2:手动解析文件头后使用np.memmap
如果你需要直接使用np.memmap接口,需要先解析npy文件头拿到偏移量、元信息后再创建memmap对象:
import numpy as np # 第一步:解析npy文件头,获取元信息和数据偏移量 with open("dataset/b.npy", "rb") as f: # 读取npy文件魔数 magic = np.lib.format.read_magic(f) # 根据版本读取数组头 if magic[0] == 1: shape, dtype, fortran_order = np.lib.format.read_array_header_1_0(f) else: shape, dtype, fortran_order = np.lib.format.read_array_header_2_0(f) # 数据段起始偏移量 data_offset = f.tell() # 第二步:创建正确的memmap对象 arr = np.memmap( "dataset/b.npy", mode="r", dtype=dtype, shape=shape, offset=data_offset ) # 后续提取子集的操作和方法1一致 subset = arr[: arr.shape[0] //4]
内容的提问来源于stack exchange,提问作者devesh marwah
相关产品推荐
相关产品推荐

