¿Cómo reemplazar NaN por valores anteriores o siguientes en pandas DataFrame?
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 NaN
valor que no sea en la misma columna encima. Se supone que la primera fila nunca contendrá un archivo 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
Puedo recorrer todo el DataFrame columna por columna, elemento por elemento y establecer los valores directamente, pero ¿existe una manera fácil (óptimamente sin bucles) de lograr esto?
Puede usar el fillna
método en el DataFrame y especificar el método como ffill
(relleno directo):
>>> 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 la última observación válida hacia la siguiente válida
Para ir en sentido contrario, también existe un bfill
mé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)
La respuesta aceptada es perfecta. Tuve una situación relacionada pero ligeramente diferente en la que tenía que ocupar el puesto de avance pero sólo 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
Una cosa que noté al probar esta solución es que si tiene N/A al principio o al final de la matriz, fill 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
Puedes usar pandas.DataFrame.fillna
con la method='ffill'
opción. 'ffill'
significa 'relleno directo' 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.
Versión de una sola columna
- Complete NAN con el último valor válido
df[column_name].fillna(method='ffill', inplace=True)
- Complete NAN con el siguiente valor válido
df[column_name].fillna(method='backfill', inplace=True)