web-dev-qa-db-fra.com

Obtenez des statistiques pour chaque groupe (comme le nombre, la moyenne, etc.) en utilisant pandas GroupBy?

J'ai un bloc de données df et j'en utilise plusieurs colonnes pour groupby:

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

De la manière ci-dessus, j'obtiens presque la table (trame de données) dont j'ai besoin. Ce qui manque, c'est une colonne supplémentaire contenant le nombre de lignes dans chaque groupe. En d'autres termes, j'ai moyen mais j'aimerais aussi savoir combien de nombres ont été utilisés pour obtenir ces moyens. Par exemple, dans le premier groupe, il y a 8 valeurs et dans le second, 10, etc.

En bref: Comment puis-je obtenir groupe par groupe statistiques pour un cadre de données?

336
Roman

Sur l'objet groupby, la fonction agg peut prendre une liste à appliquer plusieurs méthodes d'agrégation à la fois. Cela devrait vous donner le résultat dont vous avez besoin:

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

Réponse rapide:

Le moyen le plus simple d'obtenir le nombre de lignes par groupe consiste à appeler .size(), qui renvoie un Series:

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


Habituellement, vous voulez que ce résultat soit DataFrame (au lieu de Series) pour pouvoir:

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


Si vous voulez savoir comment calculer le nombre de lignes et d’autres statistiques pour chaque groupe, continuez la lecture ci-dessous.


Exemple détaillé:

Considérez l'exemple de dataframe suivant:

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

Premièrement, utilisons .size() pour obtenir le nombre de lignes:

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

Ensuite, utilisons .size().reset_index(name='counts') pour obtenir le nombre de lignes:

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


Y compris les résultats pour plus de statistiques

Lorsque vous souhaitez calculer des statistiques sur des données groupées, cela ressemble généralement à ceci:

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

Le résultat ci-dessus est un peu gênant à traiter en raison des étiquettes de colonne imbriquées, et aussi parce que le nombre de lignes est calculé colonne par colonne.

Pour obtenir plus de contrôle sur la sortie, je divise généralement les statistiques en agrégations individuelles que je combine ensuite à l'aide de join. Cela ressemble à ceci:

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



Notes de bas de page

Le code utilisé pour générer les données de test est présenté ci-dessous:

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:

Si certaines des colonnes que vous agrégez ont des valeurs NULL, vous voulez vraiment examiner le nombre de lignes de groupe en tant qu'agrégation indépendante pour chaque colonne. Sinon, vous pourriez être induit en erreur quant au nombre d'enregistrements réellement utilisés pour calculer des éléments tels que la moyenne, car pandas supprimera NaN entrées dans le calcul de la moyenne sans vous en informer.

737
Pedro M Duarte

Une fonction pour les gouverner tous: GroupBy.describe

Renvoie count, mean, std et d'autres statistiques utiles par groupe.

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

Pour obtenir des statistiques spécifiques, il suffit de les sélectionner,

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

describe fonctionne pour plusieurs colonnes (changez _['C']_ en _['C', 'D']_ - ou supprimez-le complètement - et voyez ce qu'il se passe, le résultat est un cadre de données à colonnes MultiIndexed).

Vous obtenez également des statistiques différentes pour les données de chaîne. Voici un exemple

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

Pour plus d'informations, voir le documentation .

11
cs95

Nous pouvons facilement le faire en utilisant groupby et compter. Mais, nous devrions nous rappeler d'utiliser reset_index ().

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

Créez un objet de groupe et appelez des méthodes comme dans l'exemple ci-dessous:

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

grp.max() 
grp.mean() 
grp.describe() 
0
Mahendra