pandas.assign()使用lambda函数字典遇延迟绑定错误如何规避
问题原因
这个问题和lambda本身的功能限制无关,根源就是Python闭包的延迟绑定特性:你在字典推导式里生成的所有lambda函数,共享同一个循环变量v。当assign方法实际执行这些lambda时,循环早已结束,v会固定为遍历列表的最后一个值'b',因此两列实际执行的都是x['b']*10的逻辑,才会出现两列结果完全相同的错误输出。
哪怕你把lambda换成普通def定义的函数放在推导式里,不做特殊处理的话一样会触发这个问题,和函数定义用的关键字没有关系。
解决方案
完全可以在字典推导式的写法里打破延迟绑定,不需要放弃assign的链式调用写法,最常用的方式是利用函数默认参数在定义时求值的特性,把当前循环的列名提前绑定到lambda的参数上:
import pandas as pd df = pd.DataFrame({'a': [1,2], 'b':[3,4]}) # 给lambda加col默认参数,绑定当前循环的v值 df = df.assign(**{v: lambda x, col=v: x[col]*10 for v in ['a', 'b']})
运行上述代码就能得到预期输出:
a b 0 10 30 1 20 40
如果不想用默认参数的写法,也可以借助functools.partial在定义函数时就固定列名参数,效果完全一致:
import pandas as pd from functools import partial def calc_col(x, col): return x[col] * 10 df = pd.DataFrame({'a': [1,2], 'b':[3,4]}) df = df.assign(**{v: partial(calc_col, col=v) for v in ['a', 'b']})
你之前用apply的写法当然可以实现需求,但如果要保持pandas链式调用的代码风格,上面两种写法更适配assign的使用场景。
内容的提问来源于stack exchange,提问作者Marcel Flygare
相关产品推荐
相关产品推荐

