multiple - python pandas dataframe groupby example
Cambiar el nombre de las columnas de resultados de la agregación de Pandas("FutureWarning: el uso de un dict con cambio de nombre está en desuso") (5)
Actualización para Pandas 0.25+ Reetiquetado de agregación
import pandas as pd print(pd.__version__) #0.25.0 df = pd.DataFrame({"User": ["user1", "user2", "user2", "user3", "user2", "user1"], "Amount": [10.0, 5.0, 8.0, 10.5, 7.5, 8.0]}) df.groupby("User")[''Amount''].agg(Sum=''sum'', Count=''count'')
Salida:
Sum Count User user1 18.0 2 user2 20.5 3 user3 10.5 1
Estoy tratando de hacer algunas agregaciones en un marco de datos de pandas. Aquí hay un código de muestra:
import pandas as pd
df = pd.DataFrame({"User": ["user1", "user2", "user2", "user3", "user2", "user1"],
"Amount": [10.0, 5.0, 8.0, 10.5, 7.5, 8.0]})
df.groupby(["User"]).agg({"Amount": {"Sum": "sum", "Count": "count"}})
Out[1]:
Amount
Sum Count
User
user1 18.0 2
user2 20.5 3
user3 10.5 1
Lo que genera la siguiente advertencia:
FutureWarning: el uso de un dict con cambio de nombre queda obsoleto y se eliminará en una versión futura return super (DataFrameGroupBy, self) .aggregate (arg, * args, ** kwargs)
¿Cómo puedo evitar esto?
Use groupby
apply
y devuelva una serie para cambiar el nombre de las columnas
Use el método groupby
apply
para realizar una agregación que
- Renombra las columnas
- Permite espacios en los nombres
- Le permite ordenar las columnas devueltas de la forma que elija
- Permite interacciones entre columnas
- Devuelve un índice de nivel único y NO un índice múltiple
Para hacer esto:
-
crea una función personalizada que pasas para
apply
- Esta función personalizada se pasa a cada grupo como un DataFrame
- Devolver una serie
- El índice de la Serie serán las nuevas columnas.
Crea datos falsos
df = pd.DataFrame({"User": ["user1", "user2", "user2", "user3", "user2", "user1", "user3"],
"Amount": [10.0, 5.0, 8.0, 10.5, 7.5, 8.0, 9],
''Score'': [9, 1, 8, 7, 7, 6, 9]})
crear una función personalizada que devuelve una serie
La variable
x
dentro de
my_agg
es un DataFrame
def my_agg(x):
names = {
''Amount mean'': x[''Amount''].mean(),
''Amount std'': x[''Amount''].std(),
''Amount range'': x[''Amount''].max() - x[''Amount''].min(),
''Score Max'': x[''Score''].max(),
''Score Sum'': x[''Score''].sum(),
''Amount Score Sum'': (x[''Amount''] * x[''Score'']).sum()}
return pd.Series(names, index=[''Amount range'', ''Amount std'', ''Amount mean'',
''Score Sum'', ''Score Max'', ''Amount Score Sum''])
Pase esta función personalizada al grupo mediante el método de
apply
df.groupby(''User'').apply(my_agg)
El gran inconveniente es que esta función será mucho más lenta que
agg
para las
agregaciones cythonized
Usar un diccionario con el método groupby
agg
El uso de un diccionario de diccionarios fue eliminado debido a su complejidad y naturaleza algo ambigua. Hay una discusión en curso sobre cómo mejorar esta funcionalidad en el futuro en github Aquí, puede acceder directamente a la columna de agregación después de la llamada grupal. Simplemente pase una lista de todas las funciones de agregación que desea aplicar.
df.groupby(''User'')[''Amount''].agg([''sum'', ''count''])
Salida
sum count
User
user1 18.0 2
user2 20.5 3
user3 10.5 1
Todavía es posible usar un diccionario para denotar explícitamente diferentes agregaciones para diferentes columnas, como aquí si hubiera otra columna numérica llamada
Other
.
df = pd.DataFrame({"User": ["user1", "user2", "user2", "user3", "user2", "user1"],
"Amount": [10.0, 5.0, 8.0, 10.5, 7.5, 8.0],
''Other'': [1,2,3,4,5,6]})
df.groupby(''User'').agg({''Amount'' : [''sum'', ''count''], ''Other'':[''max'', ''std'']})
Salida
Amount Other
sum count max std
User
user1 18.0 2 6 3.535534
user2 20.5 3 5 1.527525
user3 10.5 1 4 NaN
Esto es lo que hice:
Crea un conjunto de datos falso:
import pandas as pd
df = pd.DataFrame({"User": ["user1", "user2", "user2", "user3", "user2", "user1", "user3"],
"Amount": [10.0, 5.0, 8.0, 10.5, 7.5, 8.0, 9],
''Score'': [9, 1, 8, 7, 7, 6, 9]})
df
O / P:
Amount Score User
0 10.0 9 user1
1 5.0 1 user2
2 8.0 8 user2
3 10.5 7 user3
4 7.5 7 user2
5 8.0 6 user1
6 9.0 9 user3
Primero hice al Usuario el índice, y luego un grupo por:
ans = df.set_index(''User'').groupby(level=0)[''Amount''].agg([(''Sum'',''sum''),(''Count'',''count'')])
ans
Solución:
Sum Count
User
user1 18.0 2
user2 20.5 3
user3 19.5 2
Reemplace los diccionarios internos con una lista de funciones correctamente nombradas.
Para cambiar el nombre de la función, estoy usando esta función de utilidad:
def aliased_aggr(aggr, name):
if isinstance(aggr,str):
def f(data):
return data.agg(aggr)
else:
def f(data):
return aggr(data)
f.__name__ = name
return f
La declaración de grupo se convierte en:
df.groupby(["User"]).agg({"Amount": [
aliased_aggr("sum","Sum"),
aliased_aggr("count","Count")
]
Si tiene especificaciones de agregación más grandes y reutilizables, puede convertirlas con
def convert_aggr_spec(aggr_spec):
return {
col : [
aliased_aggr(aggr,alias) for alias, aggr in aggr_map.items()
]
for col, aggr_map in aggr_spec.items()
}
Entonces puedes decir
df.groupby(["User"]).agg(convert_aggr_spec({"Amount": {"Sum": "sum", "Count": "count"}}))
Ver también https://github.com/pandas-dev/pandas/issues/18366#issuecomment-476597674
Si reemplaza el diccionario interno con una lista de tuplas, se elimina el mensaje de advertencia
import pandas as pd
df = pd.DataFrame({"User": ["user1", "user2", "user2", "user3", "user2", "user1"],
"Amount": [10.0, 5.0, 8.0, 10.5, 7.5, 8.0]})
df.groupby(["User"]).agg({"Amount": [("Sum", "sum"), ("Count", "count")]})