python - for - groupby examples
Pandas de Python-filas de filtro después de groupby (3)
Por ejemplo, tengo la siguiente tabla:
index,A,B
0,0,0
1,0,8
2,0,8
3,1,0
4,1,5
Después de agrupar por A
:
0:
index,A,B
0,0,0
1,0,8
2,0,8
1:
index,A,B
3,1,5
4,1,3
Lo que necesito es dejar filas de cada grupo, donde el número en la columna B
es menor que el valor máximo de todas las filas de la columna B
del grupo. Bueno, tengo un problema al traducir y formular este problema al inglés, así que aquí está el ejemplo:
Valor máximo de las filas en la columna B
en el grupo 0
: 8
Así que quiero soltar la fila con el índice 0
y mantener las filas con los índices 1
y 2
Valor máximo de las filas en la columna B
en el grupo 1
: 5
Así que quiero soltar la fila con el índice 4
y mantener la fila con el índice 3
He intentado utilizar la función de filtro de pandas, pero el problema es que está funcionando en todas las filas del grupo a la vez:
data = <example table>
grouped = data.groupby("A")
filtered = grouped.filter(lambda x: x["B"] == x["B"].max())
Entonces, lo que idealmente necesito es algún filtro, que itere a través de todas las filas del grupo.
¡Gracias por la ayuda!
PD: ¿Hay también forma de eliminar solo filas en grupos y no devolver el objeto DataFrame
?
EDITAR: Acabo de aprender una manera mucho más .transform
hacer esto usando el grupo .transform
por método:
def get_max_rows(df):
B_maxes = df.groupby(''A'').B.transform(max)
return df[df.B == B_maxes]
B_maxes
es una serie que se indiza de forma idéntica como el df
original que contiene el valor máximo de B
para cada grupo A
Puede pasar muchas funciones al método de transformación. Creo que una vez que tienen salida, ya sea como un escalar o vector de la misma longitud. Incluso puede pasar algunas cadenas como nombres de funciones comunes como ''median''
. Esto es ligeramente diferente al método de Paul H porque ''A'' no será un índice en el resultado, pero puede establecerlo fácilmente después.
import numpy as np
import pandas as pd
df_lots_groups = pd.DataFrame(np.random.rand(30000, 3), columns = list(''BCD'')
df_lots_groups[''A''] = np.random.choice(range(10000), 30000)
%timeit get_max_rows(df_lots_groups)
100 loops, best of 3: 2.86 ms per loop
%timeit df_lots_groups.groupby(''A'').apply(lambda df: df[ df.B == df.B.max()])
1 loops, best of 3: 5.83 s per loop
EDITAR:
Aquí hay una abstracción que le permite seleccionar filas de grupos usando cualquier operador de comparación válido y cualquier método de groupby válido:
def get_group_rows(df, group_col, condition_col, func=max, comparison=''==''):
g = df.groupby(group_col)[condition_col]
condition_limit = g.transform(func)
df.query(''condition_col {} @condition_limit''.format(comparison))
Entonces, por ejemplo, si quiere que todas las filas estén por encima del valor B mediano en cada grupo A al que llama
get_group_rows(df, ''A'', ''B'', ''median'', ''>'')
Algunos ejemplos:
%timeit get_group_rows(df_lots_small_groups, ''A'', ''B'', ''max'', ''=='')
100 loops, best of 3: 2.84 ms per loop
%timeit get_group_rows(df_lots_small_groups, ''A'', ''B'', ''mean'', ''!='')
100 loops, best of 3: 2.97 ms per loop
Este es el otro ejemplo para: Filtrar las filas con el valor máximo después de la operación groupby utilizando idxmax () y .loc ()
In [465]: import pandas as pd
In [466]: df = pd.DataFrame({
''sp'' : [''MM1'', ''MM1'', ''MM1'', ''MM2'', ''MM2'', ''MM2''],
''mt'' : [''S1'', ''S1'', ''S3'', ''S3'', ''S4'', ''S4''],
''value'' : [3,2,5,8,10,1]
})
In [467]: df
Out[467]:
mt sp value
0 S1 MM1 3
1 S1 MM1 2
2 S3 MM1 5
3 S3 MM2 8
4 S4 MM2 10
5 S4 MM2 1
### Here, idxmax() finds the indices of the rows with max value within groups,
### and .loc() filters the rows using those indices :
In [468]: df.loc[df.groupby(["mt"])["value"].idxmax()]
Out[468]:
mt sp value
0 S1 MM1 3
3 S3 MM2 8
4 S4 MM2 10
Solo necesita usar apply
en el objeto groupby
. Modifiqué tus datos de ejemplo para hacer esto un poco más claro:
import pandas
from io import StringIO
csv = StringIO("""index,A,B
0,1,0.0
1,1,3.0
2,1,6.0
3,2,0.0
4,2,5.0
5,2,7.0""")
df = pandas.read_csv(csv, index_col=''index'')
groups = df.groupby(by=[''A''])
print(groups.apply(lambda g: g[g[''B''] == g[''B''].max()]))
Que impresiones:
A B
A index
1 2 1 6
2 4 2 7