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.