从零开始掌握 NumPy IO:数据读写的核心技能
在数据分析和科学计算的世界里,NumPy 是最坚实的地基。而地基的稳固,离不开高效的数据输入输出能力。我们常说“数据是燃料”,但若没有顺畅的“加油口”,再强大的引擎也难以启动。这就是 NumPy IO 的意义所在——它就像数据的“运输通道”,让你能自由地把数据搬进搬出 NumPy 数组,为后续的计算打下基础。
对于初学者而言,NumPy IO 可能看起来像一堆陌生的函数名和文件格式,但其实它的设计非常直观。只要你理解了“数据如何进入 NumPy”和“NumPy 如何把结果保存出去”这两个核心问题,剩下的就只是熟悉不同格式的使用方式了。
本文将带你一步步掌握 NumPy IO 的核心用法,从最基础的文本文件读写,到二进制格式、内存映射等进阶技巧,帮助你在真实项目中游刃有余。
文本文件读写:最常见也最灵活的方式
文本文件是数据交换最通用的格式之一,尤其适合小规模数据或需要人工查看的场景。NumPy 提供了 loadtxt 和 savetxt 两个函数,专门用于处理这类文件。
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 提供的二进制格式 npy 和 npz 就派上用场了。
使用 .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 - 多格式兼容 → 结合
genfromtxt、json等模块
记住:没有“最好”的格式,只有“最合适”的选择。根据你的数据大小、读写频率和使用场景,合理搭配这些工具,才能真正发挥 NumPy 的潜力。
在你的下一个项目中,不妨从“如何安全、高效地读取数据”开始思考。你会发现,一个良好的 NumPy IO 设计,往往能让你的整个分析流程更加流畅、稳定、可复现。
数据是起点,而正确的 IO 方式,是通往洞察的必经之路。