dataframe用apply加新列结果全为nan,最常见原因是函数未处理所有分支或返回none;必须确保每条路径都有明确return值、正确使用axis=1、避免非向量化操作、保持函数纯性。

用 apply 给 DataFrame 加新列,为什么结果全是 NaN?
最常见原因是自定义函数没处理所有分支,或者返回了 None。比如写了个条件判断但漏了 else,Python 默认返回 None,apply 就塞进 NaN。
- 检查函数是否对每个输入都有明确的
return值(哪怕只是return ""或return False) - 别在函数里直接
print或logging代替return - 先用小数据测试:取一行
df.iloc[0]手动传给函数,看返回值类型是否符合预期
apply 传 axis=1 还是 axis=0?搞错就全乱了
加新列是按行计算,必须用 axis=1;否则 apply 默认按列(axis=0),函数会收到一整列 Series,根本拿不到其他字段,容易报 KeyError 或维度错乱。
-
df["new_col"] = df.apply(lambda x: x["a"] + x["b"], axis=1)✅ -
df["new_col"] = df.apply(lambda x: x["a"] + x["b"])❌(x是列,没有"a"键) - 如果函数只依赖单列(比如清洗字符串),可以用
df["col"].apply(func),省去axis=1和 lambda 包裹
性能差得离谱?别用 apply 做向量化能干的事
apply 本质是 Python 循环,比原生向量化操作慢 10–100 倍。只要逻辑能用 np.where、pd.cut、布尔索引或 map 表达,就别碰 apply。
- 二选一:
df["flag"] = np.where(df["score"] >= 60, "pass", "fail")✅ 比apply快得多 - 多条件分组:
df["level"] = pd.cut(df["age"], bins=[0,18,35,60,100], labels=["kid","young","adult","senior"])✅ - 查表映射:
df["city_code"] = df["city"].map({"Beijing": 1, "Shanghai": 2})✅(未匹配项自动变NaN,可控)
自定义函数里改 inplace 或全局变量?后果很隐蔽
apply 的函数运行在副本上,改 inplace=True 不影响原 Series;更危险的是在函数里修改外部 list/dict,可能引发并发写入、状态残留或难以复现的 bug。
- 函数必须是纯的:只读输入,只返输出,不改外部状态
- 避免在函数里调用
df.loc、df.drop等会触发链式赋值警告的操作 - 需要复杂状态(如累计计数)?改用
groupby().apply()或预计算辅助列,别硬扛在单行函数里
真正卡住的地方往往不是语法,而是函数边界没划清——它该拿到什么、该返回什么、不该碰什么,三者模糊了,apply 就从工具变成陷阱。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











