> Modules non standards > Pandas > Calcul des agrégats sur les dataframes
Calcul des agrégats sur les dataframes
Moyenne et écart-type :
- par colonne (moyenne des valeurs de chaque ligne pour une colonne) : df.mean(axis = 0) (c'est le défaut)
- de toutes les colonnes (une valeur par ligne) : df.mean(axis = 1)
- par défaut, saute les valeurs NaN, df.mean(skipna = True) (si False, on aura NaN à chaque fois qu'il y a au moins une valeur non définie).
- on peut aussi calculer la moyenne pour une seule colonne : df['A'].mean()
- df.std() : écart-type (au sens statistique, avec n - 1, contrairement à numpy.std dont le défaut est l'écart-type avec n : ddof = 0). Saute les valeurs à NaN par défaut (donc renvoie NaN si seulement 0 ou 1 valeur non NaN)
Pour calculer les pourcentages d'un dataframe :
- par colonne : df / df.sum()
- par ligne : df / df.apply(sum, axis = 1, result_type = 'broadcast') ou bien (df.T / df.T.sum()).T
Pour standardiser un dataframe :
- par colonne : (df - df.mean()) / df.std(ddof = 0)
- par ligne : (df - df.apply(numpy.mean, axis = 1, result_type = 'broadcast')) / df.apply(numpy.std, axis = 1, result_type = 'broadcast') ou ((df.T - df.T.mean()) / df.T.std(ddof = 0)).T
- attention : si les valeurs sont entières, faire d'abord df = df.astype(float)
Pour calculer la moyenne et l'écart-type sur plusieurs colonnes : df.agg(['mean', 'std']).T : donne une ligne par variable et 2 colonnes : mean et std.
Pour avoir un dataframe avec la moyenne de chaque ligne, mais les mêmes colonnes que le dataframe de départ :
- pandas.DataFrame({x:df.mean(axis = 1) for x in df.columns}) est une solution.
- numpy.mean(df, axis = 1, keepdims = True) ne marche pas
On peut grouper un dataframe par une ou plusieurs colonne. Si
df = pandas.DataFrame({'A': ['a', 'b', 'a', 'a', 'b'], 'B': [8, 4, 5, 10, 8], 'C': ['x', 'x', 'y', 'y', 'x'], 'D': [0, 1, 2, 3, 4]}) :
- df.groupby('A') : renvoie un objet de la classe pandas.core.groupby.DataFrameGroupBy.
- len(df.groupby('A')) : nombre de groupes
- df.groupby('A').groups : dictionnaire valeur vers liste des index pour cette valeur.
- df.groupby('A').sum() : groupe avec les valeurs de A et fait la somme, pour les colonnes pour lesquelles c'est possible :
B D
A
a 23 5
b 12 5
- on peut inclure plusieurs colonnes : df.groupby(['A', 'C']).sum() donne :
B D
A C
a x 8 0
y 15 5
b x 12 5
- si on veut que les colonnes qui ont servi à faire le groupage se retrouvent comme colonnes normales (et non dans l'index) : df.groupby(['A', 'C']).sum().reset_index() donne :
A C B D
0 a x 8 0
1 a y 15 5
2 b x 12 5
- df.loc[:, ['A', 'B']].groupby('A').count() : compte le nombre de valeurs de B pour chaque groupe correspondant à une valeur de A. Attention, si B a des valeurs NaN, elles ne comptent pas !
- Si df est un dataframe avec les colonnes A et B, et que l'on fait s = df.groupby(['A', 'B'].size() :
- on obtient une series
- faire s.name = 'nbr' pour donner un nom à la series.
- si on fait s.reset_index(), on aura alors un dataframe avec les colonnes A, B et nbr.
- on peut faire simplement df.groupby('A').size() pour avoir la taille de chaque groupe.
- on peut aussi faire ça pour donner un nom à la colonne : df.loc[:,['A', 'B']].groupby(['A', 'B']).agg(size = ('A', len)).reset_index() (on aurait pu aussi mettre B dans la fonction agg, ça revient au même)
- df.groupby('A').mean() : calcule les moyennes pour chaque valeur de A
- fonctions disponibles :
- size() : le nombre dans le groupe
- min(), max()
- mean() : moyenne.
- sum(), prod() : somme, produit
- var(), std() : variance, standard deviation (normalisés par défaut par n - 1)
- median() : médiane.
- quantile(q = 0.2) : quantile
- mad() : median absolute deviate.
- nunique() : nombre de valeurs uniques.
- rank() : rang dans le groupe.
- attention : quand on fait un groupby, par défaut, les valeurs NA sont ignorées :
- df = pandas.DataFrame({'A': ['a', 'a', 'b', numpy.nan], 'B': [1, 2, 3, 4]}); s = df.groupby('A').size() donne la series avec les index ['a', 'b']
- df = pandas.DataFrame({'A': ['a', 'a', 'b', numpy.nan], 'B': [1, 2, 3, 4]}); s = df.groupby('A', dropna = False).size() donne cette fois la series avec les index ['a', 'b', NaN]
- on peut aussi faire des groupby sur les index :
df = pandas.DataFrame({'A': [0, 1, 2], 'B': [3, 4, 5],
'C': [6, 7, 8], 'D': [9, 10, 11]})
df.columns = pandas.MultiIndex(levels = [['a', 'b'], ['A', 'B']],
labels = [[0, 0, 1, 1], [0, 1, 0, 1]])
Ca donne :
a b
A B A B
0 0 3 6 9
1 1 4 7 10
2 2 5 8 11
df.index = ['a', 'a', 'b']; df.groupby(axis = 0, level = 0).sum() donne :
A B C D
a 1 7 13 19
b 2 5 8 11
Fonction agg :
- on peut faire l'aggrégation en donnant soit le le nom de la fonction, soit la fonction elle même :
- df.groupby('A').agg('min') ou df.groupby('A').agg(min)
- df.groupby('A').agg('mean') ou df.groupby('A').agg(numpy.mean)
- df.groupby('A').agg('mad') ou df.groupby('A').agg(pandas.DataFrame.mad)
- on peut faire l'aggrégation avec plusieurs stats : df.groupby('A').agg(['mad', 'mean']) : ça donne un dataframe avec un index colonne hierarchique :
B D
mad mean mad mean
A
a 1.777778 7.666667 1.111111 1.666667
b 2.000000 6.000000 1.500000 2.500000
- calcul de plusieurs stats sur plusieurs variables en même temps :
df.groupby('A').agg(min_B = ('B', min), max_B = ('B', 'max'), median_D = ('D', numpy.median))
donne :
min_B max_B median_D
A
a 5 10 2.0
b 4 8 2.5
et du coup, le simple reset_index() permet d'obtenir un dataframe avec des colonnes non hierarchiques.
- on peut aussi donner une fonction custom : df.groupby('A').agg([numpy.mean, lambda x: 100 * len(x[x > 0]) / len(x)]) : elle recoit une series comme argument.
- quand on a un index colonne hierarchique (multilevel ou multiindex), on peut le mettre à plat de la façon suivante : df.columns = ['_'.join(x) for x in df.columns.values]. Cela donne alors :
B_mad B_mean D_mad D_mean
A
a 1.777778 7.666667 1.111111 1.666667
b 2.000000 6.000000 1.500000 2.500000
- pour accéder aux différents niveaux du multiindex : df.columns.get_level_values(0), df.columns.get_level_values(1), ...
- pour simplifier un index hiérarchique à 2 niveaux : df.columns = df.columns.get_level_values(0) + '_' + df.columns.get_level_values(1)
- si on a une colonne sur laquelle on calcule des statistiques, on peut aussi faire : df.groupby('A')['B'].agg({'MAD': 'mad', 'AVG': 'mean'}) :
AVG MAD
A
a 7.666667 1.777778
b 6.000000 2.000000
- S'il n'y a qu'une seule colonne numérique et que les autres servent à l'aggrégation, c'est beaucoup plus simple : df2 = df.loc[:, ['A', 'B', 'C']].groupby(['A', 'C']).agg(['mean', 'std', len]).reset_index(); df2.columns = [x[0] if x[1] == '' else x[1] for x in df2.columns.tolist()]; df2 donne :
A C mean std len
0 a x 8.0 NaN 1
1 a y 7.5 3.535534 2
2 b x 6.0 2.828427 2
Aggrégation selon les valeurs de l'index :
df.groupby(df.index.names).agg(total = ('nbr', sum)) : aggrégation par même valeur de l'index, puis somme de la colonne nbr pour créer une colonne total (on peut aussi faire simplement df.groupby(df.index).agg(sum) pour faire la somme par valeur d'index.
apply : applique une fonction sur chaque groupe. La fonction recoit en argument un dataframe par groupe et renvoie un dataframe, et tous les dataframes sont assemblés par apply pour donner le résultat :
transform : applique une fonction sur chaque groupe et renvoie un dataframe de même dimension que le dataframe original :
transform : très utile pour par exemple calculer le pourcentage de chaque ligne par groupe :
crosstab :
- df = pandas.DataFrame({'A': ['a', 'a', 'b', 'b', 'a'], 'B': ['c', 'c', 'c', 'd', 'c']})
- pandas.crosstab(df['A'], df['B']) : donne les comptes pour chaque valeur de A (en ligne) et B (en colonne), avec 0 si pas de valeur :
c d
a 3 0
b 1 1
- pandas.crosstab(df['A'], df['B'], normalize = 'all') : normalise au total pour que la somme de toute la matrice fasse 1.
- df2 = pandas.crosstab(df['A'], df['B'], normalize = 'index') : normalise pour que la somme des lignes fasse 1 (idem avec normalize = 'columns' pour les colonnes.
Copyright python-simple.com
programmer en python, tutoriel python, graphes en python, Aymeric Duclert