iterrows 慢因每次迭代将行转为带索引和类型检查的 series,绕开底层优化;10 万行下比 numpy 向量化慢 100 倍以上,应优先用布尔索引、itertuples、向量化运算或原生 python 列表推导。

iterrows 为什么慢得让人想砸键盘
因为 iterrows 每次迭代都把一行转成 Pandas Series,带索引、类型检查、对象封装——本质是“用 Python 循环模拟向量化”,完全绕开 Pandas 底层优化。实测 10 万行 DataFrame 上,iterrows 比纯 NumPy 向量化慢 100 倍以上。
- 别在
iterrows里做数值计算(比如row['a'] * row['b']),它连基本的 float 运算都要过一遍 Pandas 类型系统 - 如果只是读取某几列值做简单判断(如
if row['status'] == 'active'),不如先用布尔索引过滤:df[df['status'] == 'active'] - 真要逐行逻辑且无法向量化?优先考虑
itertuples:它返回命名元组,无索引开销,速度通常是iterrows的 3–5 倍
apply 不是万能胶水,用错场景反而更慢
apply 默认按 axis=0(列)运行,但多数人想的是“对每行算一个结果”。这时候必须显式写 axis=1,否则函数会被传入整列,行为完全不对。
-
df.apply(lambda x: x['a'] + x['b'], axis=1)看似简洁,实际仍触发大量 Python 函数调用和 Series 构造,比df['a'] + df['b']慢几十倍 - 如果函数内部有 if/else 分支或调用外部库(如
requests、re.match),apply是合理选择;但凡能用原生 Pandas 方法(str.contains、dt.month、clip),就别碰apply - 注意
apply返回类型推断:若函数返回 list 或 dict,Pandas 会尝试拼成 object 列,后续操作极易报AttributeError: 'list' object has no attribute 'sum'
真正高效的替代方案:什么时候该切到 NumPy 或原生 Python
当逻辑简单、数据量大、类型单一,NumPy 向量化永远比任何 Pandas 遍历快;当逻辑复杂但数据量小(
- 数值运算一律用 NumPy:
np.where(df['a'] > 0, df['a'] * 2, df['b']),不是df.apply(..., axis=1) - 字符串处理优先用
str访问器:df['text'].str.len()、df['email'].str.contains('@'),避免apply+lambda x: len(x) - 需要条件复杂分支 + 小数据?直接
[my_logic(row) for row in df.to_dict('records')],比iterrows干净还快 —— 因为没 Pandas 封装成本
一个容易被忽略的坑:修改原 DataFrame 的陷阱
用 iterrows 或 apply 时,很多人习惯直接改 row['col'] = new_val,但这根本不会写回原 DataFrame —— row 是副本,改了等于白改。
- 想原地修改,必须用
.loc或.iloc:df.loc[idx, 'col'] = new_val,否则所有赋值都是幻觉 -
apply返回新列可以,但返回None或不匹配长度的结构(如返回单个数却期望一列),会静默填NaN,很难 debug - 如果用了
copy_on_write=True(Pandas 2.0+ 默认),某些链式赋值甚至会抛SettingWithCopyWarning,但错误信息根本不提iterrows或apply
遍历的本质是妥协:要么接受慢,要么重构逻辑绕开遍历。最常被低估的,是花十分钟把需求重写成布尔索引 + 向量化表达式,往往比调试半小时 apply 匿名函数更省时间。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











