np.save会突然占满磁盘是因为其默认使用未压缩二进制格式,需一次性将整个数组(如shape=(1000000, 1000)的float64数组约7.6gb)加载到内存并写入磁盘,无缓冲或流式机制。

为什么 np.save 会突然占满磁盘?
因为 np.save 默认用的是未压缩的二进制格式,数组有多大,文件就有多大。如果你保存一个 shape=(1000000, 1000) 的 float64 数组,它会直接写约 7.6 GB 的原始数据(10⁶ × 10³ × 8 字节),中间不经过任何缓冲或流式落盘 —— 所有数据先在内存里拼成完整字节块,再一次性写入磁盘。一旦磁盘剩余空间小于这个大小,就会直接报 OSError: No space left on device。
改用 np.savez_compressed 能省多少空间?
它对每个数组单独做 LZMA 压缩(底层调用 zlib),对含大量零、重复值或结构化数值(比如图像、时序采样)特别有效。实测常见科学数据压缩率在 2×–10× 之间:
- 稀疏矩阵(95% 为 0):压缩后常小于原大小的 5%
- 浮点传感器数据(小范围波动):通常能压到 30%–50%
- 纯随机
float64:压缩效果差,可能只减 10%–20%,但至少避免了临时内存峰值
用法很简单:
np.savez_compressed('data.npz', arr=large_array) 注意后缀必须是 .npz,读取时用 np.load('data.npz')['arr']。内存不够、磁盘也不够?试试分块 + 流式保存
np.save 和 np.savez_compressed 都不支持流式写入,但你可以手动分块,避免单次占用过大内存和磁盘空间:
- 按行/列切片,每次只处理
chunk_size=10000行,调用np.savez_compressed(f'chunk_{i}.npz', chunk=chunk_arr) - 用
shutil.disk_usage在每次写前检查剩余空间:free = shutil.disk_usage('.').free<br>if free raise RuntimeError("Disk almost full") - 如果最终需要单个文件,用
np.concatenate拼接后再压缩,而不是拼接未压缩的 .npy
别忽略 dtype 和存储精度的隐性开销
很多大型数组其实根本不需要 float64。比如温度传感器数据精度到 0.01°C 就够,用 arr.astype(np.float32) 直接减半体积;整数计数类数据,int32 或 uint16 往往绰绰有余。改 dtype 不仅省磁盘,还降低内存压力和 I/O 时间。但要注意:np.savez_compressed 不会自动降精度,你得自己做转换。
真正卡住的往往不是“怎么存”,而是没提前确认数据实际动态范围和必要精度 —— 一上来就用 float64 存日志级指标,等于主动给自己挖坑。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











