PAYATHON 2026

为什么 pandas apply 遇到未返回值的分支会产生 NaN,而不保留原值?

数据小许

如果函数沿某条路径执行到末尾时没有遇到 return,Python 会隐式返回 None。Series.apply 使用函数的返回值构造结果,不会自动保留原值。要让不满足条件的元素保持不变,可以显式写 return x。对于题目中的数值转换,也可以使用布尔索引。

为什么结果会出现 NaN?

这个函数只有正数分支返回了计算结果:

def scale_positive(x):
    if x > 0:
        return x * 10

当 x 为 -2、0 或 -1 时,函数执行到末尾,返回 None。apply 不会把 None 理解为“跳过修改”,因为它也可能是函数有意返回的结果。

在题目给出的 pandas 2.1.1 示例中,数值结果和 None 合并后,结果会推断为 float64,缺失位置表示为 NaN。其他 dtype 或返回值组合可能保留 None,具体表现取决于结果类型。

原始输出还漏掉了索引 0;按示例逻辑,该位置的值应为 50.0。

方法一:在其余分支返回原值

如果要保留自定义函数,补上 return x 即可:

import pandas as pd

def scale_positive(x):
    if x > 0:
        return x * 10
    return x

s = pd.Series([5, -2, 0, 8, -1])
result = s.apply(scale_positive)

print(result.tolist())
# [50, -2, 0, 80, -1]

这样每条执行路径都会返回预期值。也可以写成:

result = s.apply(lambda x: x * 10 if x > 0 else x)

apply 返回新的结果,以上写法不会修改原来的 s。

方法二:用布尔索引只修改正数

对于“正数乘以 10”这样的简单运算,可以用布尔索引选择需要修改的位置:

result = s.copy()
positive = result > 0
result.loc[positive] = result.loc[positive] * 10

也可以用 where 在一个表达式中生成结果:

result = s.where(s <= 0, s * 10)

where 在条件为真的位置保留原值,在条件为假的位置使用替换值。对于题目中没有缺失值的数值 Series,这两种写法都会得到预期结果。

DataFrame 中的一列怎么处理?

假设目标列名为 value,可以用 .loc 选择需要更新的行和列:

df = pd.DataFrame({"value": [5, -2, 0, 8, -1]})

positive = df["value"] > 0
df.loc[positive, "value"] = df.loc[positive, "value"] * 10

这段代码直接修改 df。如果需要保留原始 DataFrame,先执行 result = df.copy(),再对 result 做相同操作。

注意,df["value"].apply(...) 逐元素处理这个 Series;df.apply(...) 默认按列传入整个 Series,两者的调用方式不同。

不要事后填补所有 NaN 来修复遗漏的返回值,因为这样也可能覆盖函数有意产生的缺失值。应在函数分支或条件赋值中明确哪些位置保留原值。

备注:内容仅供参考。