Python 使用groupby获取组中具有最大值的行

Python 使用groupby获取组中具有最大值的行,python,pandas,max,pandas-groupby,Python,Pandas,Max,Pandas Groupby,在按['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 MM

在按
['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**
   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
预期输出:获取组间计数最大的结果行,如:

0  MM1  S1   a      **3**
2  MM1  S3   cb     **5**
3  MM2  S3   mk     **8**
4  MM2  S4   bg     **10** 
8  MM4  S2   uyi    **7**
示例2:我根据
['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**
   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
对于上面的示例,我希望得到all每个组中
count
等于max的行,例如:

MM2  S4   bg     10
MM4  S2   cb     8
MM4  S2   uyi    8
要获取原始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
请注意,如果每个组有多个max值,则将返回所有值

更新

有可能这就是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
要获取原始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
请注意,如果每个组有多个max值,则将返回所有值

更新

有可能这就是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

在一个相对较大的数据帧(约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']]

在一个相对较大的数据帧(约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']]

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

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

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

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

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

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

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

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

简单的解决方案是应用: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])

简单的解决方案是应用: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])

使用
groupby
idxmax
方法:

  • 将列
    日期
    传输到
    日期时间

    df['date']=pd.to_datetime(df['date'])
    
  • 获取列
    日期
    max
    索引,在
    组之后按ad\u id

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

    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
    

    使用
    groupby
    idxmax
    方法:

  • 将列
    日期
    传输到
    日期时间

    df['date']=pd.to_datetime(df['date'])
    
  • 获取列
    日期
    max
    索引,在
    组之后按ad\u id

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

    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
    

    您可能不需要使用分组方式,使用
    排序\u值
    +
    删除重复项

    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
    

    您可能不需要使用分组方式,使用
    排序\u值
    +
    删除重复项

    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
    

    我在许多集团运营中都使用了这种功能性风格:

    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\u index(drop=True)
    通过删除组索引将您恢复到原始索引。

    我在许多组操作中都使用了此功能样式:

    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\u index(drop=True)
    通过删除组索引将您恢复到原始索引。

    意识到将“nlargest”应用到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
    
    意识到将“nlargest”应用于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
    
    尝试在groupby对象上使用“nlargest”。使用nlargest的优点是,它返回从中获取“nlargest项”的行的索引。 注意:我们对索引的第二(1)个元素进行切片,因为本例中的索引由元组组成(例如(s1,0))

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


    总的来说,有很多方法,但哪一种更快

    import pandas as pd
    import numpy as np
    import time
    
    df = pd.DataFrame(np.random.randint(1,10,size=(1000000, 2)), columns=list('AB'))
    
    start_time = time.time()
    df1idx = df.groupby(['A'])['B'].transform(max) == df['B']
    df1 = df[df1idx]
    print("---1 ) %s seconds ---" % (time.time() - start_time))
    
    start_time = time.time()
    df2 = df.sort_values('B').groupby(['A']).tail(1)
    print("---2 ) %s seconds ---" % (time.time() - start_time))
    
    start_time = time.time()
    df3 = df.sort_values('B').drop_duplicates(['A'],keep='last')
    print("---3 ) %s seconds ---" % (time.time() - start_time))
    
    start_time = time.time()
    df3b = df.sort_values('B', ascending=False).drop_duplicates(['A'])
    print("---3b) %s seconds ---" % (time.time() - start_time))
    
    start_time = time.time()
    df4 = df[df['B'] == df.groupby(['A'])['B'].transform(max)]
    print("---4 ) %s seconds ---" % (time.time() - start_time))
    
    start_time = time.time()
    d = df.groupby('A')['B'].nlargest(1)
    df5 = df.iloc[[i[1] for i in d.index], :]
    print("---5 ) %s seconds ---" % (time.time() - start_time))
    
    获胜者是

    • --1)0.03337574005126953秒---
    • --2)0.1346898078918457秒---
    • --3)0.1024355883666992秒---
    • --3b)0.1004343032836914秒---
    • --4)0.028397560119628906秒---
    • --5)0.07552886009216309秒---

    总而言之,有很多方法,但哪一种更快

    import pandas as pd
    import numpy as np
    import time
    
    df = pd.DataFrame(np.random.randint(1,10,size=(1000000, 2)), columns=list('AB'))
    
    start_time = time.time()
    df1idx = df.groupby(['A'])['B'].transform(max) == df['B']
    df1 = df[df1idx]
    print("---1 ) %s seconds ---" % (time.time() - start_time))
    
    start_time = time.time()
    df2 = df.sort_values('B').groupby(['A']).tail(1)
    print("---2 ) %s seconds ---" % (time.time() - start_time))
    
    start_time = time.time()
    df3 = df.sort_values('B').drop_duplicates(['A'],keep='last')
    print("---3 ) %s seconds ---" % (time.time() - start_time))
    
    start_time = time.time()
    df3b = df.sort_values('B', ascending=False).drop_duplicates(['A'])
    print("---3b) %s seconds ---" % (time.time() - start_time))
    
    start_time = time.time()
    df4 = df[df['B'] == df.groupby(['A'])['B'].transform(max)]
    print("---4 ) %s seconds ---" % (time.time() - start_time))
    
    start_time = time.time()
    d = df.groupby('A')['B'].nlargest(1)
    df5 = df.iloc[[i[1] for i in d.index], :]
    print("---5 ) %s seconds ---" % (time.time() - start_time))
    
    获胜者是

    • --1)0.03337574005126953秒---
    • --2)0.1346898078918457秒---
    • --3)0.1024355883666992秒---
    • --3b)0.1004343032836914秒---
    • --4)0.028397560119628906秒---
    • --5)0.07552886009216309秒---

    如果对数据帧进行排序,排序将保留在groupby中。然后,您可以抓取第一个或最后一个元素并重置索引

    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.sort_values("count", ascending=False).groupby(["sp", "mt"]).first().reset_index()
    

    如果对数据帧进行排序,排序将保留在groupby中。然后,您可以抓取第一个或最后一个元素并重置索引

    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.sort_values("count", ascending=False).groupby(["sp", "mt"]).first().reset_index()
    

    你的数据框是什么格式的?我不明白。什么是团体?为什么结果中的第二行以
    13
    开头?这个答案是我能找到的最快的解决方案