Disculpas si me han preguntado algo similar antes, busqué pero no pude encontrar una solución.
Mi conjunto de datos se parece a eso
data1 = {'Group':['Winner','Winner','Winner','Loser','Loser','Loser'],
'MathStudy': ['Read','Read','Notes','Cheat','Cheat','Read'],
'ScienceStudy': ['Notes','Read','Cheat','Cheat','Read','Notes']}
df1 = pd.DataFrame(data=data1)
Me gustaría obtener un% del total de cada categoría para cada grupo, como se muestra a continuación. En mi conjunto de datos, la cantidad de ganadores y perdedores cambia, por lo que se agradece una solución flexible.
¡Gracias de antemano!
3 respuestas
Utilice DataFrame.melt
con crosstab
y { Parámetro {X2}}:
df1 = df1.melt('Group', var_name='Type')
df2 = pd.crosstab([df1['Group'], df1['Type']], df1['value'], normalize=0)
print (df2)
value Cheat Notes Read
Group Type
Loser MathStudy 0.666667 0.000000 0.333333
ScienceStudy 0.333333 0.333333 0.333333
Winner MathStudy 0.000000 0.333333 0.666667
ScienceStudy 0.333333 0.333333 0.333333
Por último, si es necesario MultiIndex
a las columnas con eliminar value
nombre de la columna, agregue DataFrame.rename_axis
con DataFrame.reset_index
:
df2 = df2.rename_axis(columns=None).reset_index()
print (df2)
Group Type Cheat Notes Read
0 Loser MathStudy 0.666667 0.000000 0.333333
1 Loser ScienceStudy 0.333333 0.333333 0.333333
2 Winner MathStudy 0.000000 0.333333 0.666667
3 Winner ScienceStudy 0.333333 0.333333 0.333333
La solución de @jezrael es intuitiva y lo que haría yo de primera mano. Sin embargo, aprendí recientemente que melt
generalmente tiene un desempeño deficiente. Aquí hay una alternativa si el rendimiento es importante, p. Ej. en códigos que se utilizan repetidamente:
g = df1.groupby('Group')
cols = ['MathStudy', 'ScienceStudy']
out = (pd.concat({col:g[col].value_counts(normalize=True) for col in cols})
.unstack(level=-1, fill_value=0)
)
Con tiempo de ejecución:
2.9 ms ± 96.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
En comparación con el enfoque melt
:
9.44 ms ± 261 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Salida:
Cheat Notes Read
MathStudy Loser 0.666667 0.000000 0.333333
Winner 0.000000 0.333333 0.666667
ScienceStudy Loser 0.333333 0.333333 0.333333
Winner 0.333333 0.333333 0.333333
Nota : pd.crosstab
es esencialmente groupby()
con algo de contabilidad adicional. Y groupby
en dos columnas suele ser mucho más lento.
Aquí hay otra alternativa:
g = df.set_index('Group').stack().str.get_dummies().groupby(level=[0,1]).sum()
g.div(g.sum(axis=1),axis=0).round(2)
Preguntas relacionadas
Nuevas preguntas
python
Python es un lenguaje de programación multipropósito, de tipificación dinámica y de múltiples paradigmas. Está diseñado para ser rápido de aprender, comprender y usar, y hacer cumplir una sintaxis limpia y uniforme. Tenga en cuenta que Python 2 está oficialmente fuera de soporte a partir del 01-01-2020. Aún así, para preguntas de Python específicas de la versión, agregue la etiqueta [python-2.7] o [python-3.x]. Cuando utilice una variante de Python (por ejemplo, Jython, PyPy) o una biblioteca (por ejemplo, Pandas y NumPy), inclúyala en las etiquetas.