Angenommen, ich habe einen DataFrame mit einigen 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
Was ich tun muss, ist jeden NaN
durch den ersten Nicht-NaN
-Wert in derselben Spalte zu ersetzen. Es wird davon ausgegangen, dass die erste Zeile niemals NaN
enthält. Für das vorige Beispiel wäre das Ergebnis also
0 1 2
0 1 2 3
1 4 2 3
2 4 2 9
Ich kann einfach die gesamte DataFrame-Spalte spaltenweise Element für Element durchlaufen und die Werte direkt festlegen, aber gibt es eine einfache (optimal eine Schleife freie) Möglichkeit, dies zu erreichen?
Sie können die Methode fillna
für den DataFrame verwenden und die Methode als ffill
(Forward Fill) angeben:
>>> 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
Diese Methode...
die letzte gültige Beobachtung vorwärts zur nächsten Gültigkeit verbreiten
Umgekehrt gibt es auch eine bfill
-Methode.
Durch diese Methode wird der DataFrame-Inplace nicht geändert. Sie müssen den zurückgegebenen DataFrame erneut an eine Variable binden oder ansonsten inplace=True
angeben:
df.fillna(method='ffill', inplace=True)
Die akzeptierte Antwort ist perfekt. Ich hatte eine verwandte, aber etwas andere Situation, in der ich mich vorwärts ausfüllen musste, aber nur innerhalb von Gruppen. Falls jemand das gleiche Bedürfnis hat, sollten Sie wissen, dass fillna mit einem DataFrameGroupBy-Objekt arbeitet.
>>> 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
Sie können pandas.DataFrame.fillna
mit der Option method='ffill'
verwenden. 'ffill'
steht für 'forward fill' und gibt die letzte gültige Beobachtung vorwärts weiter. Die Alternative ist 'bfill'
, die auf dieselbe Weise funktioniert, jedoch rückwärts.
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
Es gibt auch eine direkte Synonymfunktion für diese, pandas.DataFrame.ffill
, um die Sache zu vereinfachen.
Eine Sache, die mir beim Versuch dieser Lösung aufgefallen ist: Wenn Sie N/A am Anfang oder am Ende des Arrays haben, funktionieren ffill und bfill nicht ganz. Du brauchst beides.
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
ffill
hat jetzt eine eigene Methode 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
Nur eine Spaltenversion
df[column_name].fillna(method='ffill', inplace=True)
df[column_name].fillna(method='backfill', inplace=True)
Ich stimme nur der ffill
-Methode zu, aber eine zusätzliche Information ist, dass Sie die Weitergabe des Schlüsselwortarguments limit
einschränken können.
>>> 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.0
1 NaN NaN 6.0
2 NaN NaN 9.0
>>> df[1].fillna(method='ffill', inplace=True)
>>> df
0 1 2
0 1.0 2.0 3.0
1 NaN 2.0 NaN
2 NaN 2.0 9.0
Jetzt mit dem Schlüsselwortargument limit
>>> 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
In meinem Fall haben wir Zeitreihen von verschiedenen Geräten, aber einige Geräte konnten während eines bestimmten Zeitraums keinen Wert senden. Wir sollten also NA-Werte für jedes Gerät und jeden Zeitraum erstellen und danach Fillna ausführen.
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')
Ergebnis:
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