Pandas中使用apply修改列后重新赋值,两次执行出现值错位的原因咨询
嗨,我来帮你拆解这个奇怪的错位问题~
你遇到的现象确实很迷惑:第一次用apply赋值后,行1的b变成了101(原本是第二行a的100+1),行2的a变成了21(原本是第一行b的20+1);第二次执行后又看似“修正”了部分错位,这背后其实是Pandas处理返回值的默认逻辑和索引对齐规则在起作用。
问题根源拆解
apply返回值的默认类型
你写的add函数返回的是二元元组,但当你不带result_type="expand"参数调用apply时,df[["a","b"]].apply(lambda x: add(x), axis=1)返回的是一个Series,每个元素是二元元组,索引和原DataFrame的行索引一致(即1和2)。比如第一次执行后,这个Series长这样:1 (11, 21) 2 (101, 201) dtype: object赋值时的索引对齐逻辑“搞混了方向”
当你把这个Series赋值给df.loc[:, ["a","b"]](一个两列的DataFrame切片)时,Pandas的对齐逻辑出现了偏差:它误将Series的行索引(1、2)当成了目标切片的列名来匹配,同时把每个元组的元素拆成了行值:- 对于目标列
a,Pandas会取Series中索引为1的元组,把元组的第一个元素11赋值给行1的a,第二个元素21赋值给行2的a; - 对于目标列
b,Pandas会取Series中索引为2的元组,把元组的第一个元素101赋值给行1的b,第二个元素201赋值给行2的b。
这就直接导致了你看到的第一次执行后的错位结果。
- 对于目标列
第二次执行的错位逻辑一致
第二次执行时,df的a/b列已经是错位后的状态:a b 1 11 101 2 21 201此时
apply返回的Series变成:1 (12, 102) # 11+1, 101+1 2 (22, 202) #21+1, 201+1再按照同样的错误对齐逻辑赋值,就出现了第二次执行后的结果,看起来像是部分修正,本质还是同一套错位规则导致的。
解决办法
方法1:让apply返回匹配的DataFrame
只需要在apply中添加result_type="expand"参数,Pandas会自动把每个元组拆成单独的列,返回的结果是和原DataFrame索引完全对齐的DataFrame,赋值时就不会错位:
# 第一次执行 df.loc[:, ["a", "b"]] = df[["a", "b"]].apply(lambda x: add(x), axis=1, result_type="expand") # 正确结果: # a b c # 1 11 21 30 # 2 101 201 300 # 第二次执行同样代码,结果正常: # a b c # 1 12 22 30 # 2 102 202 300
方法2:用矢量化操作替代apply(更高效)
其实你的需求是给a和b列都加1,完全不需要用apply,直接用Pandas的矢量化操作更简单高效,还能彻底避免这类问题:
df[["a", "b"]] = df[["a", "b"]] + 1
备注:内容来源于stack exchange,提问作者Langtec

