wake-up-neo.net

Wie ersetze ich NaNs durch vorhergehende Werte in Pandas DataFrame?

Angenommen, ich habe einen DataFrame mit einigen 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

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?

64
zegkljan

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)
106
Alex Riley

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

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.

11
Ffisegydd

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

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

Nur eine Spaltenversion

  • NAN mit dem letzten gültigen Wert füllen
df[column_name].fillna(method='ffill', inplace=True)
  • NAN mit nächsten gültigen Wert füllen
df[column_name].fillna(method='backfill', inplace=True)
1
DeveScie

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

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
0
Anton Shelin