Pandas erhalten die obersten n Datensätze innerhalb jeder Gruppe

Lesezeit: 4 Minuten

Benutzer-Avatar
Roman Pekar

Angenommen, ich habe Pandas DataFrame wie folgt:

df = pd.DataFrame({'id':[1,1,1,2,2,2,2,3,4],'value':[1,2,3,1,2,3,4,1,1]})

das sieht aus wie:

   id  value
0   1      1
1   1      2
2   1      3
3   2      1
4   2      2
5   2      3
6   2      4
7   3      1
8   4      1

Ich möchte einen neuen DataFrame mit den Top 2 Datensätzen für jede ID erhalten, wie folgt:

   id  value
0   1      1
1   1      2
3   2      1
4   2      2
7   3      1
8   4      1

Ich kann es tun, indem ich Datensätze innerhalb der Gruppe danach nummeriere groupby:

dfN = df.groupby('id').apply(lambda x:x['value'].reset_index()).reset_index()

das sieht aus wie:

   id  level_1  index  value
0   1        0      0      1
1   1        1      1      2
2   1        2      2      3
3   2        0      3      1
4   2        1      4      2
5   2        2      5      3
6   2        3      6      4
7   3        0      7      1
8   4        0      8      1

dann für die gewünschte Ausgabe:

dfN[dfN['level_1'] <= 1][['id', 'value']]

Ausgabe:

   id  value
0   1      1
1   1      2
3   2      1
4   2      2
7   3      1
8   4      1

Aber gibt es dafür einen effektiveren/eleganteren Ansatz? Und es gibt auch einen eleganteren Ansatz, um Datensätze innerhalb jeder Gruppe zu nummerieren (wie die SQL-Fensterfunktion Zeilennummer()).

  • Ein mögliches Duplikat des Pandas-Datenrahmens erhält die erste Zeile jeder Gruppe

    – ssoler

    26. September 2016 um 15:51 Uhr

  • “top-n” bedeutet nicht “die n obersten/ersten/obersten Reihen”, wie Sie suchen! Es bedeutet “die n Zeilen mit den größten Werten”.

    – smci

    13. Mai 2018 um 11:50 Uhr

Benutzer-Avatar
dorvak

Hast du versucht

df.groupby('id').head(2)

Erzeugte Ausgabe:

       id  value
id             
1  0   1      1
   1   1      2 
2  3   2      1
   4   2      2
3  7   3      1
4  8   4      1

(Beachten Sie, dass Sie je nach Ihren Daten möglicherweise vorher bestellen/sortieren müssen)

EDIT: Wie vom Fragesteller erwähnt, use

df.groupby('id').head(2).reset_index(drop=True)

So entfernen Sie den MultiIndex und glätten die Ergebnisse:

    id  value
0   1      1
1   1      2
2   2      1
3   2      2
4   3      1
5   4      1

  • Ja, ich denke, das ist es. Hab das irgendwie übersehen. Kennen Sie eine gute Möglichkeit, Datensätze innerhalb der Gruppe zu nummerieren?

    – Roman Pekar

    19. November 2013 um 10:48 Uhr


  • Um eine Ausgabe zu erhalten, die ich benötige, habe ich auch hinzugefügt .reset_index(drop=True)

    – Roman Pekar

    19. November 2013 um 10:57 Uhr

  • github.com/pydata/pandas/pull/5510 wurde gerade eingegliedert; wird in 0.13 eine neue Methode um genau das zu tun aufgerufen cumcount (nummerieren Sie die Datensätze in jeder Gruppe)

    – Jeff

    19. November 2013 um 11:10 Uhr

  • Um @dorvak seine Antwort vollständiger zu machen, wenn Sie die 2 kleinsten Werte pro möchten id dann mach df.sort_values(['id', 'value'], axis=0).groupby('id').head(2). Ein anderes Beispiel, der größte Wert pro id wird von gegeben df.sort_values(['id', 'value'], axis=0).groupby('id').tail(1).

    – Elmex80s

    17. Oktober 2017 um 13:56 Uhr


  • Ab Version 0.23.4 ist danach kein Abflachen mehr erforderlich df.groupby('id').head(2). Quelle

    – rocarvaj

    8. November 2018 um 15:05 Uhr

Seit 0.14.1können Sie jetzt tun nlargest und nsmallest auf einen groupby Objekt:

In [23]: df.groupby('id')['value'].nlargest(2)
Out[23]: 
id   
1   2    3
    1    2
2   6    4
    5    3
3   7    1
4   8    1
dtype: int64

Es ist eine leichte Verrücktheit, dass Sie dort auch den Originalindex erhalten, aber das kann sehr nützlich sein, je nachdem, was Ihr Originalindex ist war.

Wenn es dich nicht interessiert, kannst du es tun .reset_index(level=1, drop=True) ganz davon loszukommen.

(Notiz: Ab 0.17.1 Sie können dies auch auf einem DataFrameGroupBy tun, aber im Moment funktioniert es nur mit Series und SeriesGroupBy.)

  • Es gibt einen Weg zu bekommen unique_limit(n)? Wie möchte ich die ersten n eindeutigen Werte? Wenn ich darum bitte nlargest es wird das gesamte df sortieren, was teuer sein kann

    – stadtnormal

    29. März 2018 um 0:54 Uhr

  • Dies funktioniert nicht für Fälle, in denen Sie ein Aggregat für das Groupby ausführen? Zum Beispiel, df.groupby([pd.Grouper(freq='M'), 'A'])['B'].count().nlargest(5, 'B') Dies gibt nur die Top 5 der gesamten Serie zurück, nicht nach jeder Gruppe

    – geogeistig

    21. Juni 2019 um 7:13 Uhr


  • Die Aussage, dass dies nun auch möglich ist, steht auf DataFrameGroupBys falsch zu sein scheint, scheint die verknüpfte Pull-Anforderung hinzuzufügen nlargest zu einfach DataFrames nur. Was ziemlich unglücklich ist, denn was ist, wenn Sie mehr als eine Spalte auswählen möchten?

    – oulenz

    23. Oktober 2019 um 13:53 Uhr

Manchmal ist das Sortieren der gesamten Daten sehr zeitaufwändig. Wir können zuerst gruppieren und für jede Gruppe topk machen:

g = df.groupby(['id']).apply(lambda x: x.nlargest(topk,['value'])).reset_index(drop=True)

df.groupby('id').apply(lambda x : x.sort_values(by = 'value', ascending = False).head(2).reset_index(drop = True))
  • Hier gibt Sortierwerte aufsteigend „false“ ähnlich wie „nlargest“ und „true“ ähnlich wie „nsmallest“ aus.
  • Der Wert im Kopf ist derselbe wie der Wert, den wir im größten Wert angeben, um die Anzahl der anzuzeigenden Werte für jede Gruppe zu erhalten.
  • reset_index ist optional und nicht notwendig.

Dies funktioniert für doppelte Werte

Wenn Sie doppelte Werte in den Top-n-Werten haben und nur eindeutige Werte wünschen, können Sie folgendermaßen vorgehen:

import pandas as pd

ifile = "https://raw.githubusercontent.com/bhishanpdl/Shared/master/data/twitter_employee.tsv"
df = pd.read_csv(ifile,delimiter="\t")
print(df.query("department == 'Audit'")[['id','first_name','last_name','department','salary']])

    id first_name last_name department  salary
24  12   Shandler      Bing      Audit  110000
25  14      Jason       Tom      Audit  100000
26  16     Celine    Anston      Audit  100000
27  15    Michale   Jackson      Audit   70000

If we do not remove duplicates, for the audit department we get top 3 salaries as 110k,100k and 100k.
If we want to have not-duplicated salaries per each department, we can do this:

(df.groupby('department')['salary']
 .apply(lambda ser: ser.drop_duplicates().nlargest(3))
 .droplevel(level=1)
 .sort_index()
 .reset_index()
)

This gives

department  salary
0   Audit   110000
1   Audit   100000
2   Audit   70000
3   Management  250000
4   Management  200000
5   Management  150000
6   Sales   220000
7   Sales   200000
8   Sales   150000





1049410cookie-checkPandas erhalten die obersten n Datensätze innerhalb jeder Gruppe

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy