
np.loadtxt 在处理大文件时存在一个已知缺陷:skiprows 会被错误地应用于每个数据块(默认块大小50000行),而非仅跳过文件开头指定行数,导致多跳行、数据丢失,尤其在 dtype=str 下表现明显。
`np.loadtxt` 在处理大文件时存在一个已知缺陷:`skiprows` 会被错误地应用于每个数据块(默认块大小50000行),而非仅跳过文件开头指定行数,导致多跳行、数据丢失,尤其在 `dtype=str` 下表现明显。
在使用 numpy.loadtxt 读取大型文本文件(如含 524123 行的 ID 列表)时,若指定 skiprows=1 期望仅跳过首行表头,却意外缺失 10 行数据——这并非用户操作失误,而是 NumPy 2.2.3 及更早版本中一个已确认的底层实现缺陷。
? 问题根源:分块加载 + 重复跳行
loadtxt 内部采用分块(chunked)方式逐批读取文件,默认每块最多 50000 行。而 skiprows=n 的逻辑被错误地应用在每个块的起始处,而非仅对整个文件生效。
以 524123 行文件为例:
- 总块数 = ⌈524123 / 50000⌉ = 11 块
- 每块均执行
skiprows=1→ 实际跳过 11 行(第1行 + 后续每块首行) - 导致净丢失 10 行(本应只跳1行,却跳了11行)
该行为在 dtype=str 下尤为显著,是因为字符串类型触发了更严格的缓冲区对齐与内存预分配逻辑,放大了块边界判定误差;而显式指定固定长度字符串类型(如 '<u10> 或 <code>'<u20>)会改变内部解析路径,使部分块边界对齐“偶然正确”,因此仅丢失 1 行(即 524122),印证了块机制的影响。</u20>
✅ 验证与复现示例
import numpy as np
# 模拟问题文件(含表头)
with open('foo.txt', 'w') as f:
f.write('IID SuperPops\n')
for i in range(50002): # 超过 50000 行,触发第二块
f.write(f'FG{i:08d} R6\n')
# 观察跳行异常
print("Total lines (with header):", 50003)
print("skiprows=0 →", len(np.loadtxt('foo.txt', usecols=0, dtype=str))) # 50003
print("skiprows=1 →", len(np.loadtxt('foo.txt', usecols=0, dtype=str, skiprows=1))) # 50001(应为50002,少1行)
# 第二块首行(第50002行)被额外跳过 → 确认块级 skiprows 错误? 解决方案与替代建议
| 方案 | 说明 | 推荐度 |
|---|---|---|
| 升级 NumPy ≥ 2.2.4 | 官方已在 PR #28319 中修复该问题,skiprows 现严格作用于文件全局起始位置。 |
⭐⭐⭐⭐⭐ |
改用 np.genfromtxt |
更健壮的通用文本加载器,无此分块跳行缺陷,支持相同参数(skip_header, usecols, dtype)。 |
⭐⭐⭐⭐ |
手动跳过 + np.loadtxt |
先用 Python 打开文件并跳过首行,再传入文件对象:with open('foo.txt') as f: next(f); data = np.loadtxt(f, usecols=0, dtype=str)
|
⭐⭐⭐⭐ |
| Pandas 替代(推荐大数据场景) |
pd.read_csv('foo.txt', sep=r'\s+', header=0, usecols=[0], dtype=str)['IID'].values —— 自动处理空白分隔、编码鲁棒、性能优。 |
⭐⭐⭐⭐⭐ |
⚠️ 注意事项
- 此 Bug 与
comments、delimiter、converters等参数无关,纯属skiprows在分块流式读取中的逻辑错误; -
unpack=True/False、usecols组合不会规避该问题,仅影响输出形状; - 若项目受限于旧版 NumPy(如 QMT 等封闭环境),切勿依赖
skiprows处理超 50000 行文本,务必采用文件对象跳过或genfromtxt方案; - 字符串长度不一致(如
len(ID)==10的 ID 全部丢失)是典型线索,可快速定位是否命中此缺陷。
✅ 总结:这不是数据格式问题,而是 NumPy 版本缺陷。升级至 2.2.4+ 是根本解法;临时项目请优先选用
genfromtxt或pandas.read_csv,兼顾正确性、可维护性与未来兼容性。

















