Pandas实现SQL Group By + Having逻辑的等价代码求助
Pandas实现SQL Group By + Having逻辑的等价代码求助
首先,先帮你拆解原SQL的逻辑,顺便指出你尝试代码里的几个问题:
你的原SQL逻辑(先修正可能的笔误:SQL里sum(A,B,C)应该是sum(A) + sum(B) + sum(C)吧?我下面按这个逻辑处理,如果是每行A+B+C再求和的场景,可以后面调整):
select A, B, sum(C), sum(D), sum(E)
from T
group by A
having sum(A) + sum(B) + sum(C) > 0
你尝试的代码里有几个明显问题:
groupby(A)应该用字符串列名,也就是groupby('A')(除非你把列名存成了变量A,但一般不会这么写)filter()方法的参数是针对组的判断函数,不是直接写聚合条件,而且filter返回的是原数据的行,不是聚合后的结果,不适合完成你的需求agg()的写法错误,Pandas的agg需要指定列和对应聚合函数,比如字典格式
下面给你两种可行的实现方式,根据你的实际场景选择:
方式一:先聚合所有字段,再过滤(推荐)
这种方式先把分组后的所有聚合值(包括having需要的条件值)计算出来,再过滤掉不满足条件的行,最后整理成你要的结果,效率更高:
# 1. 分组聚合,计算所有需要的指标,包括用于having的sum(A)+sum(B)+sum(C) agg_df = df.groupby('A').agg( B=('B', 'first'), # 假设每个A对应唯一的B,用first取第一个值;如果B需要聚合可换'mean'/'sum'等 sum_C=('C', 'sum'), sum_D=('D', 'sum'), sum_E=('E', 'sum'), total_ABC=lambda x: x['A'].sum() + x['B'].sum() + x['C'].sum() ) # 2. 应用having条件,过滤掉total_ABC <=0的组 result = agg_df[agg_df['total_ABC'] > 0].drop(columns='total_ABC') # 可选:把列名改回SQL里的格式 result = result.rename(columns={'sum_C': 'sum(C)', 'sum_D': 'sum(D)', 'sum_E': 'sum(E)'})
如果你的having条件是每行的A+B+C求和后再取总和(也就是sum(A+B+C)),那聚合total_ABC的部分改成:
total_ABC=lambda x: (x['A'] + x['B'] + x['C']).sum()
方式二:先过滤组,再聚合
如果你想先过滤掉不满足条件的组,再对剩下的组做聚合,也可以这么写:
# 定义过滤组的函数:返回True表示保留该组 def filter_group(group): return (group['A'].sum() + group['B'].sum() + group['C'].sum()) > 0 # 先过滤组,再聚合 filtered_df = df.groupby('A').filter(filter_group) result = filtered_df.groupby('A').agg( B=('B', 'first'), sum_C=('C', 'sum'), sum_D=('D', 'sum'), sum_E=('E', 'sum') )
这种方式需要分组两次,效率比第一种低,所以更推荐第一种方式。
另外补充:SQL里group by A但select里包含B,在大多数数据库的严格模式下是不允许的,除非B和A是函数依赖(比如A是主键,每个A对应唯一的B)。所以上面的代码里用('B', 'first')是假设每个A对应的B是唯一的,如果你的场景里每个A有多个B值,需要根据实际需求选择合适的聚合方式(比如取最大值、最小值或者拼接)。
备注:内容来源于stack exchange,提问作者ssaf
相关产品推荐
相关产品推荐

