Python Pandas: Asignar el último valor del grupo DataFrame a todas las entradas de ese grupo

En Python Pandas, tengo un DataFrame. Agrupo este DataFrame por una columna y quiero asignar el último valor de una columna a todas las filas de otra columna.

Sé que puedo seleccionar la última fila del grupo con este comando:

import pandas as pd df = pd.DataFrame({'a': (1,1,2,3,3), 'b':(20,21,30,40,41)}) print(df) print("-") result = df.groupby('a').nth(-1) print(result) 

Resultado:

  ab 0 1 20 1 1 21 2 2 30 3 3 40 4 3 41 - b a 1 21 2 30 3 41 

¿Cómo sería posible volver a asignar el resultado de esta operación al dataframe original para que tenga algo como:

  ab b_new 0 1 20 21 1 1 21 21 2 2 30 30 3 3 40 41 4 3 41 41 

Utilice transform con el last :

 df['b_new'] = df.groupby('a')['b'].transform('last') 

Alternativa:

 df['b_new'] = df.groupby('a')['b'].transform(lambda x: x.iat[-1]) print(df) ab b_new 0 1 20 21 1 1 21 21 2 2 30 30 3 3 40 41 4 3 41 41 

Solución con nth y join :

 df = df.join(df.groupby('a')['b'].nth(-1).rename('b_new'), 'a') print(df) ab b_new 0 1 20 21 1 1 21 21 2 2 30 30 3 3 40 41 4 3 41 41 

Tiempos :

 N = 10000 df = pd.DataFrame({'a':np.random.randint(1000,size=N), 'b':np.random.randint(10000,size=N)}) #print (df) def f(df): return df.join(df.groupby('a')['b'].nth(-1).rename('b_new'), 'a') #cᴏʟᴅsᴘᴇᴇᴅ1 In [211]: %timeit df['b_new'] = df.a.map(df.groupby('a').b.nth(-1)) 100 loops, best of 3: 3.57 ms per loop #cᴏʟᴅsᴘᴇᴇᴅ2 In [212]: %timeit df['b_new'] = df.a.replace(df.groupby('a').b.nth(-1)) 10 loops, best of 3: 71.3 ms per loop #jezrael1 In [213]: %timeit df['b_new'] = df.groupby('a')['b'].transform('last') 1000 loops, best of 3: 1.82 ms per loop #jezrael2 In [214]: %timeit df['b_new'] = df.groupby('a')['b'].transform(lambda x: x.iat[-1]) 10 loops, best of 3: 178 ms per loop #jezrael3 In [219]: %timeit f(df) 100 loops, best of 3: 3.63 ms per loop 

Advertencia

Los resultados no abordan el rendimiento dado el número de grupos, lo que afectará mucho los tiempos de algunas de estas soluciones.

Dos posibilidades, con groupby + nth + map o replace

 df['b_new'] = df.a.map(df.groupby('a').b.nth(-1)) 

O,

 df['b_new'] = df.a.replace(df.groupby('a').b.nth(-1)) 

También puede reemplazar nth(-1) con last() (de hecho, hacerlo hace que esto sea un poco más rápido), pero nth le da más flexibilidad sobre qué elemento elegir de cada grupo en b .


 df ab b_new 0 1 20 21 1 1 21 21 2 2 30 30 3 3 40 41 4 3 41 41 

Creo que esto debería ser rápido.

 df.merge(df.drop_duplicates('a',keep='last'),on='a',how='left') Out[797]: a b_x b_y 0 1 20 21 1 1 21 21 2 2 30 30 3 3 40 41 4 3 41 41