使用groupby获取分组中具有最大计数的行


244

count['Sp','Mt']列分组后,如何找到熊猫数据框中所有具有列最大值的行?

示例1:以下数据框,我将其分组['Sp','Mt']

   Sp   Mt Value   count
0  MM1  S1   a      **3**
1  MM1  S1   n      2
2  MM1  S3   cb     5
3  MM2  S3   mk      **8**
4  MM2  S4   bg     **10**
5  MM2  S4   dgd      1
6  MM4  S2  rd     2
7  MM4  S2   cb      2
8  MM4  S2   uyi      **7**

预期输出:获取结果行的数量在组之间最大,例如:

0  MM1  S1   a      **3**
1 3  MM2  S3   mk      **8**
4  MM2  S4   bg     **10** 
8  MM4  S2   uyi      **7**

示例2:此数据框,我将其分组['Sp','Mt']

   Sp   Mt   Value  count
4  MM2  S4   bg     10
5  MM2  S4   dgd    1
6  MM4  S2   rd     2
7  MM4  S2   cb     8
8  MM4  S2   uyi    8

对于上面的示例,我想获取每个组中等于max的所有行,count例如:

MM2  S4   bg     10
MM4  S2   cb     8
MM4  S2   uyi    8

您的数据框采用什么格式?
David Robinson

2
我不明白 一组到底是什么?为什么结果中的第二行以1 3
乔苏


1
这个答案是我能找到的最快的解决方案:stackoverflow.com/a/21007047/778533
tommy.carstensen

类似于这个问题,任何人都可以回答这个问题:stackoverflow.com/questions/62069465/… 谢谢。
ds_Abc

Answers:


325
In [1]: df
Out[1]:
    Sp  Mt Value  count
0  MM1  S1     a      3
1  MM1  S1     n      2
2  MM1  S3    cb      5
3  MM2  S3    mk      8
4  MM2  S4    bg     10
5  MM2  S4   dgd      1
6  MM4  S2    rd      2
7  MM4  S2    cb      2
8  MM4  S2   uyi      7

In [2]: df.groupby(['Mt'], sort=False)['count'].max()
Out[2]:
Mt
S1     3
S3     8
S4    10
S2     7
Name: count

要获取原始DF的索引,您可以执行以下操作:

In [3]: idx = df.groupby(['Mt'])['count'].transform(max) == df['count']

In [4]: df[idx]
Out[4]:
    Sp  Mt Value  count
0  MM1  S1     a      3
3  MM2  S3    mk      8
4  MM2  S4    bg     10
8  MM4  S2   uyi      7

请注意,如果每个组有多个最大值,则将全部返回。

更新资料

在OP所要求的情况下,这真是万劫不复:

In [5]: df['count_max'] = df.groupby(['Mt'])['count'].transform(max)

In [6]: df
Out[6]:
    Sp  Mt Value  count  count_max
0  MM1  S1     a      3          3
1  MM1  S1     n      2          3
2  MM1  S3    cb      5          8
3  MM2  S3    mk      8          8
4  MM2  S4    bg     10         10
5  MM2  S4   dgd      1         10
6  MM4  S2    rd      2          7
7  MM4  S2    cb      2          7
8  MM4  S2   uyi      7          7

@ Zelazny7,有没有一种方法可以采用此答案将其应用于按列分组,然后查看2列并最多进行两列以获得两者中的更大者?我不能让它工作。我目前拥有的是:def Greater(Merge,maximumA,maximumB):a = Merge [maximumA] b = Merge [maximumB] return max(a,b)Merger.groupby(“ Search_Term”)。apply(Greater,“ Ratio_x “,” Ratio_y“)
mathlover

3
@ Zelazny7我正在使用第二种idx方法。但是,我只能负担每个组的一个最大值(并且我的数据有几个重复最大值)。有没有办法解决您的解决方案?
3pitt

实际上,这对我不起作用。我无法跟踪问题,因为如果退出时数据帧很大,但是@Rani的解决方案效果很好
Ladenkov Vladislav

嗨,Zealzny,如果我想采用前3个最大行而不是一个最大值,该如何调整代码?
Zephyr

transform当数据集足够大时,此方法可能具有池性能,请先获取最大值,然后合并数据帧会更好。
伍兹·陈

170

您可以按计数对dataFrame排序,然后删除重复项。我认为这更容易:

df.sort_values('count', ascending=False).drop_duplicates(['Sp','Mt'])

4
非常好!快速使用大型框架(2.5万行)
Nolan Conaway

2
对于那些刚接触Python的用户,您需要将其分配给新变量,它不会更改当前的df变量。
泰勒(Tyler)

1
@Samir或将其inplace = True用作drop_duplicates
TMrtSmith

5
当只需要一个具有相同最大值的行时,这是一个很好的答案,但是如果我需要所有具有最大值的行,它将无法按预期工作。
伍兹·陈

1
@WoodsChen,它将删除[sp,mt]的重复项,因此在您的示例中,输出应仅为一行。
拉尼

54

一个简单的解决方案是应用:idxmax()函数来获取具有最大值的行的索引。 这将过滤出组中具有最大值的所有行。

In [365]: import pandas as pd

In [366]: df = pd.DataFrame({
'sp' : ['MM1', 'MM1', 'MM1', 'MM2', 'MM2', 'MM2', 'MM4', 'MM4','MM4'],
'mt' : ['S1', 'S1', 'S3', 'S3', 'S4', 'S4', 'S2', 'S2', 'S2'],
'val' : ['a', 'n', 'cb', 'mk', 'bg', 'dgb', 'rd', 'cb', 'uyi'],
'count' : [3,2,5,8,10,1,2,2,7]
})

In [367]: df                                                                                                       
Out[367]: 
   count  mt   sp  val
0      3  S1  MM1    a
1      2  S1  MM1    n
2      5  S3  MM1   cb
3      8  S3  MM2   mk
4     10  S4  MM2   bg
5      1  S4  MM2  dgb
6      2  S2  MM4   rd
7      2  S2  MM4   cb
8      7  S2  MM4  uyi


### Apply idxmax() and use .loc() on dataframe to filter the rows with max values:
In [368]: df.loc[df.groupby(["sp", "mt"])["count"].idxmax()]                                                       
Out[368]: 
   count  mt   sp  val
0      3  S1  MM1    a
2      5  S3  MM1   cb
3      8  S3  MM2   mk
4     10  S4  MM2   bg
8      7  S2  MM4  uyi

### Just to show what values are returned by .idxmax() above:
In [369]: df.groupby(["sp", "mt"])["count"].idxmax().values                                                        
Out[369]: array([0, 2, 3, 4, 8])

4
根据文档(0.21)"I want to get ALL the rows where count equals max in each group",发问者在此指定idxmax Return[s] index of first occurrence of maximum over requested axis"
Max Power

1
这是一个很好的解决方案,但针对另一个问题
卡洛斯·索萨

33

在较大的DataFrame(约40万行)上尝试了Zelazny建议的解决方案后,我发现它非常慢。这是我发现在数据集上运行速度快几个数量级的替代方法。

df = pd.DataFrame({
    'sp' : ['MM1', 'MM1', 'MM1', 'MM2', 'MM2', 'MM2', 'MM4', 'MM4', 'MM4'],
    'mt' : ['S1', 'S1', 'S3', 'S3', 'S4', 'S4', 'S2', 'S2', 'S2'],
    'val' : ['a', 'n', 'cb', 'mk', 'bg', 'dgb', 'rd', 'cb', 'uyi'],
    'count' : [3,2,5,8,10,1,2,2,7]
    })

df_grouped = df.groupby(['sp', 'mt']).agg({'count':'max'})

df_grouped = df_grouped.reset_index()

df_grouped = df_grouped.rename(columns={'count':'count_max'})

df = pd.merge(df, df_grouped, how='left', on=['sp', 'mt'])

df = df[df['count'] == df['count_max']]

1
确实,这要快得多。对于大型数据集,转换似乎很慢。
goh 2014年

1
您可以添加注释来解释每一行的作用吗?
tommy.carstensen

fwiw:我发现@ Zelazny7提供的看起来更优雅的解决方案花了很长时间才能执行我的约10万行记录,但是这个运行很快。(我正在运行一种现在已经过时的0.13.0,这可能是缓慢的原因)。
罗兰

2
但是这样做df[df['count'] == df['count_max']]会丢失NaN行以及上面的答案。
Qy Zuo

我强烈建议使用此方法,对于较大的数据帧,使用.appy()或.agg()的速度要快得多。
Touya D. Serdan

18

您可能不需要使用sort_values+ 来分组drop_duplicates

df.sort_values('count').drop_duplicates(['Sp','Mt'],keep='last')
Out[190]: 
    Sp  Mt Value  count
0  MM1  S1     a      3
2  MM1  S3    cb      5
8  MM4  S2   uyi      7
3  MM2  S3    mk      8
4  MM2  S4    bg     10

通过使用也几乎相同的逻辑 tail

df.sort_values('count').groupby(['Sp', 'Mt']).tail(1)
Out[52]: 
    Sp  Mt Value  count
0  MM1  S1     a      3
2  MM1  S3    cb      5
8  MM4  S2   uyi      7
3  MM2  S3    mk      8
4  MM2  S4    bg     10

这不仅比其他解决方案快一个数量级(至少在我的用例中如此),而且还具有附加的好处,即简单地链接作为原始数据帧的一部分。
Clay

我挠头想当然地认为这很简单,感谢您像温先生一样出色的回答。
Datanovice

7

对我来说,最简单的解决方案是当count等于最大值时保持值。因此,以下一行命令就足够了:

df[df['count'] == df.groupby(['Mt'])['count'].transform(max)]

4

用途groupbyidxmax方法:

  1. 转移col datedatetime

    df['date']=pd.to_datetime(df['date'])
  2. 得到的索引max列的date,后groupyby ad_id

    idx=df.groupby(by='ad_id')['date'].idxmax()
  3. 获取所需数据:

    df_max=df.loc[idx,]

出[54]:

ad_id  price       date
7     22      2 2018-06-11
6     23      2 2018-06-22
2     24      2 2018-06-30
3     28      5 2018-06-22

2
df = pd.DataFrame({
'sp' : ['MM1', 'MM1', 'MM1', 'MM2', 'MM2', 'MM2', 'MM4', 'MM4','MM4'],
'mt' : ['S1', 'S1', 'S3', 'S3', 'S4', 'S4', 'S2', 'S2', 'S2'],
'val' : ['a', 'n', 'cb', 'mk', 'bg', 'dgb', 'rd', 'cb', 'uyi'],
'count' : [3,2,5,8,10,1,2,2,7]
})

df.groupby(['sp', 'mt']).apply(lambda grp: grp.nlargest(1, 'count'))

2

意识到将“最大”应用groupby对象同样有效:

附加优势- 如果需要,还可以获取 前n个值

In [85]: import pandas as pd

In [86]: df = pd.DataFrame({
    ...: 'sp' : ['MM1', 'MM1', 'MM1', 'MM2', 'MM2', 'MM2', 'MM4', 'MM4','MM4'],
    ...: 'mt' : ['S1', 'S1', 'S3', 'S3', 'S4', 'S4', 'S2', 'S2', 'S2'],
    ...: 'val' : ['a', 'n', 'cb', 'mk', 'bg', 'dgb', 'rd', 'cb', 'uyi'],
    ...: 'count' : [3,2,5,8,10,1,2,2,7]
    ...: })

## Apply nlargest(1) to find the max val df, and nlargest(n) gives top n values for df:
In [87]: df.groupby(["sp", "mt"]).apply(lambda x: x.nlargest(1, "count")).reset_index(drop=True)
Out[87]:
   count  mt   sp  val
0      3  S1  MM1    a
1      5  S3  MM1   cb
2      8  S3  MM2   mk
3     10  S4  MM2   bg
4      7  S2  MM4  uyi

2

尝试在groupby对象上使用“ nlargest”。使用nlargest的优点是它返回从中获取“最大的项目”的行的索引。注意:由于我们的索引由元组组成(例如(s1,0)),因此我们对索引的second(1)元素进行了切片。

df = pd.DataFrame({
'sp' : ['MM1', 'MM1', 'MM1', 'MM2', 'MM2', 'MM2', 'MM4', 'MM4','MM4'],
'mt' : ['S1', 'S1', 'S3', 'S3', 'S4', 'S4', 'S2', 'S2', 'S2'],
'val' : ['a', 'n', 'cb', 'mk', 'bg', 'dgb', 'rd', 'cb', 'uyi'],
'count' : [3,2,5,8,10,1,2,2,7]
})

d = df.groupby('mt')['count'].nlargest(1) # pass 1 since we want the max

df.iloc[[i[1] for i in d.index], :] # pass the index of d as list comprehension

在此处输入图片说明


1

我已经在许多小组操作中使用了这种功能风格:

df = pd.DataFrame({
   'Sp' : ['MM1', 'MM1', 'MM1', 'MM2', 'MM2', 'MM2', 'MM4', 'MM4', 'MM4'],
   'Mt' : ['S1', 'S1', 'S3', 'S3', 'S4', 'S4', 'S2', 'S2', 'S2'],
   'Val' : ['a', 'n', 'cb', 'mk', 'bg', 'dgb', 'rd', 'cb', 'uyi'],
   'Count' : [3,2,5,8,10,1,2,2,7]
})

df.groupby('Mt')\
  .apply(lambda group: group[group.Count == group.Count.max()])\
  .reset_index(drop=True)

    sp  mt  val  count
0  MM1  S1    a      3
1  MM4  S2  uyi      7
2  MM2  S3   mk      8
3  MM2  S4   bg     10

.reset_index(drop=True) 通过删除组索引可以使您回到原始索引。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.