咨询辛普森悖论测试代码中pandas groupby().agg()的逻辑疑问
pandas分组聚合默认运行逻辑说明
当你未通过字典格式显式指定待聚合列与对应规则时,pandas的分组聚合默认会对所有未纳入groupby分组维度的列执行指定的聚合计算,这是内置的默认行为。
你之前替换分组字段为["recovery", "treatment"]时观察到的结果,就是这个规则的直接体现:被放入groupby参数列表的列,会被自动从待计算的普通数据列集合中移除,转为分组的索引标签,不会参与后续的聚合运算。
.agg([np.sum, lambda x: len(x)]) 的实际运行机制 当你给.agg()方法传入一个聚合函数构成的列表时,pandas会按如下流程执行计算:
- 遍历当前groupby实例下所有不属于分组键的普通数据列
- 对每一个普通列,按照分组规则拆分出每个分组对应的列元素序列
- 把拆分好的每个分组的元素序列,依次传给列表里的每一个聚合函数,计算对应结果
具体到你提到的两个聚合函数,作用对象完全一致,都是“每个分组下、每一个非分组列的全部元素”:
np.sum的计算结果:对应每个非分组列在当前分组下的元素求和值。比如在结石大小+治疗方式的分组场景下,如果非分组列是标记是否康复的0/1数值列,求和结果就是该组的康复总人数。lambda x: len(x)的计算结果:对应每个非分组列在当前分组下的元素总个数,也就是该分组的样本量。因为是对列元素计数,这个值和具体列的取值无关,同一个分组下所有非分组列算出来的长度结果都是一样的。
常见认知补充
- 这种无显式列指定的写法,会对所有非分组列执行相同的聚合规则。如果表中非分组列不止一个数值字段,最终输出会形成多层列索引:最上层是原始的列名,下一层是对应的聚合结果名(
np.sum会显示为sum,自定义lambda会自动命名为<lambda>)。 - 与字典指定写法的区别:如果用字典形式写
.agg({"recovery": [np.sum, lambda x: len(x)]}),pandas就只会对字典中指定的recovery列执行聚合,不会遍历其他非分组列,这种写法也是生产环境中更常用的实现,能避免非预期的列计算。 - 潜在问题:如果非分组列是字符串、分类等不支持数值求和的类型,
np.sum可能会输出字符串拼接的非预期结果,或是直接抛出类型错误,这也是这类无指定聚合写法的主要局限。
内容的提问来源于stack exchange,提问作者Robin Andrews
相关产品推荐
相关产品推荐

