iterrows() 慢因每行构造带索引的 series,触发 python 对象创建和类型推断;itertuples() 更快因返回轻量命名元组,无索引拷贝和 dtype 转换,但需禁用 index、清理列名或用位置访问,并在无状态依赖时优先向量化。

为什么 iterrows() 慢得明显?
它返回每行一个 pd.Series,带完整索引和类型检查,每次调用都触发 Python 层对象构造 + 类型推断,内存开销大、CPU 缓存不友好。尤其当 DataFrame 有 10k+ 行或含字符串列时,速度可能比 itertuples() 低 5–10 倍。
itertuples() 怎么用才真正快?
默认返回命名元组(Pandas 自建的 namedtuple 子类),字段名直接映射列名,无索引拷贝、无 dtype 转换,纯 C 层迭代。但要注意几个关键点:
- 禁用
index=True(默认开启)——除非真需要索引,否则关掉能提速 15%~20% - 列名含空格或特殊字符时,
itertuples()会自动重命名为_1,_2等,建议提前清理列名或用位置索引访问:row[1]比row.col_name稍快(微秒级差异,但高频遍历时可累积) - 如果只读少数几列,用
cols=['a', 'b']参数提前筛选,避免整行加载 - 示例:
for row in df.itertuples(index=False, name=None): # name=None 返回普通 tuple,更快 result = row[0] * row[1] + 1
什么情况下必须放弃逐行、改写为向量化?
只要逻辑不依赖「上一行计算结果」(即无状态依赖),90% 的 iterrows() 场景都能向量化。常见可替代模式:
- 条件赋值 → 改用
np.where()或布尔索引:df['new'] = np.where(df['a'] > 0, df['b'] * 2, df['c']) - 字符串操作 → 用
str访问器:df['name'].str.upper()、df['email'].str.contains('@') - 时间运算 → 用
pd.to_datetime()后直接加减:df['date'] + pd.Timedelta('7D') - 简单数学函数 → 直接作用于 Series:
df['x'].apply(np.log1p)比逐行慢,但np.log1p(df['x'])是向量化的
别踩这些坑:itertuples 不是万能加速器
itertuples() 快,但不是所有“看起来像逐行”的场景都适合它:
- 如果循环体内要频繁调用 Pandas 方法(比如
row.to_frame().groupby(...)),性能反而更差——这本质是把向量化优势全丢回 Python 层 - 当 DataFrame 列数极多(>100)、且只用其中 2–3 列时,
itertuples()仍会加载全部列数据;此时改用zip()解包指定列更轻量:for a, b in zip(df['col_a'], df['col_b']): ... - 遇到
AttributeError: 'tuple' object has no attribute 'xxx',大概率是忘了name=None却还用row.xxx访问——命名元组需name非None才支持属性访问 - 注意
itertuples()对NaN的处理和iterrows()一致(保持原 dtype),但某些旧版本 Pandas 在含category列时可能降级为 object,建议升级到 1.5+ 并测试
向量化永远优先;itertuples() 是退而求其次的务实选择;而 iterrows() 应该只在调试、极小数据或必须用 Series 接口时出现。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











