Pandas apply自定义函数未按预期执行 未更新DataFrame列值
Pandas条件赋值列值未更新问题排查
问题背景
现有如下结构的Pandas DataFrame:
df: score_difference DNB selection selection_match 0 1.040000 0.65 DNB No Match 1 0.894543 0.65 DNB No Match 2 2.120546 2.11 DNB No Match 3 0.672945 0.65 DNB No Match 4 1.578659 0.96 DNB No Match 5 2.746971 2.72 DNB No Match
需要实现的逻辑:当selection_match == 'No Match'且selection == 'DNB'时,设置DNB = score_difference + 0.02,其余场景保留DNB列原有值。
初始编写的实现代码如下:
def selection_mod_dnb(row): if row["selection_match"] == "No Match" and row['selection'] == "DNB": return 0.02 + float(row['score_difference']) else: return row['DNB'] df['DNB'] = df.apply(selection_mod_dnb, axis=1)
执行代码后DataFrame未产生任何修改,DNB列仍为初始值,未得到预期结果。预期正确计算结果如下:
score_difference DNB selection selection_match 0 1.040000 1.060000 DNB No Match 1 0.894543 0.914543 DNB No Match 2 2.120546 2.140546 DNB No Match 3 0.672945 0.692945 DNB No Match 4 1.578659 1.598659 DNB No Match 5 2.746971 2.766971 DNB No Match
问题根因
按出现概率从高到低排序,共有3类常见诱因:
- 视图赋值失效:当前操作的
df是其他DataFrame的切片结果(比如之前通过行列筛选得到df时未追加.copy()),触发Pandas的SettingWithCopyWarning,赋值操作被静默拦截,没有实际写入df对象。 - 字符串匹配失败:
selection或selection_match列的字符串存在隐藏空白字符(比如前后带空格、制表符,实际值为' DNB'、'No Match '),导致if条件判断恒为False,始终走else分支返回原有DNB值。 - 执行顺序问题:apply赋值语句运行后,又重新执行了读取原始数据、覆盖df变量的代码,导致更新结果被重置。
解决方案
优先使用向量化操作实现,相比apply行循环性能提升1~2个数量级,同时可以避开大部分视图赋值的坑:
# 构造筛选条件,.str.strip()用于自动清除字符串前后隐藏空白,无空白场景可删除 mask = (df["selection_match"].str.strip() == "No Match") & (df["selection"].str.strip() == "DNB") # 用loc定位满足条件的行执行赋值,其余行自动保留原值 df.loc[mask, "DNB"] = df.loc[mask, "score_difference"] + 0.02
如果需要保留自定义函数+apply的写法,需要先将df转为独立副本,同时增加字符串空白处理逻辑:
# 强制生成独立副本,避免视图赋值失效 df = df.copy() def selection_mod_dnb(row): if row["selection_match"].strip() == "No Match" and row['selection'].strip() == "DNB": return row['score_difference'] + 0.02 else: return row['DNB'] df['DNB'] = df.apply(selection_mod_dnb, axis=1)
执行上述任意一种方案后,即可得到预期的计算结果。
内容的提问来源于stack exchange,提问作者Rander
相关产品推荐
相关产品推荐

