499 Stimmen

Holen Sie sich die Zeile(n) mit dem maximalen Wert in Gruppen mithilfe von groupby

Wie finde ich alle Reihen in einem Pandas DataFrame, die den maximalen Wert für die count-Spalte haben, nachdem sie nach den ['Sp','Mt']-Spalten gruppiert wurden?

Beispiel 1: das folgende DataFrame:

   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**

Die erwartete Ausgabe besteht darin, die Zeilen zu erhalten, deren Zähler in jeder Gruppe maximal ist, wie folgt:

   Sp   Mt   Value  count
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**

Beispiel 2:

   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

Die erwartete Ausgabe:

   Sp   Mt   Value  count
4  MM2  S4   bg     10
7  MM4  S2   cb     8
8  MM4  S2   uyi    8

19voto

blueear Punkte 273

Verwenden Sie die Methoden groupby und idxmax:

  1. Übertragen Sie die Spalte date in datetime:

    df['date'] = pd.to_datetime(df['date'])
  2. Erhalten Sie den Index von max der Spalte date nach dem groupby ad_id:

    idx = df.groupby(by='ad_id')['date'].idxmax()
  3. Erhalten Sie die gewünschten Daten:

    df_max = df.loc[idx,]

    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

15voto

PAC Punkte 4990

Für mich wäre die einfachste Lösung, den Wert beizubehalten, wenn die Anzahl gleich dem Maximum ist. Daher genügt der folgende Einzeiler-Befehl:

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

10voto

Mauro Mascia Punkte 352

Zusammenfassend gibt es viele Möglichkeiten, aber welche ist schneller?

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))

Und der Gewinner ist...

  • --1 ) 0.03337574005126953 seconds ---
  • --2 ) 0.1346898078918457 seconds ---
  • --3 ) 0.10243558883666992 seconds ---
  • --3b) 0.1004343032836914 seconds ---
  • --4 ) 0.028397560119628906 seconds ---
  • --5 ) 0.07552886009216309 seconds ---

8voto

Kweweli Punkte 329

Versuchen Sie, nlargest auf das groupby-Objekt anzuwenden. Der Vorteil dabei ist, dass die Zeilen zurückgegeben werden, aus denen die "n größten Elemente" geholt wurden, und wir ihren Index erhalten können.

In diesem Fall möchten wir n=1 für das Maximum und keep='all' verwenden, um doppelte Maxima einzuschließen.

Hinweis: Wir schneiden das letzte (-1) Element unseres Index ab, da unser Index in diesem Fall aus Tupeln besteht (z.B. ('MM1', 'S1', 0)).

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(['Sp', 'Mt'])['count'].nlargest(1, keep='all')

df.loc[[i[-1] for i in d.index]]

    Sp  Mt  Val  count
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

7voto

joh-mue Punkte 1471

Ich verwende diesen funktionalen Stil seit vielen Gruppenoperationen:

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 group: group[group['Count'] == group['Count'].max()])
   .reset_index(drop=True))

    Sp  Mt  Val  Count
0  MM1  S1    a      3
1  MM1  S3   cb      5
2  MM2  S3   mk      8
3  MM2  S4   bg     10
4  MM4  S2  uyi      7

.reset_index(drop=True) bringt Sie zurück zum ursprünglichen Index, indem der Gruppenindex verworfen wird.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X