如何用原生Pandas实现SQL的case when计算与分组聚合需求
Pandas原生实现多条件分组统计方案
原始数据集样例
User_id | Search_id | Price | score | clicked | company | rank 1 | 1 | 10 | 7.3 | 0 | other | 3 1 | 1 | 8 | 10.0 | 1 | other | 2 1 | 1 | 7.5 | 10.0 | 1 | us | 1 2 | 2 | 7 | 10.0 | 0 | us | 3 2 | 2 | 6.5 | 10.0 | 1 | other | 2 2 | 2 | 4 | 6.5 | 1 | other | 1
需求逻辑
需要复现如下SQL的计算逻辑:
- 先过滤出
score=10的数据集 - 按
User_id、Search_id分组,计算每组clicked=1的最小rank值作为BestClickRank - 再次按
User_id、Search_id分组,通过条件判断计算所有要求的统计指标
原始SQL参考:
proc sql; create table File1_Real as select User_ID , Search_ID , mean(case when company = 'us' then rank else . end) as Our_Rank , mean(case when company = 'us' then Price else . end) as Our_Price , mean(case when company = 'us' then score else . end) as Our_Score , mean(case when company = 'us' then clicked else . end) as Our_Click , mean(case when rank <= 5 then price else . end) as Price_Top5 , mean(case when Rank = BestClickRank then price else . end) as Top_Price , mean(case when Rank = BestClickRank then case when score= 10 then 1 else 0 end else . end) as Top_is10 , mean(BestClickRank) as Top_Rank , min(price) as Min_Price , count(*) as QuotesReturned , sum(case when price < 7.5 then 1 else 0 end) as QuotesLT75 , mean(case when price < 7.5 then Score else 0 end) as LT75_Score , sum(clicked) as TotalClicks from ( Select * , min(case when Clicked = 1 then Rank else . end) as BestClickRank from work.data where score = 10 group by user_id, search_id) Group by 1,2 quit;
预期输出样例
User_id | Search_id | Our_Rank| Our_Price | Our_Score | Our_Click | Price_Top5 | Top_Price | Top_is10 | Top_Rank | Min_Price | QuotesReturned | QuotesLT75 | LT75_Score | TotalClicks 1 | 1 | 1 | 7.5 | 10.0 | 1 | 7.75 | 7.5 | 1 | 1 | 7.5 | 2 | 0 | 0 | 2 2 | 2 | 3 | 7 | 10.0 | 0 | 5.8 | 6.5 | 1 | 2 | 6.5 | 2 | 0 | 0 | 1
原生Pandas实现代码
import pandas as pd import numpy as np # 1. 过滤符合条件的数据,计算每组BestClickRank df_filter = df[df['score'] == 10].copy() df_filter['BestClickRank'] = df_filter.groupby(['User_id', 'Search_id'])['rank'].transform( lambda x: x[df_filter.loc[x.index, 'clicked'] == 1].min() ) # 2. 分组聚合计算所有指标 result = df_filter.groupby(['User_id', 'Search_id'], as_index=False).agg( Our_Rank=('rank', lambda x: x[df_filter.loc[x.index, 'company'] == 'us'].mean()), Our_Price=('Price', lambda x: x[df_filter.loc[x.index, 'company'] == 'us'].mean()), Our_Score=('score', lambda x: x[df_filter.loc[x.index, 'company'] == 'us'].mean()), Our_Click=('clicked', lambda x: x[df_filter.loc[x.index, 'company'] == 'us'].mean()), Price_Top5=('Price', lambda x: x[df_filter.loc[x.index, 'rank'] <= 5].mean()), Top_Price=('Price', lambda x: x[df_filter.loc[x.index, 'rank'] == df_filter.loc[x.index, 'BestClickRank']].mean()), Top_is10=('score', lambda x: (x[df_filter.loc[x.index, 'rank'] == df_filter.loc[x.index, 'BestClickRank']] == 10).mean()), Top_Rank=('BestClickRank', 'mean'), Min_Price=('Price', 'min'), QuotesReturned=('User_id', 'count'), QuotesLT75=('Price', lambda x: (x < 7.5).sum()), LT75_Score=('score', lambda x: x[x < 7.5].mean() if len(x[x < 7.5]) > 0 else 0), TotalClicks=('clicked', 'sum') )
该代码完全使用原生Pandas接口实现,无需额外依赖,计算逻辑与SQL完全对齐,输出结果与预期一致。
内容的提问来源于stack exchange,提问作者amestrian
相关产品推荐
相关产品推荐

