python - Agregado de pandas con nombres de columna dinámicos
aggregate pandas-groupby (5)
Desafortunadamente, tendrá que aplicar ambas funciones de agregación por separado (eso o repetir
"valn": "mean"
tantas veces como columnas
valx
).
Groupby.agg
puede tomar un diccionario pero las claves deben ser columnas individuales.
La forma en que haría esto es usar
DataFrame.filter
para seleccionar el subconjunto del marco de datos con las columnas siguiendo el formato de
valx
, agregar con la media y luego asignar nuevas columnas con los resultados agregados en las otras columnas:
(df.filter(regex=r''^val'').groupby(df.group).mean()
.assign(color = df.group_color.groupby(df.group).first()))
val1 val2 color
group
A 3.333333 4.666667 green
B 4.500000 6.000000 blue
Tengo un script que genera un marco de datos de pandas con un número variable de columnas de valor. Como ejemplo, este df podría ser
import pandas as pd
df = pd.DataFrame({
''group'': [''A'', ''A'', ''A'', ''B'', ''B''],
''group_color'' : [''green'', ''green'', ''green'', ''blue'', ''blue''],
''val1'': [5, 2, 3, 4, 5],
''val2'' : [4, 2, 8, 5, 7]
})
group group_color val1 val2
0 A green 5 4
1 A green 2 2
2 A green 3 8
3 B blue 4 5
4 B blue 5 7
Mi objetivo es obtener la media agrupada para cada una de las columnas de valor. En este caso específico (con 2 columnas de valor), puedo usar
df.groupby(''group'').agg({"group_color": "first", "val1": "mean", "val2": "mean"})
group_color val1 val2
group
A green 3.333333 4.666667
B blue 4.500000 6.000000
pero eso no funciona cuando el marco de datos en cuestión tiene más columnas de valor (val3, val4, etc.). ¿Hay alguna manera de tomar dinámicamente la media de "todas las otras columnas" o "todas las columnas que contienen val en sus nombres"?
Más fácil como
df.groupby(''group'').agg(lambda x : x.head(1) if x.dtype==''object'' else x.mean())
Out[63]:
group_color val1 val2
group
A green 3.333333 4.666667
B blue 4.500000 6.000000
Por comentario de OP
Podemos agrupar por
''group''
y
''group_color''
sin el riesgo de que haya más de un único
''group_color''
por
''group''
Por consiguiente:
df.groupby([''group'', ''group_color'']).mean().reset_index(level=1)
group_color val1 val2
group
A green 3.333333 4.666667
B blue 4.500000 6.000000
Puedes ir con 2 diccionarios que puedes combinar así:
df.groupby(''group'').agg({**{''group_color'': ''first''}, **{c: ''mean'' for c in df.columns if c.startswith(''val'')}})
En este caso, tiene un
dict
con agregaciones fijas y otro con selección de columna dinámica.
Si su
group_color
es siempre el mismo dentro de un grupo, puede hacer:
df.pivot_table(index=[''group'',''group_color''],aggfunc=''mean'')
Salida:
val1 val2
group group_color
A green 3.333333 4.666667
B blue 4.500000 6.000000
En el otro caso, puede construir el diccionario y pasarlo a
agg
:
agg_dict = {f: ''first'' if f==''group_color'' else ''mean'' for f in df.columns[1:]}
df.groupby(''group'').agg(agg_dict)
Qué salida:
group_color val1 val2
group
A green 3.333333 4.666667
B blue 4.500000 6.000000