第 9 章 文件读写
学习目标
- 掌握二进制格式:
np.save/np.load(.npy) - 掌握文本格式:
np.savetxt/np.loadtxt(CSV、带表头) - 会用
np.genfromtxt处理缺失值 - 能选择合适的格式读写数据
9.1 为什么需要文件读写
程序运行时,数据在内存里;程序退出,内存释放,数据消失。持久化是把数组保存到磁盘文件,下次运行再读回来。
NumPy 提供两类方式:
- 二进制格式(.npy):保存精确的 dtype 与形状,速度最快,但只能用 NumPy 读。
- 文本格式(CSV/TXT):人类可读、可用 Excel 打开,但体积大、速度慢,数字精度受限。
原则:自己程序之间交换数据用 .npy;给别人看、或与其他软件对接用文本。
9.2 二进制格式:save 与 load
np.save(文件名, 数组) 保存,np.load(文件名) 读回:
python
import numpy as np
a = np.arange(12).reshape(3, 4)
np.save("demo.npy", a)
b = np.load("demo.npy")
print(b)输出:
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]要点:
- 文件名建议以
.npy结尾(不加时save会自动补)。 load读回的数组,形状、dtype 与保存时完全一致。- 保存多个数组可用
np.savez(把数组打包进一个.npz),入门先用save。
9.3 文本格式:savetxt 与 loadtxt
np.savetxt(文件名, 数组, delimiter=分隔符, fmt=格式) 把数组写成文本;np.loadtxt(文件名, delimiter=分隔符) 读回。
保存并读回一个成绩表:
python
import numpy as np
scores = np.arange(12).reshape(3, 4) # 3 名学生 × 4 门课
np.savetxt("scores.txt", scores, fmt="%d", delimiter=",")fmt="%d" 表示按整数格式写出。生成的文件内容:
0,1,2,3
4,5,6,7
8,9,10,11读回:
python
import numpy as np
data = np.loadtxt("scores.txt", delimiter=",")
print(data)
print(data.dtype) # 文本读回默认是浮点输出:
[[ 0. 1. 2. 3.]
[ 4. 5. 6. 7.]
[ 8. 9. 10. 11.]]
float64loadtxt 默认把数字读成浮点;要读回整数,加 dtype=int:
python
import numpy as np
data = np.loadtxt("scores.txt", delimiter=",", dtype=int)
print(data.dtype)输出:
int649.4 带表头的文件
np.savetxt 的 header 参数写表头行,comments 设为空字符串避免表头前加 #;读取时用 skiprows=1 跳过表头:
python
import numpy as np
scores = np.arange(12).reshape(3, 4)
np.savetxt("scores2.txt", scores, fmt="%d", delimiter=",",
header="math,eng,phy,chem", comments="")
data = np.loadtxt("scores2.txt", delimiter=",", skiprows=1)
print(data)文件内容(前两行):
math,eng,phy,chem
0,1,2,3读取输出:
[[ 0. 1. 2. 3.]
[ 4. 5. 6. 7.]
[ 8. 9. 10. 11.]]9.5 缺失值:genfromtxt
loadtxt 遇到空单元格或缺失值会直接报错。np.genfromtxt 是更宽容的版本:缺失位置填入 nan(浮点数组)。
准备一个含缺失的成绩文件 missing.csv:
1,2,3
4,,6
7,8,读回:
python
import numpy as np
data = np.genfromtxt("missing.csv", delimiter=",")
print(data)输出:
[[ 1. 2. 3.]
[ 4. nan 6.]
[ 7. 8. nan]]缺失值成为 nan,之后用第 8 章的掩码排除:
python
import numpy as np
data = np.genfromtxt("missing.csv", delimiter=",")
valid = data[~np.isnan(data)]
print("有效成绩平均:", valid.mean())输出:
有效成绩平均: 4.4285714285714299.6 完整实践:成绩单的保存与读取
把程序流程串起来:生成成绩 → 保存 → 读回 → 统计。
python
import numpy as np
# 1. 模拟 4 名学生的 3 门课成绩(0~100 随机整数)
rng = np.random.default_rng(42)
scores = rng.integers(60, 101, size=(4, 3))
np.savetxt("grades.csv", scores, fmt="%d", delimiter=",",
header="math,eng,phy", comments="")
# 2. 读回
data = np.loadtxt("grades.csv", delimiter=",", skiprows=1, dtype=int)
# 3. 统计
print("每门课平均分:", data.mean(axis=0))
print("每个学生总分:", data.sum(axis=1))
print("全班最高分:", data.max())输出:
每门课平均分: [78. 85. 88.25]
每个学生总分: [239 264 257 264]
全班最高分: 98动手实践
- 创建一个 5×5 数组,用
np.save保存为my.npy,重启交互环境后np.load读回,验证形状与 dtype。 - 把同样的数组用
savetxt写成 CSV,用文本编辑器打开查看内容,再用loadtxt读回。 - 给 CSV 加上表头后保存,读取时用
skiprows=1,验证读回正确。 - 手写一个含空格的 CSV,用
genfromtxt读回,用掩码统计有效值平均。
常见错误
| 错误写法 | 现象 | 原因 |
|---|---|---|
忘记 delimiter 参数 | 读回结果不对或报错 | 保存与读取的 delimiter 必须一致 |
读取带表头的文件不用 skiprows | 表头被当作数据报错 | 文本第 1 行不是数字,要跳过 |
savetxt 后表头带 # | 文件第一行是 #math,... | comments 默认是 #,设为 "" 去掉 |
loadtxt 读含空格的 CSV | ValueError: could not convert string to float: '' | 空单元格要用 genfromtxt |
| 用文本格式保存浮点 | 读回精度下降 | 文本只保留有效数字;高精度需求用 .npy |
| 保存后马上读,路径不对 | FileNotFoundError | 注意保存与读取的目录一致(用相对路径时在当前工作目录) |
章末练习
基础
- 把
np.arange(20).reshape(4, 5)保存为arr.npy并读回,验证相等。 - 把
np.array([[1, 2], [3, 4], [5, 6]])用savetxt写成逗号分隔的 CSV,再用loadtxt读回并打印。 - 给上面的 CSV 加表头
a,b保存,用skiprows=1读回。
提高
- 生成 10 名学生的 5 门课成绩(60~100 整数),保存为带表头的 CSV,读回后输出:每门课平均分、不及格(<60)人数。
- 手写一个 3 行 4 列的 CSV,其中包含 2 个空单元格,用
genfromtxt读回,统计每行有效值的平均。
挑战
- 用
savetxt的fmt="%.2f"保存一个浮点数组,读回后与原始数组比较,记录误差;再换成.npy保存读回,比较两者误差,解释差异。 - 写一个完整的「成绩登记程序」:从
grades.csv读数据,计算并输出每个学生的总分与排名(降序),把排名写回一个新 CSV。
章末自测
每题选择一个最佳答案。本书不附答案:完成后交由老师或 AI 老师批改讲解。
np.save与np.load使用的文件格式是?- A. CSV
- B.
.npy(二进制) - C. JSON
- D. TXT
np.savetxt("a.csv", a, delimiter=",")中delimiter的作用是?- A. 指定文件编码
- B. 指定列分隔符
- C. 指定小数位数
- D. 指定表头
loadtxt默认把数字读成什么类型?- A.
int64 - B.
float64 - C.
str - D.
bool
- A.
- 读取带表头的 CSV,应使用参数?
- A.
header=1 - B.
skiprows=1 - C.
comments=1 - D.
names=1
- A.
loadtxt遇到空单元格会?- A. 自动填 0
- B. 报错
- C. 填入 nan
- D. 跳过该行
genfromtxt遇到空单元格会?- A. 自动填 0
- B. 报错
- C. 填入 nan
- D. 跳过该行
- 需要与 Excel 交换数据,应使用?
- A.
np.save - B.
savetxt写成 CSV - C.
savez - D.
np.load
- A.
savetxt中fmt="%d"表示?- A. 按整数格式写出
- B. 按浮点格式写出
- C. 按字符串写出
- D. 指定小数位数
- 读回整数数组的正确写法是?
- A.
np.loadtxt(f, dtype=float) - B.
np.loadtxt(f, dtype=int) - C.
np.loadtxt(f, fmt="%d") - D.
np.loadtxt(f, delimiter=",")
- A.
.npy相比 CSV 的优势是?- A. 人类可读
- B. 保存精确的 dtype 且速度快
- C. 可以用 Excel 打开
- D. 体积更小一定
