df.apply()默认axis=0按列传Series,无法直接多列运算;需设axis=1传整行Series,再用x['col']取值,注意类型、缺失值及性能问题。

为什么 df.apply() 默认只对单列/单行生效,不能直接写多列运算?
因为 df.apply() 的默认 axis=0 是按列遍历,传给函数的是每个 Series;设成 axis=1 虽然能拿到整行(Series),但此时列名、类型、缺失值对齐全靠你自己处理——它不自动把多列打包成元组或字典传进去。
常见错误现象:TypeError: <lambda>() missing 2 required positional arguments</lambda>,是因为你写了 lambda x, y, z: ...,但 apply 只扔一个参数(Series)进来。
- 必须用
axis=1才能访问多列,且函数接收的是整行Series,通过.loc或方括号取值 - 别在 lambda 里写多个形参,那是误解了数据流向
- 如果逻辑复杂,优先写普通函数,比嵌套 lambda 更易读、易调试
df.apply(lambda x: ..., axis=1) 怎么安全取多列值?
用 x['col_a'] 或 x.loc['col_a'] 最稳妥。注意:列名必须存在,且大小写、空格、特殊字符要完全一致;如果某行该列是 NaN,取值后仍是 NaN,后续计算可能触发 TypeError。
使用场景:比如同时用 price 和 discount_rate 算折后价,或用 start_time 和 end_time 算时长。
立即学习“Python免费学习笔记(深入)”;
- 推荐用
x['col_name'],比x.col_name更健壮(避免列名含空格或与内置属性冲突) - 加
try/except不现实——apply会中断;改用pd.to_numeric(..., errors='coerce')预处理更靠谱 - 性能影响:
axis=1是 Python 层循环,比向量化慢一个数量级;万级以上数据要考虑numpy.where或pd.eval
df['final_price'] = df.apply(lambda x: x['price'] * (1 - x['discount_rate']), axis=1)
想复用逻辑又不想写函数?用 functools.partial 或闭包更干净
直接在 lambda 里硬编码常量(比如税率、系数)会导致逻辑散落、难维护。与其反复写 lambda x: x['a'] * 0.9 + x['b'] * 0.1,不如把系数抽出来。
参数差异:闭包能捕获外部变量,partial 能预设部分参数,两者都比“把所有东西塞进 lambda”更可控。
- 闭包示例:
make_calculator = lambda rate: lambda x: x['base'] * rate + x['bonus'],然后df.apply(make_calculator(0.8), axis=1) -
partial示例:from functools import partial,def calc(row, rate, bonus_factor): return row['base'] * rate + row['bonus'] * bonus_factor,再df.apply(partial(calc, rate=0.8, bonus_factor=1.2), axis=1) - 闭包和
partial都不会提升性能,但能让测试、修改、复用变得简单
容易被忽略的坑:dtype 混合、缺失值传播、链式赋值警告
多列参与运算时,只要其中一列是 object(比如混了字符串和数字),整个结果列大概率变成 object,后续 sum()、plot() 全报错;而 NaN 在多数算术中静默传播,表面不出错,实则污染结果。
- 务必提前检查:用
df[['col_a', 'col_b']].dtypes确认类型一致,用df[['col_a', 'col_b']].isna().sum()看缺失情况 - 避免链式赋值:不要写
df[df['flag']==1].apply(...),应先切片再 apply,否则可能触发SettingWithCopyWarning - 兼容性注意:Pandas 2.0+ 对
axis=1的apply返回类型推断更严格,旧代码若依赖隐式类型转换,可能出FutureWarning
真正麻烦的不是语法怎么写,而是你得清楚每一列在每一步里是什么类型、有没有空、边界值怎么处理——这些没法靠 lambda 一行兜住。









