Jak zamienić NaNs przez poprzedzające wartości w pandas DataFrame?


158

Załóżmy, że mam DataFrame z kilkoma 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

To, co muszę zrobić, to zastąpić każdy NaNpierwszym nie- NaNwartością w tej samej kolumnie powyżej. Zakłada się, że pierwszy wiersz nigdy nie będzie zawierał NaN. Tak więc w poprzednim przykładzie wynik byłby

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

Mogę po prostu zapętlić całą kolumnę DataFrame, element po elemencie i ustawić wartości bezpośrednio, ale czy istnieje łatwy (optymalnie wolny od pętli) sposób osiągnięcia tego?

Odpowiedzi:


237

Możesz użyć fillnametody w DataFrame i określić metodę jako ffill(wypełnienie do przodu):

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

Ta metoda...

propagate [s] ostatnia ważna obserwacja do przodu do następnej ważnej

Aby pójść w drugą stronę, jest też bfillmetoda.

Ta metoda nie modyfikuje elementu DataFrame inplace - musisz ponownie powiązać zwrócony DataFrame ze zmienną lub określić inplace=True:

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

Co by się stało, gdyby pusta komórka znajdowała się w indeksie nazw kolumn (np. Kilka kolumn nie miało nazw, ale zawierało dane. Czy istnieje sposób użycia bfill lub ffill do wypełnienia pustej komórki indeksu kolumny komórką w wiersz bezpośrednio pod nim? Na przykład: df = pd.DataFrame ({'col1': [2, 4, 8], 'col2': [2, 0, 0], '': [10, 2, 1]} , index = ['falcon', 'dog', 'spider' ']) Jak mogę użyć bfill lub ffill, aby zmienić nazwę trzeciej kolumny na 10 (która jest wartością wiersza bezpośrednio pod pustą nazwą trzeciej kolumny Dzięki!
GbG

33

Przyjęta odpowiedź jest idealna. Miałem podobną, ale nieco inną sytuację, w której musiałem wypełnić naprzód, ale tylko w grupach. Jeśli ktoś ma taką samą potrzebę, wiedz, że fillna działa na obiekcie 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

dokładnie to, czego szukałem, ty
Tony,

18

Możesz użyć pandas.DataFrame.fillnaz method='ffill'opcją. 'ffill'oznacza „forward fill” i będzie propagować ostatnią ważną obserwację do przodu. Alternatywą jest to, 'bfill'co działa w ten sam sposób, ale wstecz.

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

pandas.DataFrame.ffillDla ułatwienia istnieje również funkcja bezpośredniego synonimu .


15

Jedną rzeczą, którą zauważyłem podczas wypróbowywania tego rozwiązania, jest to, że jeśli masz N / A na początku lub na końcu tablicy, funkcje ffill i bfill nie działają. Potrzebujesz obu.

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

Znakomity. Potrzebowałem dokładnie tego do mojego problemu. Wypełnienie zarówno przed, jak i po. Wielkie dzięki.
Prometheus

Świetny. Potrzebuję tego rozwiązania. Dzięki
Junkrat


5

Tylko jedna wersja kolumnowa

  • Wypełnij NAN ostatnią prawidłową wartością
df[column_name].fillna(method='ffill', inplace=True)
  • Wypełnij NAN kolejną prawidłową wartością
df[column_name].fillna(method='backfill', inplace=True)

5

Zgadzam się tylko z ffillmetodą, ale jedną dodatkową informacją jest to, że możesz ograniczyć wypełnienie do przodu za pomocą argumentu słowa kluczowego 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

Teraz z limitargumentem słów kluczowych

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

W moim przypadku mamy szeregi czasowe z różnych urządzeń, ale niektóre urządzenia nie mogły wysłać żadnej wartości w pewnym okresie. Powinniśmy więc utworzyć wartości NA dla każdego urządzenia i okresu, a potem zrobić fillna.

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

Wynik:

        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

Możesz użyć fillnado usunięcia lub zastąpienia wartości NaN.

NaN Usuń

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

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

Odniesienia do pand.DataFrame.fillna

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.