Numpy花式索引选列触发数据拷贝内存占用过高的原因及解决方法
为什么花式索引会触发内存拷贝
你使用的x[:, [0, 1, 3, 5, 11, ...]]属于Numpy的花式索引(高级索引的一种),按照Numpy的设计规则,只有以下几种索引操作会返回原数组的视图,其余都会生成数据拷贝:
- 连续切片索引,比如
x[:, 2:10] - 固定步长的切片索引,比如
x[:, ::3] - 单个整数标量索引,比如
x[:, 4]
你用整数列表选取离散列时,这些列在底层内存中不是连续排布,也无法通过统一的步长(stride)计算访问地址,Numpy无法通过调整元数据(数组形状、步长、指针偏移)生成视图,只能把选中的元素复制到新的连续内存块中。数十亿行规模下,单份拷贝的大小就会达到几十到上百GB,自然会触发内存不足崩溃。
避免拷贝的可行方案
- 如果待选列是固定间隔的离散列,直接改用步长切片语法代替列表索引。比如要选第0、2、4、6...列时,用
x[:, ::2]而非x[:, [0,2,4,6...]],即可返回视图无拷贝。 - 如果待选列无规律,不要一次性选取所有列存储为新数组。可以逐列单独操作:单个整数索引列
x[:, col_id]返回的是原数组的视图,不需要拷贝,你可以依次对每一列做计算,不需要把所有列合并为新数组。 - 如果必须拿到多列的聚合结果,采用分批处理逻辑:按行切片每次读取几万到几十万行的对应列,处理完成后立即释放临时内存,峰值内存占用可以控制在百MB级别。
- 全量数据可以改用
np.memmap映射磁盘文件存储,选中的列可以直接写入新的memmap文件,不需要全量加载到内存中。
内容的提问来源于stack exchange,提问作者DiveIntoML
相关产品推荐
相关产品推荐

