如何在Pandas中选择分组 Dataframe 的最佳行

djmepvbi  于 2023-01-24  发布在  其他
关注(0)|答案(3)|浏览(144)

假设我有以下 Dataframe

df = pd.DataFrame.from_dict({'class':['A', 'A', 'A', 'B','B'],
                            'name': ['max1', 'lisa1', 'max3', 'lisa2', 'lisa3'],
                             'gender': ['m', 'f','m','f','f'],
                            'grade':[2,3,1, 2,4]})
>>> print(df)
  class   name gender  grade
0     A   max1      m      2
1     A  lisa1      f      3
2     A   max3      m      1
3     B  lisa2      f      2
4     B  lisa3      f      4

我想得到每个班最好的学生。(成绩越低越好)

class  grade   name gender
0     A      1   max3      m
1     B      2  lisa2      f

我怎样才能在Pandas身上做到这一点呢?另外,如果最好的分数不是唯一的,就像上面的例子一样,我怎样才能选择第一个出现的最好/将它们聚合到一个列表中呢?
为了澄清,假设lisa 3的等级为2而不是4,那么我希望得到的结果将是:

  • 首次发生:同上
  • 聚合到列表中:
class  grade            name  gender
0     A      1          [max3]     [m]
1     B      2  [lisa2, lisa3]  [f, f]
wkyowqbh

wkyowqbh1#

您可以使用pandas.DataFrame.groupby按每个班级对学生进行分组,对于每个班级,您可以使用transform获得最小值,然后使用pandas.Series.tolist将出现多次的行转换为列表。

df = pd.DataFrame.from_dict({'class':['A', 'A', 'A', 'B','B'],
                        'name': ['max1', 'lisa1', 'max3', 'lisa2', 'lisa3'],
                         'gender': ['m', 'f','m','f','f'],
                        'grade':[2,3,1, 2,2]})

temp = df[df.grade == df.groupby(['class'])['grade'].transform('min')]
temp.groupby(['class', 'grade']).agg(pd.Series.tolist)
输出:

这将为您提供预期输出:

name  gender
class grade                        
A     1              [max3]     [m]
B     2      [lisa2, lisa3]  [f, f]

DataFrameGroupBy.transform基本上会给出每个组的最小值,并返回一个DataFrame,该DataFrame具有与填充了转换值的原始对象相同的索引。在我们的示例中,每个组的min都是对应于每个索引值返回的。
所以df.groupby(['class'])['grade'].transform('min')给我们

0    1
1    1
2    1
3    2
4    2

其中12是它们各自组的最小值,对属于该组的每一行进行复制。

slmsl1lt

slmsl1lt2#

您可以按应用分组:

df.groupby("class", as_index=False).apply(lambda x: x[x['grade'].eq(x['grade'].min())].\
                                          groupby(['class', 'grade'], as_index=False).\
                                          agg(list)).reset_index(drop=True)

  class  grade            name  gender
0     A      1          [max3]     [m]
1     B      2  [lisa2, lisa3]  [f, f]
rjzwgtxy

rjzwgtxy3#

试试这个:

df.groupby(['class','grade']).agg(list).groupby('class').head(1)

df.loc[df['grade'].eq(df.groupby('class')['grade'].transform('min'))].groupby(['class','grade']).agg(list).reset_index()

输出:

name  gender
class grade                        
A     1              [max3]     [m]
B     2      [lisa2, lisa3]  [f, f]

相关问题