pandas Series.agg传入lambda自定义函数与内置函数结果不一致问题咨询
现象底层逻辑说明
这一表现是pandas.Series.agg内部多分支兼容逻辑导致的,不属于设计缺陷,具体执行逻辑如下:
Series.agg接收传入函数后,会先判断函数是否属于内部注册的已知聚合函数白名单:np.mean属于白名单范畴,此时pandas直接将完整Series作为参数传入函数,计算得到聚合标量170.4,符合预期。- 若传入的是不在白名单内的可调用对象(比如lambda),pandas会优先尝试逐元素执行函数:如果逐元素运行无报错,直接返回逐元素计算后的新Series。测试中
lambda x: np.mean(x)返回和原Series取值一致的结果,就是因为此时x是单个float值,np.mean(单个float)的返回值就是它本身。 - 若逐元素执行过程中抛出异常(比如调用
x.tolist()时,float类型没有该方法),pandas会触发回退逻辑,改为将完整Series作为参数传入函数执行,所以此时能打印出整个Series的列表内容。
其他场景表现一致的原因
groupby.agg的核心逻辑是按分组传入子Series块执行聚合,没有逐元素应用的分支设计,所以不管传入原生聚合函数还是lambda,都会把子Series作为参数传入,结果一致。DataFrame.agg默认按列聚合,始终把整列Series作为参数传入函数,所以lambda也能拿到完整列数据,计算结果符合预期。
解决方案
如果需要在非分组Series.agg中使用自定义lambda做聚合,推荐两种方案:
- 使用
pipe方法替代agg,pipe始终会把整个调用对象作为参数传入函数:
v.pipe(lambda x: np.mean(x)) # 返回170.4
- 将lambda放在列表中传入
agg,强制pandas按聚合逻辑执行:
v.agg([lambda x: np.mean(x)]).iloc[0] # 返回170.4
内容的提问来源于stack exchange,提问作者KH Kim
相关产品推荐
相关产品推荐

