Pandas中按指定列聚合分组后按多规则排序的简洁方法
免责声明:这是我第一次提问,有点局促紧张 :/
我有一个包含两列:title 和 val的DataFrame:
>>> df=pd.DataFrame( ... { ... "title": ["a", "a", "a", "b", "b", "b", "c", "c", "c"], ... "val": [1, 4, 3, 4, 5, 6, 2, 4, 5], ... } ... ) >>> df title val 0 a 1 1 a 4 2 a 3 3 b 4 4 b 5 5 b 6 6 c 2 7 c 4 8 c 5
排序需求
将相同title的行聚合为同一分组,按以下规则排序:
- 第一优先级:按分组内
val的最大值对分组做降序排序 - 第二优先级:若不同分组的
val最大值相等,按title的字母顺序升序排序 - 第三优先级:每个分组内部的行按
val做降序排序
目前我通过新增辅助列的方式可以实现需求,代码如下:
>>> df.loc[:,'max_value']=df.groupby('title', as_index=False).transform(max) >>> df title val max_value 0 a 1 4 1 a 4 4 2 a 3 4 3 b 4 6 4 b 5 6 5 b 6 6 6 c 2 5 7 c 4 5 8 c 5 5 >>> df.sort_values(['max_value','title', 'val'], ascending=False, inplace=True) >>> df.drop(columns='max_value', inplace=True) >>> df title val 5 b 6 4 b 5 3 b 4 8 c 5 7 c 4 6 c 2 1 a 4 2 a 3 0 a 1
想知道有没有更简洁的实现方式。
简洁实现方案
不需要手动新增、删除辅助列,直接在sort_values中传入分组计算的隐式排序键即可,一行代码就能完成,同时可以修正原写法中第二优先级排序方向的bug(原写法统一设置ascending=False会导致title按降序排列,和字母升序的需求冲突):
df = df.sort_values( by=[df.groupby('title')['val'].transform('max'), 'title', 'val'], ascending=[False, True, False] )
三个排序键分别对应三个优先级,ascending参数单独为每个键指定排序方向,运行结果和需求完全一致。
如果处理的数据量较大,还有性能更好的写法:先统计每个title分组的max值,得到title的正确排序顺序,将title转为有序分类类型后再排序,避免给全量行生成transform辅助列:
# 先得到符合规则的title排序:先按分组val最大值降序,同值则按title字母升序 title_sorted = df.groupby('title')['val'].max().sort_values(ascending=False).sort_index(kind='stable').index # 转换为有序分类后直接排序 df = df.assign(title=pd.Categorical(df['title'], categories=title_sorted, ordered=True)).sort_values(['title', 'val'], ascending=[True, False])
内容的提问来源于stack exchange,提问作者synybody
相关产品推荐
相关产品推荐

