Panda groupby ordinamento all'interno di gruppi


166

Voglio raggruppare il mio frame di dati per due colonne e quindi ordinare i risultati aggregati all'interno dei gruppi.

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

Vorrei ora ordinare la colonna dei conteggi in ordine decrescente all'interno di ciascuno dei gruppi. E poi prendi solo le prime tre file. Per ottenere qualcosa di simile:

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

Risposte:


147

Quello che vuoi fare è in realtà di nuovo un groupby (sul risultato del primo groupby): ordina e prendi i primi tre elementi per gruppo.

A partire dal risultato del primo groupby:

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

Raggruppiamo per il primo livello dell'indice:

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

Quindi vogliamo ordinare ('ordinare') ogni gruppo e prendere i primi tre elementi:

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

Tuttavia, per questo, c'è una funzione di collegamento per fare questo 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

Ci sarebbe un modo per riassumere tutto ciò che non è contenuto nei primi tre risultati per gruppo e aggiungerli a un gruppo di origine chiamato "altro" per ciascun lavoro?
JoeDanger,

31
orderè deprecato l'uso sort_valuesinvece
zthomas.nc

Grazie per la magnifica risposta. Per un ulteriore passaggio, ci sarebbe un modo per assegnare l'ordinamento in base ai valori nella colonna groupby? Ad esempio, ordina in ordine crescente se il valore è "Acquista" e ordina in ordine decrescente se il valore è "Vendi".
Bowen Liu

174

Puoi anche farlo in una sola volta, facendo prima l'ordinamento e usando head per prendere i primi 3 di ciascun gruppo.

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

14
Fa groupbygarantisce che l'ordine è conservato?
toto_tico,

52
Sembra di si; dalla documentazione di groupby : groupby conserva l'ordine delle righe all'interno di ciascun gruppo
toto_tico

10
toto_tico- È corretto, tuttavia occorre prestare attenzione nell'interpretazione di tale affermazione. L'ordine delle righe ENTRO UN SINGOLO GRUPPO viene conservato, tuttavia groupby ha un'istruzione sort = True per impostazione predefinita, il che significa che i gruppi stessi potrebbero essere stati ordinati sulla chiave. In altre parole, se il mio frame di dati ha le chiavi (in input) 3 2 2 1, .. il gruppo per oggetto mostrerà i 3 gruppi nell'ordine 1 2 3 (ordinati). Utilizzare sort = False per assicurarsi che l'ordine dei gruppi e l'ordine delle righe siano conservati.
user2103050

4
testa (3) dà più di 3 risultati?
Nabin,

27

Ecco un altro esempio di prendere i primi 3 nell'ordine ordinato e l'ordinamento all'interno dei gruppi:

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

Prova questo invece

modo semplice per fare 'groupby' e l'ordinamento in ordine decrescente

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

8

Se non hai bisogno di sommare una colonna, usa la risposta di @ tvashtar. Se hai bisogno di riassumere, puoi usare la risposta di @joris o questa che è molto simile ad essa.

df.groupby(['job']).apply(lambda x: (x.groupby('source')
                                      .sum()
                                      .sort_values('count', ascending=False))
                                     .head(3))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.