¿Cómo fillna por groupby salidas en pandas?

Tengo un dataframe que tiene 4 columnas (A, B, C, D). D tiene algunas entradas de NaN. Quiero llenar los valores de NaN por el valor promedio de D que tiene el mismo valor de A, B, C.

Por ejemplo, si el valor de A, B, C, D son x, y, z y Nan respectivamente, entonces quiero que el valor de NaN sea reemplazado por el promedio de D para las filas donde el valor de A, B, C son x, y, z respectivamente.

df['D'].fillna(df.groupby(['A','B','C'])['D'].transform('mean')) sería más rápido que apply

 In [2400]: df Out[2400]: ABCD 0 1 1 1 1.0 1 1 1 1 NaN 2 1 1 1 3.0 3 3 3 3 5.0 In [2401]: df['D'].fillna(df.groupby(['A','B','C'])['D'].transform('mean')) Out[2401]: 0 1.0 1 2.0 2 3.0 3 5.0 Name: D, dtype: float64 In [2402]: df['D'] = df['D'].fillna(df.groupby(['A','B','C'])['D'].transform('mean')) In [2403]: df Out[2403]: ABCD 0 1 1 1 1.0 1 1 1 1 2.0 2 1 1 1 3.0 3 3 3 3 5.0 

Detalles

 In [2396]: df.shape Out[2396]: (10000, 4) In [2398]: %timeit df['D'].fillna(df.groupby(['A','B','C'])['D'].transform('mean')) 100 loops, best of 3: 3.44 ms per loop In [2397]: %timeit df.groupby(['A','B','C'])['D'].apply(lambda x: x.fillna(x.mean())) 100 loops, best of 3: 5.34 ms per loop 

Creo que necesitas:

 df.D = df.groupby(['A','B','C'])['D'].apply(lambda x: x.fillna(x.mean())) 

Muestra:

 df = pd.DataFrame({'A':[1,1,1,3], 'B':[1,1,1,3], 'C':[1,1,1,3], 'D':[1,np.nan,3,5]}) print (df) ABCD 0 1 1 1 1.0 1 1 1 1 NaN 2 1 1 1 3.0 3 3 3 3 5.0 df.D = df.groupby(['A','B','C'])['D'].apply(lambda x: x.fillna(x.mean())) print (df) ABCD 0 1 1 1 1.0 1 1 1 1 2.0 2 1 1 1 3.0 3 3 3 3 5.0 

Enlace al duplicado de esta pregunta para obtener más información: Pandas Dataframe: Reemplazo de NaN por promedio de fila

Otra forma sugerida de hacerlo que se menciona en el enlace es usar un relleno simple en la transposición: df.T.fillna(df.mean(axis=1)).T