¿Cómo reemplazar los NaN por los valores anteriores en el dataframe de pandas?

Supongamos que tengo un DataFrame con algunos NaN s:

 >>> import pandas as pd >>> df = pd.DataFrame([[1, 2, 3], [4, None, None], [None, None, 9]]) >>> df 0 1 2 0 1 2 3 1 4 NaN NaN 2 NaN NaN 9 

Lo que debo hacer es reemplazar cada NaN con el primer valor que no sea NaN en la misma columna que se encuentra arriba. Se supone que la primera fila nunca contendrá un NaN . Así que para el ejemplo anterior el resultado sería

  0 1 2 0 1 2 3 1 4 2 3 2 4 2 9 

Simplemente puedo recorrer todo el DataFrame columna por columna, elemento por elemento y establecer los valores directamente, pero ¿hay una forma fácil (óptimamente sin bucles) de lograr esto?

Podría usar el método fillna en el DataFrame y especificar el método como ffill (forward forward):

 >>> df = pd.DataFrame([[1, 2, 3], [4, None, None], [None, None, 9]]) >>> df.fillna(method='ffill') 0 1 2 0 1 2 3 1 4 2 3 2 4 2 9 

Este método…

propagar [s] última observación válida hacia adelante a la siguiente válida

Para ir en la dirección opuesta, también hay un método de bfill .

Este método no modifica el dataframe in situ; deberá volver a vincular el dataframe devuelto a una variable o, si no, especificar inplace=True :

 df.fillna(method='ffill', inplace=True) 

La respuesta aceptada es perfecta. Tuve una situación relacionada, pero ligeramente diferente, en la que tuve que rellenar hacia adelante pero solo dentro de los grupos. En caso de que alguien tenga la misma necesidad, sepa que fillna funciona en un objeto DataFrameGroupBy.

 >>> example = pd.DataFrame({'number':[0,1,2,nan,4,nan,6,7,8,9],'name':list('aaabbbcccc')}) >>> example name number 0 a 0.0 1 a 1.0 2 a 2.0 3 b NaN 4 b 4.0 5 b NaN 6 c 6.0 7 c 7.0 8 c 8.0 9 c 9.0 >>> example.groupby('name')['number'].fillna(method='ffill') # fill in row 5 but not row 3 0 0.0 1 1.0 2 2.0 3 NaN 4 4.0 5 4.0 6 6.0 7 7.0 8 8.0 9 9.0 Name: number, dtype: float64 

Puede usar pandas.DataFrame.fillna con la opción method='ffill' . 'ffill' significa ‘relleno hacia adelante’ y propagará la última observación válida hacia adelante. La alternativa es 'bfill' que funciona de la misma manera, pero al revés.

 import pandas as pd df = pd.DataFrame([[1, 2, 3], [4, None, None], [None, None, 9]]) df = df.fillna(method='ffill') print(df) # 0 1 2 #0 1 2 3 #1 4 2 3 #2 4 2 9 

También hay una función de sinónimo directo para esto, pandas.DataFrame.ffill , para simplificar las cosas.

Una cosa que noté al probar esta solución es que si tiene N / A al inicio o al final de la matriz, ffill y bfill no funcionan del todo. Necesitas ambos.

 In [224]: df = pd.DataFrame([None, 1, 2, 3, None, 4, 5, 6, None]) In [225]: df.ffill() Out[225]: 0 0 NaN 1 1.0 ... 7 6.0 8 6.0 In [226]: df.bfill() Out[226]: 0 0 1.0 1 1.0 ... 7 6.0 8 NaN In [227]: df.bfill().ffill() Out[227]: 0 0 1.0 1 1.0 ... 7 6.0 8 6.0 

ffill ahora tiene su propio método pd.DataFrame.ffill

 df.ffill() 0 1 2 0 1.0 2.0 3.0 1 4.0 2.0 3.0 2 4.0 2.0 9.0 

Sólo una versión de columna

  • Rellene NAN con el último valor válido
 df[column_name].fillna(method='ffill', inplace=True) 
  • Rellene NAN con el siguiente valor válido
 df[column_name].fillna(method='backfill', inplace=True) 

Solo ffill acuerdo con el método ffill , pero una información adicional es que puede limitar el relleno hacia adelante con el limit argumento de palabra clave.

 >>> import pandas as pd >>> df = pd.DataFrame([[1, 2, 3], [None, None, 6], [None, None, 9]]) >>> df 0 1 2 0 1.0 2.0 3.0 1 NaN NaN 6.0 2 NaN NaN 9.0 >>> df[1].fillna(method='ffill', inplace=True) >>> df 0 1 2 0 1.0 2.0 3.0 1 NaN 2.0 NaN 2 NaN 2.0 9.0 

Ahora con el argumento de palabras clave limit

 >>> df[0].fillna(method='ffill', limit=1, inplace=True) >>> df 0 1 2 0 1.0 2.0 3 1 1.0 2.0 6 2 NaN 2.0 9 

En mi caso, tenemos series temporales de diferentes dispositivos, pero algunos dispositivos no pudieron enviar ningún valor durante algún período. Por lo tanto, deberíamos crear valores de NA para cada dispositivo y período de tiempo y, después de eso, rellenar.

 df = pd.DataFrame([["device1", 1, 'first val of device1'], ["device2", 2, 'first val of device2'], ["device3", 3, 'first val of device3']]) df.pivot(index=1, columns=0, values=2).fillna(method='ffill').unstack().reset_index(name='value') 

Resultado:

  0 1 value 0 device1 1 first val of device1 1 device1 2 first val of device1 2 device1 3 first val of device1 3 device2 1 None 4 device2 2 first val of device2 5 device2 3 first val of device2 6 device3 1 None 7 device3 2 None 8 device3 3 first val of device3