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

如何在Pandas groupby()分组结果中添加非分组的学生列

问题:按年份分组获取最高GPA并关联对应学生(含并列情况)

原始DataFrame定义

import pandas as pd

df = pd.DataFrame({
    'student': ['Bob', 'Sally', 'Rich', 'Melissa', 'Len', 'Sue', 'Jon', 'Sandy',
                'William', 'Sara'],
    'year': [2020, 2020, 2020, 2021, 2021, 2021, 2021, 2022, 2022, 2022],
    'gpa': [2.9, 3.7, 3.2, 3.8, 3.8, 3.1, 3.2, 2.7, 3.6, 3.9]})

输出:

student  year  gpa
0      Bob  2020  2.9
1    Sally  2020  3.7
2     Rich  2020  3.2
3  Melissa  2021  3.8
4      Len  2021  3.8
5      Sue  2021  3.1
6      Jon  2021  3.2
7    Sandy  2022  2.7
8  William  2022  3.6
9     Sara  2022  3.9

用户尝试的代码及问题

用户尝试通过groupby获取每年最高GPA,但结果缺少学生列:

result = df.groupby(['year'])[['gpa']].max().reset_index()

输出:

year    gpa
0   2020    3.7
1   2021    3.8
2   2022    3.9

需要得到包含对应学生(含并列)的结果:

year   gpa       student
2020   3.7       Sally
2021   3.8       Len
2021   3.8       Melissa
2022   3.9       Sara

解决方案

方法1:先计算年度最高GPA,再筛选原数据

先通过groupby得到每年的最高GPA,再用布尔索引匹配原数据中符合条件的行:

# 计算每年的最高GPA
year_max_gpa = df.groupby('year')['gpa'].max().reset_index()
# 合并并筛选
result = df.merge(year_max_gpa, on=['year', 'gpa'])
# 调整列顺序(可选)
result = result[['year', 'gpa', 'student']]

输出:

year  gpa   student
0  2020  3.7     Sally
1  2021  3.8   Melissa
2  2021  3.8       Len
3  2022  3.9      Sara

方法2:使用transform方法(更简洁)

transform会将分组后的结果广播到原数据的每一行,直接筛选出等于年度最高GPA的行:

# 标记出每行是否等于当年最高GPA
df['is_max_gpa'] = df['gpa'] == df.groupby('year')['gpa'].transform('max')
# 筛选标记为True的行,再去掉辅助列
result = df[df['is_max_gpa']][['year', 'gpa', 'student']]

输出和方法1一致。

方法3:使用rank方法

通过排名筛选出当年GPA排名第一的学生(支持并列):

# 按年份分组,对GPA降序排名,并列的取相同排名
df['gpa_rank'] = df.groupby('year')['gpa'].rank(method='min', ascending=False)
# 筛选排名为1的行
result = df[df['gpa_rank'] == 1][['year', 'gpa', 'student']]

输出同样符合要求。


内容的提问来源于stack exchange,提问作者equanimity

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 13:55:33