NumPy IO(长文讲解)

从零开始掌握 NumPy IO:数据读写的核心技能

在数据分析和科学计算的世界里,NumPy 是最坚实的地基。而地基的稳固,离不开高效的数据输入输出能力。我们常说“数据是燃料”,但若没有顺畅的“加油口”,再强大的引擎也难以启动。这就是 NumPy IO 的意义所在——它就像数据的“运输通道”,让你能自由地把数据搬进搬出 NumPy 数组,为后续的计算打下基础。

对于初学者而言,NumPy IO 可能看起来像一堆陌生的函数名和文件格式,但其实它的设计非常直观。只要你理解了“数据如何进入 NumPy”和“NumPy 如何把结果保存出去”这两个核心问题,剩下的就只是熟悉不同格式的使用方式了。

本文将带你一步步掌握 NumPy IO 的核心用法,从最基础的文本文件读写,到二进制格式、内存映射等进阶技巧,帮助你在真实项目中游刃有余。


文本文件读写:最常见也最灵活的方式

文本文件是数据交换最通用的格式之一,尤其适合小规模数据或需要人工查看的场景。NumPy 提供了 loadtxtsavetxt 两个函数,专门用于处理这类文件。

import numpy as np

temperatures = np.array([
    [23.5, 24.1, 25.0, 24.8, 23.9, 22.7, 21.5],
    [22.8, 23.5, 24.3, 25.1, 25.4, 24.6, 23.2],
    [21.0, 21.8, 22.5, 23.3, 24.1, 24.8, 25.2]
])

np.savetxt('temperatures.txt', temperatures, fmt='%.1f', delimiter=',', header='Mon,Tue,Wed,Thu,Fri,Sat,Sun')

上面这段代码会生成一个名为 temperatures.txt 的文件,内容如下:

Mon,Tue,Wed,Thu,Fri,Sat,Sun
23.5,24.1,25.0,24.8,23.9,22.7,21.5
22.8,23.5,24.3,25.1,25.4,24.6,23.2
21.0,21.8,22.5,23.3,24.1,24.8,25.2

现在我们来读回这个文件:

data = np.loadtxt('temperatures.txt', delimiter=',', skiprows=1)


print(data)

💡 小贴士:如果你的数据中包含非数值字符(如字符串),loadtxt 会报错。这时建议使用 genfromtxt,它更健壮,能处理缺失值或混合类型。


二进制格式:高性能数据存储的首选

当数据量变大时,文本文件的读写效率会明显下降。此时,NumPy IO 提供的二进制格式 npynpz 就派上用场了。

使用 .npy 文件:单个数组的高效保存

large_data = np.random.rand(1000, 1000)

np.save('large_data.npy', large_data)

读取时只需一行代码:

loaded_data = np.load('large_data.npy')

print(loaded_data.shape)  # 输出: (1000, 1000)
print(loaded_data.dtype)  # 输出: float64

使用 .npz 文件:多个数组的打包存储

当你有多个相关数组需要一起保存时,npz 是更好的选择。

temps = np.random.normal(25, 5, size=(100, 10))
humidities = np.random.uniform(30, 90, size=(100, 10))

np.savez('climate_data.npz', temperatures=temps, humidity=humidities)

读取时可以按名称获取:

data = np.load('climate_data.npz')

print(data.files)  # 输出: ['temperatures', 'humidity']

temperatures = data['temperatures']
humidity = data['humidity']

print(temperatures.shape)  # (100, 10)
print(humidity.shape)    # (100, 10)

data.close()

📌 重要提醒:.npy 适合单个数组,.npz 适合多个数组打包。两者都支持跨平台读写,是 NumPy IO 中最推荐的格式。


内存映射:处理超大文件的“智慧搬运工”

当你的数据量超过内存容量时,直接加载整个文件会引发内存溢出。这时,NumPy 的 memmap 就成了救命稻草。

什么是内存映射?

想象你有一本 1000 页的书,但你的书桌只能放 10 页。内存映射就像一个“智能书签系统”:你只打开需要的部分,其他页放在书架上,要用时再翻出来。这样既不占桌面空间,又能快速访问。

huge_data = np.random.rand(10000, 10000)

np.save('huge_data.npy', huge_data)

mmap_data = np.memmap('huge_data.npy', dtype='float64', mode='r', shape=(10000, 10000))

现在你可以像操作普通数组一样操作 mmap_data

print(mmap_data[100, 500])  # 只加载这一项,不加载整行

print(mmap_data[0, :10])  # 只加载前 10 个值

subset = mmap_data[1000:1010, 2000:2010]  # 仅读取 10x10 的小块

✅ 优势:内存占用几乎恒定,适合处理 GB 级别的数据
⚠️ 注意:只读模式下无法修改数据,若需写入,应使用 mode='r+'


多格式兼容:轻松应对不同场景

现实项目中,数据来源五花八门。NumPy IO 也提供了对多种格式的支持,让你能无缝对接各种系统。

读取 CSV 文件(带头信息)

虽然 loadtxt 能处理 CSV,但更推荐使用 genfromtxt,它能智能处理缺失值和混合类型。


data = np.genfromtxt('data.csv', delimiter=',', skip_header=1, dtype=None, encoding='utf-8')

print(data[0])  # 输出: (b'Alice', 30, 75000.0)

保存为 JSON 格式(间接方式)

NumPy 本身不支持 JSON,但可以通过 json 模块配合数组转换实现。

import json

array_data = np.array([1.5, 2.3, 4.7, 5.1])
json_data = json.dumps(array_data.tolist())

with open('output.json', 'w') as f:
    f.write(json_data)

with open('output.json', 'r') as f:
    loaded_list = json.load(f)
    loaded_array = np.array(loaded_list)

🔄 提示:JSON 适合配置文件或 API 传输,但不适合大型数值数据,因体积大且精度可能丢失。


总结:构建你的数据输入输出流水线

掌握 NumPy IO,就等于掌握了数据科学工作的“第一道门”。从简单的文本读写,到高效的二进制存储,再到应对超大文件的内存映射,每一种方式都有其适用场景。

  • 小数据、人工可读 → 用 savetxt / loadtxt
  • 大数据、高性能 → 用 .npy / .npz
  • 超大文件、内存受限 → 用 memmap
  • 多格式兼容 → 结合 genfromtxtjson 等模块

记住:没有“最好”的格式,只有“最合适”的选择。根据你的数据大小、读写频率和使用场景,合理搭配这些工具,才能真正发挥 NumPy 的潜力。

在你的下一个项目中,不妨从“如何安全、高效地读取数据”开始思考。你会发现,一个良好的 NumPy IO 设计,往往能让你的整个分析流程更加流畅、稳定、可复现。

数据是起点,而正确的 IO 方式,是通往洞察的必经之路。