2015-01-12 39 views
36

Supponiamo che io ho una dataframe con alcuni NaN s:Come sostituire i NaN con i valori precedenti in DataFrame panda?

>>> 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 

Che cosa devo fare è sostituire ogni NaN con il primo valore di NaN non nella stessa colonna sopra di esso. Si presume che la prima riga non contenga mai un NaN. Quindi per l'esempio precedente, il risultato sarebbe

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

posso solo scorrere l'intero dataframe colonna per colonna, elemento per elemento e impostare i valori direttamente, ma c'è un facile (in modo ottimale un loop -free) modo di raggiungere questo?

risposta

59

Si potrebbe utilizzare il metodo fillna sulla dataframe e specificare il metodo ffill (avanti compilare):

>>> 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 

Questo metodo ...

propagano [s] ultima osservazione valida in avanti alla successiva valida

per andare nella direzione opposta, c'è anche un metodo bfill.

Questo metodo non modifica l'inplace dataframe - è necessario associare nuovamente il dataframe restituito ad una variabile oppure specificare inplace=True:

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

È possibile utilizzare pandas.DataFrame.fillna con l'opzione method='ffill'. 'ffill' sta per 'forward fill' e proporrà l'ultima osservazione valida in avanti. L'alternativa è 'bfill' che funziona allo stesso modo, ma all'indietro.

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 

C'è anche una funzione sinonimo d'acquisto per questo, pandas.DataFrame.ffill, per rendere le cose più semplici.

2

Una cosa che ho notato provando questa soluzione è che se hai N/A all'inizio o alla fine dell'array, ffill e bfill non funzionano. Hai bisogno di entrambi.

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 
4

La risposta accettata è perfetto. Avevo una situazione correlata, ma leggermente diversa, in cui dovevo compilare in avanti, ma solo all'interno dei gruppi. Nel caso qualcuno abbia lo stesso bisogno, sappi che fillna lavora su un oggetto 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 
+0

esattamente quello che stavo cercando, ty – Tony

Problemi correlati