una tablas tabla graficos graficas documentacion curso crear con and python pandas crosstab

python - tablas - ¿Cómo hacer una tabla cruzada pandas con porcentajes?



python and pandas (5)

Dado un marco de datos con diferentes variables categóricas, ¿cómo devuelvo una tabulación cruzada con porcentajes en lugar de frecuencias?

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

El uso de la opción de márgenes en la tabla de referencias cruzadas para calcular los totales de filas y columnas nos permite estar lo suficientemente cerca como para pensar que debería ser posible usar un agresivo o un grupo, pero mi exiguo cerebro no puede analizarlo.

B A B C A one .33 .33 .33 three .33 .33 .33 two .33 .33 .33


Desde Pandas 0.18.1 en adelante, hay una opción de normalize :

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

Donde se puede normalizar en all , index (filas) o columns .

Más detalles están disponibles en la documentación .


Otra opción es usar div lugar de aplicar:

In [11]: res = pd.crosstab(df.A, df.B)

Dividir por la suma sobre el índice:

In [12]: res.sum(axis=1) Out[12]: A one 12 three 6 two 6 dtype: int64

Similar a lo anterior, necesitas hacer algo con la división de enteros (yo uso 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


Podemos mostrarlo como porcentajes multiplicando por 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

Donde he redondeado por conveniencia.


Si está buscando un porcentaje del total, puede dividir por el len del df en lugar de la suma de la fila:

pd.crosstab(df.A, df.B).apply(lambda r: r/len(df), axis=1)


pd.crosstab(df.A, df.B).apply(lambda r: r/r.sum(), axis=1)

Básicamente, solo tienes la función que hace row/row.sum() , y usas apply con axis=1 para aplicarlo por fila.

(Si haces esto en Python 2, deberías usar la from __future__ import division para asegurarte de que la división siempre devuelva un flotador).