如何在不加载全量数据时将内存映射Numpy数组转为Fortran顺序?
我通过内存映射加载了一个超出内存容量的Numpy数组:
arr = np.load("a.npy", mmap_mode='r')
后续计算需要将它转为Fortran顺序,但使用np.asfortranarray转换后调用np.save会把整个数组加载到内存,内存占用与输入数据成正比。我需要实现纯文件到文件的操作,怎么才能在不加载全量数据的前提下完成转换?
示例说明
假设原数组为:
arr = np.array([[1, 2], [3, 4]])
它在磁盘上以C顺序存储:
fortran_order: False
01 02 03 04
不同转换方式的结果对比:
直接调用
np.asfortranarray(arr)后保存:np.asfortranarray(arr) # 输出: array([[1, 2], [3, 4]])磁盘存储变为Fortran顺序,数据排列符合需求:
fortran_order: True
01 03 02 04
但该方式会将全量数据加载到内存,无法处理超大型数组。调用
np.asfortranarray(arr.T)后保存:np.asfortranarray(arr.T) # 输出: array([[1, 3], [2, 4]])磁盘存储:
fortran_order: True
01 02 03 04
数据排列未发生实质变化,不符合需求。直接保存
arr.T:arr.T # 输出: array([[1, 3], [2, 4]])磁盘存储:
fortran_order: True
01 02 03 04arr.T仅改变数组的访问视图,并未修改磁盘上的数据存储顺序,同样不符合需求。
解决方案:分块处理+内存映射写入
核心思路是分块读取原C顺序数组的连续块,按Fortran顺序的连续块写入目标文件,全程仅加载小块数据到内存。
步骤1:创建Fortran顺序的内存映射目标数组
先读取原数组的元数据(形状、数据类型等),不加载实际数据,然后创建对应规格的Fortran顺序内存映射文件:
import numpy as np # 读取原数组元信息 with np.load("a.npy", mmap_mode='r') as arr: src_shape = arr.shape src_dtype = arr.dtype # 创建Fortran顺序的内存映射目标数组 target_arr = np.lib.format.open_memmap( "a_fortran.npy", mode='w+', dtype=src_dtype, shape=src_shape, order='F' )
步骤2:分块读写数据
根据可用内存设置合适的块大小,分块读取原数组的连续区域,写入目标数组的对应位置。以二维数组为例,按列分块处理:
block_size = 1024 # 根据可用内存调整,比如设为内存能容纳的最大列数 with np.load("a.npy", mmap_mode='r') as arr: # 遍历原数组的列,分块处理 for col_start in range(0, src_shape[1], block_size): col_end = min(col_start + block_size, src_shape[1]) # 读取原数组的当前列块(C顺序下arr[:, col_start:col_end]是连续内存) block = arr[:, col_start:col_end] # 将块写入目标数组的对应列(Fortran顺序下target_arr[:, col_start:col_end]是连续内存) target_arr[:, col_start:col_end] = block
步骤3:收尾操作
显式删除内存映射对象,确保数据写入磁盘:
del target_arr
原理说明
- 原数组是C顺序,
arr[:, col_start:col_end]对应磁盘上的连续数据块,读取时仅加载该块到内存。 - 目标数组是Fortran顺序,
target_arr[:, col_start:col_end]对应磁盘上的连续数据块,写入时直接按Fortran顺序存储。 - 分块处理将内存占用控制在块大小范围内,避免加载全量数据。
内容的提问来源于stack exchange,提问作者Trick

