Come sostituire NaNs precedendo i valori in Panda DataFrame?


141

Supponiamo che io abbia un DataFrame con alcuni 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

Quello che devo fare è sostituire ognuno NaNcon il primo non NaNvalore nella stessa colonna sopra di esso. Si presume che la prima riga non conterrà mai a 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 semplicemente passare in rassegna l'intero DataFrame colonna per colonna, elemento per elemento e impostare direttamente i valori, ma esiste un modo semplice (ottimamente privo di loop) per raggiungere questo obiettivo?

Risposte:


214

È possibile utilizzare il fillnametodo su DataFrame e specificare il metodo come ffill(riempimento diretto ):

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

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

Per andare nella direzione opposta, c'è anche un bfillmetodo.

Questo metodo non modifica il DataFrame sul posto: dovrai ricollegare il DataFrame restituito a una variabile oppure specificare inplace=True:

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

Che cosa succede se la cella vuota si trova nell'indice dei nomi di colonna (ovvero, un paio di colonne non avevano nomi ma avevano dati. C'è un modo per usare bfill o ffill per riempire la cella dell'indice di colonna vuota con la cella nella riga immediatamente sotto? Ad esempio: df = pd.DataFrame ({'col1': [2, 4, 8], 'col2': [2, 0, 0], '': [10, 2, 1]} , index = ['falcon', 'dog', 'spider' ']) Come potrei usare bfill o ffill per cambiare il nome della terza colonna in 10 (che è il valore della riga immediatamente sotto il nome della terza colonna vuota ? Grazie!
GbG

31

La risposta accettata è perfetta. Ho avuto una situazione correlata ma leggermente diversa in cui ho dovuto compilare in avanti ma solo all'interno dei gruppi. Nel caso in cui qualcuno abbia lo stesso bisogno, sappi che fillna funziona 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

esattamente quello che stavo cercando, ty
Tony,

18

È possibile utilizzare pandas.DataFrame.fillnacon l' method='ffill'opzione. 'ffill'sta per "riempimento in avanti" e propaga in avanti l'ultima osservazione valida. L'alternativa è 'bfill'che funziona allo stesso modo, ma al contrario.

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 diretto per questo pandas.DataFrame.ffill, per rendere le cose più semplici.


14

Una cosa che ho notato quando ho provato questa soluzione è che se si dispone di N / A all'inizio o alla fine dell'array, il riempimento e il riempimento 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

Brillante. Avevo bisogno esattamente di questo per il mio problema. Riempimento sia prima che dopo. Molte grazie.
Prometeo

Grande. Ho bisogno di questa soluzione. Grazie
Junkrat il


5

Solo una versione di colonna

  • Riempi NAN con l' ultimo valore valido
df[column_name].fillna(method='ffill', inplace=True)
  • Riempi NAN con il prossimo valore valido
df[column_name].fillna(method='backfill', inplace=True)

5

Solo d'accordo con il ffillmetodo, ma un'ulteriore informazione è che puoi limitare il riempimento in avanti con l'argomento della parola chiave 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

Ora con limitargomento parola chiave

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

1

Nel mio caso, abbiamo serie temporali di dispositivi diversi ma alcuni dispositivi non sono stati in grado di inviare alcun valore per un certo periodo. Quindi dovremmo creare valori NA per ogni dispositivo e periodo di tempo e successivamente riempire.

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

Risultato:

        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

0

È possibile utilizzare fillnaper rimuovere o sostituire i valori NaN.

NaN Rimuovi

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 Sostituisci

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

Panda di riferimento.DataFrame.fillna

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.