¿Cómo reemplazar NaNs por valores anteriores en el marco de datos de pandas?

140

Supongamos que tengo un DataFrame con algunos NaNs:

>>> 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 necesito hacer es reemplazar cada uno NaNcon el primer no NaNvalor en la misma columna sobre él. Se supone que la primera fila nunca contendrá a NaN. Entonces, para el ejemplo anterior, el resultado sería

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

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

zegkljan
fuente

Respuestas:

213

Puede usar el fillnamétodo en el DataFrame y especificar el método como ffill(relleno hacia adelante):

>>> 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 sentido contrario, también hay un bfillmétodo.

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

df.fillna(method='ffill', inplace=True)
Alex Riley
fuente
31

La respuesta aceptada es perfecta. Tuve una situación relacionada pero ligeramente diferente en la que tuve que completar 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
ErnestScribbler
fuente
exactamente lo que estaba buscando, ty
Tony
18

Puedes usar pandas.DataFrame.fillnacon la method='ffill'opción. '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.

Ffisegydd
fuente
14

Una cosa que noté al probar esta solución es que si tiene N / A al comienzo 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
jjs
fuente
Brillante. Necesitaba exactamente esto para mi problema. Relleno tanto antes como después. Muchas gracias.
Prometeo
Excelente. Necesito esta solucion Gracias
Junkrat
5

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
piRSquared
fuente
5

Solo 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)
SpiralDev
fuente
5

Simplemente estoy de acuerdo con el ffillmétodo, pero una información adicional es que puede limitar el relleno hacia adelante con el argumento de la palabra clave limit.

>>> 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
1  NaN  NaN   6
2  NaN  NaN   9

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

Ahora con limitargumento de palabra clave

>>> 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
Suvo
fuente
1

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 debemos completar.

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
Hodza
fuente
0

Puede usar fillnapara eliminar o reemplazar valores de NaN.

NaN Eliminar

import pandas as pd

df = pd.DataFrame([[1, 2, 3], [4, None, None], [None, None, 9]])

df.fillna(method='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

NaN Reemplazar

df.fillna(0) # 0 means What Value you want to replace 
     0    1    2
0  1.0  2.0  3.0
1  4.0  0.0  0.0
2  0.0  0.0  9.0

Referencia pandas.DataFrame.fillna

MD Jewele Islam
fuente