Pandas gruppieren nach Gruppen


166

Ich möchte meinen Datenrahmen nach zwei Spalten gruppieren und dann die aggregierten Ergebnisse innerhalb der Gruppen sortieren.

In [167]:
df

Out[167]:
count   job source
0   2   sales   A
1   4   sales   B
2   6   sales   C
3   3   sales   D
4   7   sales   E
5   5   market  A
6   3   market  B
7   2   market  C
8   4   market  D
9   1   market  E

In [168]:
df.groupby(['job','source']).agg({'count':sum})

Out[168]:
            count
job     source  
market  A   5
        B   3
        C   2
        D   4
        E   1
sales   A   2
        B   4
        C   6
        D   3
        E   7

Ich möchte jetzt die Zählspalte in absteigender Reihenfolge innerhalb jeder der Gruppen sortieren. Und dann nimm nur die obersten drei Reihen. Um so etwas zu bekommen wie:

            count
job     source  
market  A   5
        D   4
        B   3
sales   E   7
        C   6
        B   4

Antworten:


147

Was Sie tun möchten, ist tatsächlich wieder ein Groupby (nach dem Ergebnis des ersten Groupby): Sortieren und nehmen Sie die ersten drei Elemente pro Gruppe.

Ausgehend vom Ergebnis der ersten Gruppe durch:

In [60]: df_agg = df.groupby(['job','source']).agg({'count':sum})

Wir gruppieren nach der ersten Ebene des Index:

In [63]: g = df_agg['count'].groupby(level=0, group_keys=False)

Dann wollen wir jede Gruppe sortieren ('ordnen') und die ersten drei Elemente nehmen:

In [64]: res = g.apply(lambda x: x.order(ascending=False).head(3))

Hierzu gibt es jedoch eine Verknüpfungsfunktion nlargest:

In [65]: g.nlargest(3)
Out[65]:
job     source
market  A         5
        D         4
        B         3
sales   E         7
        C         6
        B         4
dtype: int64

Gibt es eine Möglichkeit, alles, was nicht in den drei besten Ergebnissen pro Gruppe enthalten ist, zusammenzufassen und für jeden Job einer Quellgruppe mit dem Namen "other" hinzuzufügen?
JoeDanger

30
orderist veraltete Verwendung sort_valuesstattdessen
zthomas.nc

Danke für die tolle Antwort. Gibt es für einen weiteren Schritt eine Möglichkeit, die Sortierreihenfolge basierend auf den Werten in der Spalte groupby zuzuweisen? Sortieren Sie beispielsweise aufsteigend, wenn der Wert "Kaufen" lautet, und sortieren Sie absteigend, wenn der Wert "Verkaufen" lautet.
Bowen Liu

171

Sie können es auch einfach auf einmal tun, indem Sie zuerst die Sortierung durchführen und mit head die ersten 3 jeder Gruppe nehmen.

In[34]: df.sort_values(['job','count'],ascending=False).groupby('job').head(3)

Out[35]: 
   count     job source
4      7   sales      E
2      6   sales      C
1      4   sales      B
5      5  market      A
8      4  market      D
6      3  market      B

13
Ist groupbygewährleistet , dass der Auftrag erhalten bleibt?
toto_tico

51
Es scheint so; aus der Dokumentation von groupby : groupby behält die Reihenfolge der Zeilen innerhalb jeder Gruppe bei
toto_tico

10
toto_tico- Das ist richtig, aber bei der Interpretation dieser Aussage ist Vorsicht geboten. Die Reihenfolge der Zeilen INNERHALB EINER EINZELNEN GRUPPE bleibt erhalten, jedoch hat groupby standardmäßig die Anweisung sort = True, was bedeutet, dass die Gruppen selbst möglicherweise nach dem Schlüssel sortiert wurden. Mit anderen Worten, wenn mein Datenrahmen Schlüssel hat (bei Eingabe) 3 2 2 1, .. zeigt die Gruppe nach Objekt die 3 Gruppen in der Reihenfolge 1 2 3 (sortiert). Verwenden Sie sort = False, um sicherzustellen, dass die Gruppenreihenfolge und die Zeilenreihenfolge erhalten bleiben.
user2103050

4
Kopf (3) gibt mehr als 3 Ergebnisse?
Nabin

27

Hier ist ein weiteres Beispiel für die Auswahl der Top 3 in sortierter Reihenfolge und die Sortierung innerhalb der Gruppen:

In [43]: import pandas as pd                                                                                                                                                       

In [44]:  df = pd.DataFrame({"name":["Foo", "Foo", "Baar", "Foo", "Baar", "Foo", "Baar", "Baar"], "count_1":[5,10,12,15,20,25,30,35], "count_2" :[100,150,100,25,250,300,400,500]})

In [45]: df                                                                                                                                                                        
Out[45]: 
   count_1  count_2  name
0        5      100   Foo
1       10      150   Foo
2       12      100  Baar
3       15       25   Foo
4       20      250  Baar
5       25      300   Foo
6       30      400  Baar
7       35      500  Baar


### Top 3 on sorted order:
In [46]: df.groupby(["name"])["count_1"].nlargest(3)                                                                                                                               
Out[46]: 
name   
Baar  7    35
      6    30
      4    20
Foo   5    25
      3    15
      1    10
dtype: int64


### Sorting within groups based on column "count_1":
In [48]: df.groupby(["name"]).apply(lambda x: x.sort_values(["count_1"], ascending = False)).reset_index(drop=True)
Out[48]: 
   count_1  count_2  name
0       35      500  Baar
1       30      400  Baar
2       20      250  Baar
3       12      100  Baar
4       25      300   Foo
5       15       25   Foo
6       10      150   Foo
7        5      100   Foo

9

Versuchen Sie dies stattdessen

einfache Möglichkeit, 'groupby' zu machen und in absteigender Reihenfolge zu sortieren

df.groupby(['companyName'])['overallRating'].sum().sort_values(ascending=False).head(20)

8

Wenn Sie keine Spalte summieren müssen, verwenden Sie die Antwort von @ tvashtar. Wenn Sie summieren müssen, können Sie die Antwort von @joris oder diese Antwort verwenden, die dieser sehr ähnlich ist.

df.groupby(['job']).apply(lambda x: (x.groupby('source')
                                      .sum()
                                      .sort_values('count', ascending=False))
                                     .head(3))
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.