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?
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'])
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.
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 .
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()
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()