Mantener otras columnas cuando se usa min () con groupby

Estoy usando groupby en un dataframe de pandas para eliminar todas las filas que no tienen el mínimo de una columna específica. Algo como esto:

 df1 = df.groupby("item", as_index=False)["diff"].min() 

Sin embargo, si tengo más de esas dos columnas, las otras columnas se eliminan. ¿Puedo mantener esas columnas usando groupby, o tendré que encontrar una forma diferente de eliminar las filas?

Mis datos parecen:

  item diff otherstuff 0 1 2 1 1 1 1 2 2 1 3 7 3 2 -1 0 4 2 1 3 5 2 4 9 6 2 -6 2 7 3 0 0 8 3 2 9 

y debería terminar como

  item diff otherstuff 0 1 1 2 1 2 -6 2 2 3 0 0 

pero lo que estoy consiguiendo es:

  item diff 0 1 1 1 2 -6 2 3 0 

He estado revisando la documentación y no puedo encontrar nada. Lo intenté:

 df1 = df.groupby(["item", "otherstuff"], as_index=false)["diff"].min() df1 = df.groupby("item", as_index=false)["diff"].min()["otherstuff"] df1 = df.groupby("item", as_index=false)["otherstuff", "diff"].min() 

Pero ninguno de esos trabajos (se dio cuenta con el último de que la syntax está destinada a agregarse después de crear un grupo).

Método # 1: use idxmin() para obtener los índices de los elementos de diff mínimo, y luego seleccione esos:

 >>> df.loc[df.groupby("item")["diff"].idxmin()] item diff otherstuff 1 1 1 2 6 2 -6 2 7 3 0 0 [3 rows x 3 columns] 

Método # 2: ordenar por diff , y luego tomar el primer elemento en cada grupo de item :

 >>> df.sort_values("diff").groupby("item", as_index=False).first() item diff otherstuff 0 1 1 2 1 2 -6 2 2 3 0 0 [3 rows x 3 columns] 

Tenga en cuenta que los índices resultantes son diferentes aunque el contenido de la fila sea el mismo.

Puede usar DataFrame.sort_values con DataFrame.drop_duplicates :

 df = df.sort_values(by='diff').drop_duplicates(subset='item') print (df) item diff otherstuff 6 2 -6 2 7 3 0 0 1 1 1 2 

Si es posible, varios valores mínimos por grupo y desea que todas las filas mínimas utilicen boolean indexing con transform para valores mínimos por grupo:

 print (df) item diff otherstuff 0 1 2 1 1 1 1 2 <-multiple min 2 1 1 7 <-multiple min 3 2 -1 0 4 2 1 3 5 2 4 9 6 2 -6 2 7 3 0 0 8 3 2 9 print (df.groupby("item")["diff"].transform('min')) 0 1 1 1 2 1 3 -6 4 -6 5 -6 6 -6 7 0 8 0 Name: diff, dtype: int64 df = df[df.groupby("item")["diff"].transform('min') == df['diff']] print (df) item diff otherstuff 1 1 1 2 2 1 1 7 6 2 -6 2 7 3 0 0 

La respuesta anterior funcionó muy bien si hay / quieres un minuto. En mi caso, podría haber varios minutos y quería todas las filas iguales a min que .idxmin() no te da. Esto funciono

 def filter_group(dfg, col): return dfg[dfg[col] == dfg[col].min()] df = pd.DataFrame({'g': ['a'] * 6 + ['b'] * 6, 'v1': (list(range(3)) + list(range(3))) * 2, 'v2': range(12)}) df.groupby('g',group_keys=False).apply(lambda x: filter_group(x,'v1')) 

Como nota aparte, .filter () también es relevante para esta pregunta pero no funcionó para mí.

Si sabe que todos sus “artículos” tienen más de un registro que puede ordenar, use duplicated :

 df.sort_values(by='diff').duplicated(subset='item', keep='first')