Comment faire un panda tableau croisé avec des pourcentages?
étant donné un cadre de données avec différentes variables catégoriques, comment retourner une tabulation croisée avec des pourcentages au lieu de fréquences?
df = pd.DataFrame({'A' : ['one', 'one', 'two', 'three'] * 6,
'B' : ['A', 'B', 'C'] * 8,
'C' : ['foo', 'foo', 'foo', 'bar', 'bar', 'bar'] * 4,
'D' : np.random.randn(24),
'E' : np.random.randn(24)})
pd.crosstab(df.A,df.B)
B A B C
A
one 4 4 4
three 2 2 2
two 2 2 2
L'utilisation de l'option marges dans crosstab pour calculer les totaux des lignes et des colonnes nous amène assez près pour penser que cela devrait être possible en utilisant un aggfunc ou groupby, mais mon cerveau Maigre ne peut pas réfléchir à travers.
B A B C
A
one .33 .33 .33
three .33 .33 .33
two .33 .33 .33
5 réponses
pd.crosstab(df.A, df.B).apply(lambda r: r/r.sum(), axis=1)
Fondamentalement, vous avez juste la fonction qui fait row/row.sum()
, et que vous utilisez apply
axis=1
pour appliquer en ligne.
(Si cela en Python 2, vous devez utiliser from __future__ import division
pour s'assurer que la division renvoie toujours un char.)
à partir de Pandas 0.18.1, il y a un normalize
option:
In [1]: pd.crosstab(df.A,df.B, normalize='index')
Out[1]:
B A B C
A
one 0.333333 0.333333 0.333333
three 0.333333 0.333333 0.333333
two 0.333333 0.333333 0.333333
Où vous pouvez normaliser sur all
, index
(lignes), ou columns
.
Plus de détails sont disponibles dans la documentation.
si vous cherchez un pourcentage du total, vous pouvez diviser par le len du df au lieu de la somme de la ligne:
pd.crosstab(df.A, df.B).apply(lambda r: r/len(df), axis=1)
une Autre option est d'utiliser div plutôt que de l'appliquer:
In [11]: res = pd.crosstab(df.A, df.B)
Diviser par la somme sur l'index:
In [12]: res.sum(axis=1)
Out[12]:
A
one 12
three 6
two 6
dtype: int64
comme ci-dessus, vous devez faire quelque chose à propos de la division entière (j'utilise astype('float')):
In [13]: res.astype('float').div(res.sum(axis=1), axis=0)
Out[13]:
B A B C
A
one 0.333333 0.333333 0.333333
three 0.333333 0.333333 0.333333
two 0.333333 0.333333 0.333333
on peut le montrer sous forme de pourcentages en multipliant par 100
:
pd.crosstab(df.A,df.B, normalize='index')\
.round(4)*100
B A B C
A
one 33.33 33.33 33.33
three 33.33 33.33 33.33
two 33.33 33.33 33.33