You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

对分组后带过滤条件的Pandas DataFrame应用.mean()等函数的最佳实践

问题分析与解决方案

你的报错是因为df.loc[df.groupby(...)]的用法完全错误——groupby对象不能直接作为loc的索引,而且你的np.where参数也不完整。下面一步步解决你的需求,同时讲解分组过滤后聚合的最佳实践。

先构造你的示例数据(方便测试)

import pandas as pd

df = pd.DataFrame({
    'Day': ['Mon']*6,
    'Country': ['US','US','US','CA','CA','CA'],
    'Type': [1,2,3,1,2,3],
    'Product': ['a1']*6,
    'Cost': [0,5,6,8,0,1]
})

需求实现:添加分组过滤后的平均成本列(分两种场景)

场景1:需要数值型的平均结果

如果你的最终目标是得到计算后的均值(比如US组是5.5,CA组是4.5),用groupby.transform()是最简洁的方式——它会自动把分组计算的结果广播到原DataFrame的每一行:

# 按Country和Product分组,过滤Cost>0的行后求均值,再映射到每行
df['Average'] = df.groupby(['Country', 'Product'])['Cost'].transform(
    lambda x: x[x > 0].mean()
)

执行后你会得到:

DayCountryTypeProductCostAverage
MonUS1a105.5
MonUS2a155.5
MonUS3a165.5
MonCA1a184.5
MonCA2a104.5
MonCA3a114.5
场景2:需要显示计算表达式(如你示例中的(5+6)/2)

如果要得到像示例里的字符串格式的计算式,我们可以自定义一个函数传给transform,在函数里处理分组内的非零值并拼接表达式:

def build_avg_expression(x):
    # 获取分组内Cost>0的所有值
    positive_vals = x[x > 0].tolist()
    if not positive_vals:
        return "N/A"  # 处理没有非零值的分组
    # 拼接成"值1+值2+.../数量"的格式
    sum_part = "+".join(map(str, positive_vals))
    return f"({sum_part})/{len(positive_vals)}"

df['Average'] = df.groupby(['Country', 'Product'])['Cost'].transform(build_avg_expression)

运行后就完全匹配你期望的结果了:

DayCountryTypeProductCostAverage
MonUS1a10(5+6)/2
MonUS2a15(5+6)/2
MonUS3a16(5+6)/2
MonCA1a18(8+1)/2
MonCA2a10(8+1)/2
MonCA3a11(8+1)/2

分组过滤后聚合的最佳实践

  • 优先用transform做行映射:当你需要把分组计算的结果对应到原DataFrame的每一行时,transform是最优选择,它会自动处理分组和行的匹配,不需要手动merge。
  • 过滤逻辑嵌入聚合函数:在transform或agg的lambda/自定义函数里先做过滤(比如x[x>0]),再调用mean()/max()等聚合方法,这是最清晰的写法。
  • 复杂逻辑用自定义函数:如果需要像生成表达式、多条件聚合这类复杂操作,直接写自定义函数传给groupby的方法即可,只要保证函数返回的结果长度和分组内的行数一致(transform要求),或者返回单个聚合值(agg要求)。
  • 避免错误的索引方式:永远不要用groupby对象直接作为loc的索引,这是完全不符合Pandas语法的——groupby是分组工具,不是索引标签。

内容的提问来源于stack exchange,提问作者Jonas Palačionis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 18:22:45