Estoy tratando de obtener el resultado superior 'n' usando 'más grande' pero, en mi opinión, el comportamiento es extraño. Sería genial si alguien me puede ayudar a entender por qué el comportamiento es así.
filter = pd.DataFrame([['user1','item2',2,1], ['user1','item1',2,0.666667], ['user1','item3',2,0.500000]], columns=['user_id','item_id','num_transactions','RCP']) sort_RCP_df = ( filter.set_index("item_id") .groupby(["user_id"])["RCP"] .nlargest(2) .reset_index() ) print(sort_RCP_df) user_id item_id RCP user1 item2 1.000000 user1 item1 0.666667
Si mantengo nlargest (2), obtengo el resultado correcto, pero si cambio el valor a 3, solo obtengo las columnas item_id y RCP.
filter = pd.DataFrame([['user1','item2',2,1], ['user1','item1',2,0.666667], ['user1','item3',2,0.500000]], columns=['user_id','item_id','num_transactions','RCP']) sort_RCP_df = ( filter.set_index("item_id") .groupby(["user_id"])["RCP"] .nlargest(3) .reset_index() ) print(sort_RCP_df) item_id RCP item2 1.000000 item1 0.666667 item3 0.500000
¿Por qué la columna 'user_id' no aparece con nlargest = 3?
Y si este es el comportamiento esperado, ¿hay alguna manera de hacer que 'user_id' también forme parte de la salida?
Los documentos insinúan la causa del problema porque en las Notas mencionan explícitamente una consideración de rendimiento:
Más rápido que
.sort_values(ascending=False).head(n)
para n pequeño en relación con el tamaño del objeto Serie.
Si observa en profundidad el código, Series.nlargest
/ Series.nsmallest
son manejados por la clase SelectNSeries
en pandas/core/algorithms. Esta clase tiene un comportamiento diferente dependiendo de n
relativa a la longitud de la Serie:
# slow method if n >= len(self.obj): ascending = method == "nsmallest" return dropped.sort_values(ascending=ascending).head(n) # fast method arr, new_dtype = _ensure_data(dropped.values) if method == "nlargest": arr = -arr if is_integer_dtype(new_dtype): # GH 21426: ensure reverse ordering at boundaries arr -= 1 ...
La conclusión clave aquí es que cuando n >= length of Series
la llamada no utiliza el algoritmo normal para calcular el valor mayor/menor y, en su lugar, solo lo calcula con sort_values
+ head
. Podemos ver que esto coincide manualmente con su salida si sustituimos su llamada más grande con esta lógica.
sort_RCP_df = ( filter.set_index("item_id") .groupby(["user_id"])["RCP"] .apply(lambda s: s.sort_values(ascending=False).head(2)) .reset_index() ) # user_id item_id RCP #0 user1 item2 1.000000 #1 user1 item1 0.666667