Ricevi statistiche per ciascun gruppo (come conteggio, media, ecc.) Utilizzando Panda GroupBy?


439

Ho un frame di dati dfe ne uso diverse colonne per groupby:

df['col1','col2','col3','col4'].groupby(['col1','col2']).mean()

Nel modo sopra ottengo quasi la tabella (frame di dati) di cui ho bisogno. Ciò che manca è una colonna aggiuntiva che contiene il numero di righe in ciascun gruppo. In altre parole, ho cattive intenzioni, ma vorrei anche sapere quanti numeri sono stati usati per ottenere tali mezzi. Ad esempio nel primo gruppo ci sono 8 valori e nel secondo 10 e così via.

In breve: come posso ottenere statistiche di gruppo per un dataframe?

Risposte:


427

Sul groupbyoggetto, la aggfunzione può prendere un elenco di applicare diversi metodi di aggregazione in una sola volta. Questo dovrebbe darti il ​​risultato di cui hai bisogno:

df[['col1', 'col2', 'col3', 'col4']].groupby(['col1', 'col2']).agg(['mean', 'count'])

2
Penso che sia necessario che il riferimento alla colonna sia un elenco. Intendi forse: df[['col1','col2','col3','col4']].groupby(['col1','col2']).agg(['mean', 'count'])
rysqui,

43
Questo crea quattro colonne di conteggio, ma come ottenerne solo una? (La domanda chiede "un'ulteriore colonna" ed è quello che vorrei anche io.)
Jaan,

16
Si prega di vedere la mia risposta se si desidera ottenere solo una countcolonna per gruppo.
Pedro M Duarte,

Che cosa succede se ho un Conte separato chiamato e invece di contare le righe del tipo raggruppato, devo aggiungere lungo la colonna Conti.
Abhishek Bhatia,

@Jaan result = df['col1','col2','col3','col4'].groupby(['col1', 'col2']).mean() ; counts = times.groupby(['col1', 'col2']).size() ; result['count'] = counts
alvitawa,

913

Risposta rapida:

Il modo più semplice per ottenere il conteggio delle righe per gruppo è chiamando .size(), che restituisce un Series:

df.groupby(['col1','col2']).size()


Di solito vuoi questo risultato come DataFrame(invece di a Series) in modo da poter fare:

df.groupby(['col1', 'col2']).size().reset_index(name='counts')


Se vuoi scoprire come calcolare i conteggi delle righe e altre statistiche per ciascun gruppo, continua a leggere di seguito.


Esempio dettagliato:

Si consideri il seguente esempio di frame di dati:

In [2]: df
Out[2]: 
  col1 col2  col3  col4  col5  col6
0    A    B  0.20 -0.61 -0.49  1.49
1    A    B -1.53 -1.01 -0.39  1.82
2    A    B -0.44  0.27  0.72  0.11
3    A    B  0.28 -1.32  0.38  0.18
4    C    D  0.12  0.59  0.81  0.66
5    C    D -0.13 -1.65 -1.64  0.50
6    C    D -1.42 -0.11 -0.18 -0.44
7    E    F -0.00  1.42 -0.26  1.17
8    E    F  0.91 -0.47  1.35 -0.34
9    G    H  1.48 -0.63 -1.14  0.17

Per prima cosa usiamo .size()per ottenere i conteggi delle righe:

In [3]: df.groupby(['col1', 'col2']).size()
Out[3]: 
col1  col2
A     B       4
C     D       3
E     F       2
G     H       1
dtype: int64

Quindi usiamo .size().reset_index(name='counts')per ottenere i conteggi delle righe:

In [4]: df.groupby(['col1', 'col2']).size().reset_index(name='counts')
Out[4]: 
  col1 col2  counts
0    A    B       4
1    C    D       3
2    E    F       2
3    G    H       1


Compresi risultati per ulteriori statistiche

Quando vuoi calcolare le statistiche sui dati raggruppati, di solito si presenta così:

In [5]: (df
   ...: .groupby(['col1', 'col2'])
   ...: .agg({
   ...:     'col3': ['mean', 'count'], 
   ...:     'col4': ['median', 'min', 'count']
   ...: }))
Out[5]: 
            col4                  col3      
          median   min count      mean count
col1 col2                                   
A    B    -0.810 -1.32     4 -0.372500     4
C    D    -0.110 -1.65     3 -0.476667     3
E    F     0.475 -0.47     2  0.455000     2
G    H    -0.630 -0.63     1  1.480000     1

Il risultato sopra è un po 'fastidioso da gestire a causa delle etichette delle colonne nidificate e anche perché i conteggi delle righe sono basati su una colonna.

Per ottenere un maggiore controllo sull'output di solito divido le statistiche in singole aggregazioni che poi combino usando join. Sembra così:

In [6]: gb = df.groupby(['col1', 'col2'])
   ...: counts = gb.size().to_frame(name='counts')
   ...: (counts
   ...:  .join(gb.agg({'col3': 'mean'}).rename(columns={'col3': 'col3_mean'}))
   ...:  .join(gb.agg({'col4': 'median'}).rename(columns={'col4': 'col4_median'}))
   ...:  .join(gb.agg({'col4': 'min'}).rename(columns={'col4': 'col4_min'}))
   ...:  .reset_index()
   ...: )
   ...: 
Out[6]: 
  col1 col2  counts  col3_mean  col4_median  col4_min
0    A    B       4  -0.372500       -0.810     -1.32
1    C    D       3  -0.476667       -0.110     -1.65
2    E    F       2   0.455000        0.475     -0.47
3    G    H       1   1.480000       -0.630     -0.63



Le note

Il codice utilizzato per generare i dati di test è mostrato di seguito:

In [1]: import numpy as np
   ...: import pandas as pd 
   ...: 
   ...: keys = np.array([
   ...:         ['A', 'B'],
   ...:         ['A', 'B'],
   ...:         ['A', 'B'],
   ...:         ['A', 'B'],
   ...:         ['C', 'D'],
   ...:         ['C', 'D'],
   ...:         ['C', 'D'],
   ...:         ['E', 'F'],
   ...:         ['E', 'F'],
   ...:         ['G', 'H'] 
   ...:         ])
   ...: 
   ...: df = pd.DataFrame(
   ...:     np.hstack([keys,np.random.randn(10,4).round(2)]), 
   ...:     columns = ['col1', 'col2', 'col3', 'col4', 'col5', 'col6']
   ...: )
   ...: 
   ...: df[['col3', 'col4', 'col5', 'col6']] = \
   ...:     df[['col3', 'col4', 'col5', 'col6']].astype(float)
   ...: 


Disclaimer:

Se alcune delle colonne che stai aggregando hanno valori nulli, allora vuoi davvero guardare i conteggi delle righe di gruppo come aggregazione indipendente per ogni colonna. Altrimenti potresti essere indotto in errore su quanti record vengono effettivamente utilizzati per calcolare cose come la media perché i panda lasceranno cadere le NaNvoci nel calcolo della media senza dirtelo.


1
Ehi, mi piace molto la tua soluzione, in particolare l'ultima, in cui usi il concatenamento di metodi. Tuttavia, poiché è spesso necessario applicare diverse funzioni di aggregazione a colonne diverse, è possibile anche concatenare i frame di dati risultanti utilizzando pd.concat. Questo forse è più facile da leggere rispetto al concatenamento susseguente
Quickbeam2k1

4
bella soluzione, ma per In [5]: counts_df = pd.DataFrame(df.groupby('col1').size().rename('counts')), forse è meglio impostare la dimensione () come una nuova colonna se desideri manipolare il frame di dati per ulteriori analisi, che dovrebbe esserecounts_df = pd.DataFrame(df.groupby('col1').size().reset_index(name='counts')
LancelotHolmes,

2
Grazie per il bit "Incluso risultati per più statistiche"! Poiché la mia prossima ricerca riguardava l'appiattimento del multiindice risultante sulle colonne, collegherò alla risposta qui: stackoverflow.com/a/50558529/1026
Nickolay,

Grande! Potresti darmi un suggerimento su come aggiungere isnulla questa query per averla anche in una colonna? 'col4': ['median', 'min', 'count', 'isnull']
Peter.k,

38

Una funzione per dominarli tutti: GroupBy.describe

I ritorni count, mean, std, e altre statistiche utili per gruppo.

df.groupby(['col1', 'col2'])['col3', 'col4'].describe()

# Setup
np.random.seed(0)
df = pd.DataFrame({'A' : ['foo', 'bar', 'foo', 'bar',
                          'foo', 'bar', 'foo', 'foo'],
                   'B' : ['one', 'one', 'two', 'three',
                          'two', 'two', 'one', 'three'],
                   'C' : np.random.randn(8),
                   'D' : np.random.randn(8)})

from IPython.display import display

with pd.option_context('precision', 2):
    display(df.groupby(['A', 'B'])['C'].describe())

           count  mean   std   min   25%   50%   75%   max
A   B                                                     
bar one      1.0  0.40   NaN  0.40  0.40  0.40  0.40  0.40
    three    1.0  2.24   NaN  2.24  2.24  2.24  2.24  2.24
    two      1.0 -0.98   NaN -0.98 -0.98 -0.98 -0.98 -0.98
foo one      2.0  1.36  0.58  0.95  1.15  1.36  1.56  1.76
    three    1.0 -0.15   NaN -0.15 -0.15 -0.15 -0.15 -0.15
    two      2.0  1.42  0.63  0.98  1.20  1.42  1.65  1.87

Per ottenere statistiche specifiche, basta selezionarle,

df.groupby(['A', 'B'])['C'].describe()[['count', 'mean']]

           count      mean
A   B                     
bar one      1.0  0.400157
    three    1.0  2.240893
    two      1.0 -0.977278
foo one      2.0  1.357070
    three    1.0 -0.151357
    two      2.0  1.423148

describefunziona per più colonne (passare ['C']a ['C', 'D']—o rimuoverlo del tutto — e vedere cosa succede, il risultato è un frame di dati con colonne MultiIndexed).

Ottieni anche statistiche diverse per i dati delle stringhe. Ecco un esempio,

df2 = df.assign(D=list('aaabbccc')).sample(n=100, replace=True)

with pd.option_context('precision', 2):
    display(df2.groupby(['A', 'B'])
               .describe(include='all')
               .dropna(how='all', axis=1))

              C                                                   D                
          count  mean       std   min   25%   50%   75%   max count unique top freq
A   B                                                                              
bar one    14.0  0.40  5.76e-17  0.40  0.40  0.40  0.40  0.40    14      1   a   14
    three  14.0  2.24  4.61e-16  2.24  2.24  2.24  2.24  2.24    14      1   b   14
    two     9.0 -0.98  0.00e+00 -0.98 -0.98 -0.98 -0.98 -0.98     9      1   c    9
foo one    22.0  1.43  4.10e-01  0.95  0.95  1.76  1.76  1.76    22      2   a   13
    three  15.0 -0.15  0.00e+00 -0.15 -0.15 -0.15 -0.15 -0.15    15      1   c   15
    two    26.0  1.49  4.48e-01  0.98  0.98  1.87  1.87  1.87    26      2   b   15

Per ulteriori informazioni, consultare la documentazione .


Non tutte le distribuzioni sono normali. IQR sarebbe sorprendente.
Brad

7

Possiamo farlo facilmente usando groupby e count. Ma dovremmo ricordare di usare reset_index ().

df[['col1','col2','col3','col4']].groupby(['col1','col2']).count().\
reset_index()

3
Questa soluzione funziona fintanto che non esiste un valore nullo nelle colonne, altrimenti può essere fuorviante (il conteggio sarà inferiore al numero effettivo di osservazioni per gruppo).
Adrien Pacifico,

4

Per ottenere più statistiche, comprimi l'indice e mantieni i nomi delle colonne:

df = df.groupby(['col1','col2']).agg(['mean', 'count'])
df.columns = [ ' '.join(str(i) for i in col) for col in df.columns]
df.reset_index(inplace=True)
df

produce:

** inserisci qui la descrizione dell'immagine **


1

Creare un oggetto gruppo e chiamare metodi come nell'esempio seguente:

grp = df.groupby(['col1',  'col2',  'col3']) 

grp.max() 
grp.mean() 
grp.describe() 

1

Per favore prova questo codice

new_column=df[['col1', 'col2', 'col3', 'col4']].groupby(['col1', 'col2']).count()
df['count_it']=new_column
df

Penso che il codice aggiungerà una colonna chiamata "conta" che conta di ciascun gruppo

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.