Załóżmy, że mam DataFrame z kilkoma 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
To, co muszę zrobić, to zastąpić każdy NaN
pierwszym nie- NaN
wartoś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?
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
źródło
Możesz użyć
pandas.DataFrame.fillna
zmethod='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.ffill
Dla ułatwienia istnieje również funkcja bezpośredniego synonimu .źródło
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
źródło
ffill
teraz ma swoją własną metodępd.DataFrame.ffill
df.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
źródło
Tylko jedna wersja kolumnowa
df[column_name].fillna(method='ffill', inplace=True)
df[column_name].fillna(method='backfill', inplace=True)
źródło
Zgadzam się tylko z
ffill
metodą, ale jedną dodatkową informacją jest to, że możesz ograniczyć wypełnienie do przodu za pomocą argumentu słowa kluczowegolimit
.>>> 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
limit
argumentem 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
źródło
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
źródło
Możesz użyć
fillna
do 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
źródło