如何索引numpy.memmap不生成内存副本?索引操作的副本与视图区分
numpy.memmap 索引的视图与副本规则
numpy.memmap 是 ndarray 的子类,它的索引行为和普通 numpy 数组完全一致——判断操作返回视图(不创建内存副本,仍由原文件支持)还是副本的规则,和标准 ndarray 没有区别。以下是具体区分:
返回视图(安全,无内存副本)的操作
这类操作不需要复制数据,仅通过调整数组的维度、步长(strides)或偏移量(offset)就能表示结果,因此仍与原文件关联:
- 基本切片操作:使用冒号(
:)定义的切片,包括带固定步长的切片,比如mmap[5:15]、mmap[:, ::2]、mmap[1:-1, 3:] - 维度重排:转置(
.T)、transpose()或swapaxes(),仅调整维度顺序,不改变数据存储的连续性 - reshape 操作:只要不改变数据的存储顺序(比如从
(2,3)reshape 为(6,),或从(4,5)reshape 为(5,4)且原数组是连续的),返回的是视图 - 添加空维度:使用
np.newaxis(或None)扩展维度,比如mmap[:, np.newaxis]
返回内存副本(脱离原文件)的操作
这类操作无法仅通过调整数组元信息实现,必须复制数据到内存,因此结果不再与原文件关联:
- 花式索引:使用整数数组或列表进行索引,比如
mmap[[1,3,5]]、mmap[:, [0,2,4]] - 布尔索引:通过布尔数组筛选元素,比如
mmap[mmap > 0] - 非连续数据的强制扁平化:
flatten()方法(无论数组是否连续,都会返回副本);而ravel()仅在无法返回视图时才生成副本 - 修改数组连续性的操作:比如对非连续视图再进行某些索引,导致无法通过步长描述,最终触发复制
验证是否为视图的方法
可以通过两个属性快速判断:
- 检查
.base属性:如果结果的.base指向原 memmap 对象,说明是视图 - 检查
.mmap属性:视图会保留该属性(关联原文件映射),而副本是普通 ndarray,没有.mmap属性
示例代码:
import numpy as np # 创建测试用 memmap mm = np.memmap('test_memmap.dat', dtype='float64', mode='w+', shape=(10, 10)) # 视图验证 slice_view = mm[2:8, 3:7] print(slice_view.base is mm) # 输出 True print(hasattr(slice_view, 'mmap')) # 输出 True # 副本验证 fancy_copy = mm[[0,2,4], :] print(fancy_copy.base is mm) # 输出 False print(hasattr(fancy_copy, 'mmap')) # 输出 False
内容的提问来源于stack exchange,提问作者Ricardo Decal
相关产品推荐
相关产品推荐

