iterrows() 慢是因为它将每行转为带索引和 dtype 推断的 pd.Series,违背 NumPy 向量化设计,触发 Python 层迭代、绕过 C/Fortran 加速,且有内存开销和无法 JIT 优化等问题。

为什么 iterrows() 慢得明显?
iterrows() 每次返回一个 pd.Series,带完整索引和 dtype 推断,本质是把每行转成 Python 对象再包装——这和 Pandas 底层的 NumPy 向量化设计完全背道而驰。尤其当 DataFrame 超过 5000 行,你大概率会卡在「明明只改一列,却等了 8 秒」的状态。
- 它强制触发 Python 层迭代,绕过了 C/Fortran 加速路径
- 返回的
Series有额外内存开销,且无法被 JIT(如 Numba)优化 - 如果你在循环里还调用
.loc或.at再写回,性能雪上加霜
itertuples() 怎么用才不翻车?
itertuples() 直接返回命名元组(namedtuple),字段名默认是列名,索引作为第一个字段(除非 index=False)。它比 iterrows() 快 2–5 倍,但有几个硬约束必须注意:
- 列名不能含空格、特殊字符或以数字开头,否则生成的字段名非法(会 fallback 成
Index,_1,_2等) - 所有列会被强制转为统一 dtype(通常是
object),数值计算前得手动转类型,比如row.age + 1可能报错,得写成int(row.age) + 1 - 默认包含索引;如果不需要,一定加
index=False,否则第一项永远是索引值,容易误读
for row in df.itertuples(index=False):
if row.status == "active":
result.append(row.id * 2)什么情况下必须放弃循环,改用向量化?
只要逻辑不依赖「上一行结果」或「动态条件跳转」,90% 的 iterrows() 场景都能向量化。常见可替换模式:
- 条件赋值:不用
if row.x > 0: y = row.x <em> 2</em>,改用df["y"] = df["x"].where(df["x"] > 0, df["x"] 2)或np.where() - 字符串操作:
df["name"].str.upper()比循环调.upper()快两个数量级 - 多列计算:用
df.eval("c = a + b * 2"),避免逐行取值再算 - 分组内计算:优先用
groupby().transform(),别在循环里查 group key
记住一点:Pandas 的向量化函数不是“语法糖”,它们背后是预编译的 C 循环,和 Python for 循环根本不在一个量级。
真要循环时,还有没有更快的替代?
如果业务逻辑实在复杂(比如状态机、递归依赖),又必须逐行处理,可以考虑:
- 用
df.values+ 普通 Python for:拿到纯 NumPy 数组,无索引无 dtype 开销,但失去列名语义 - 把逻辑抽到函数里,用
numba.jit编译(仅限数值计算,且输入得是 numpy.ndarray) - 小数据量(< 10k 行)+ 复杂逻辑,不如导出为 list of dict,用原生 Python 处理,有时反而更稳
最常被忽略的是:很多人改用 itertuples() 后没关掉 name 参数,默认生成的 namedtuple 名字叫 Pandas,导致 IDE 提示失效、调试困难。建议显式指定:itertuples(name="Row", index=False)。
向量化不是银弹,但 iterrows() 是红灯——看到它,先想三秒有没有 mask、where、apply(axis=1) 或 eval 能代劳。真绕不开,再碰 itertuples(),顺便检查列名是否合法。

















