unendliche Werte aus Datenrahmen in Pandas löschen?

219

Was ist der schnellste / einfachste Weg, um Nano- und Inf / Inf-Werte aus einem Pandas-DataFrame zu löschen, ohne sie zurückzusetzen mode.use_inf_as_null? Ich möchte in der Lage sein, die Argumente subsetund howvon zu verwenden dropna, außer bei infWerten, die als fehlend gelten, wie:

df.dropna(subset=["col1", "col2"], how="all", with_inf=True)

Ist das möglich? Gibt es eine Möglichkeit zu sagen , dropnaenthalten infin ihrer Definition Werte fehlt?


quelle

Antworten:

416

Der einfachste Weg wäre, zuerst replaceNaN zu infizieren:

df.replace([np.inf, -np.inf], np.nan)

und dann verwenden Sie die dropna:

df.replace([np.inf, -np.inf], np.nan).dropna(subset=["col1", "col2"], how="all")

Beispielsweise:

In [11]: df = pd.DataFrame([1, 2, np.inf, -np.inf])

In [12]: df.replace([np.inf, -np.inf], np.nan)
Out[12]:
    0
0   1
1   2
2 NaN
3 NaN

Die gleiche Methode würde für eine Serie funktionieren.

Andy Hayden
quelle
2
Wie kann man die infWerte gegen eine vordefinierte intwie 0in einer bestimmten Spalte "austauschen" ?
3kstc
4
@ 3kstc verwenden .replace(..., 0). Um nur auf Spalten zu tun, aktualisieren Sie diese Spalten, dhdf[cols] = df[cols].replace(..., 0)
Andy Hayden
3
Vielleicht lohnt es sich anzugeben, dass replacedies nicht an Ort und Stelle funktioniert, sodass eine neue DataFramezurückgegeben wird
Marco
36

Mit Optionskontext ist dies ohne permanente Einstellung möglich use_inf_as_na. Beispielsweise:

with pd.option_context('mode.use_inf_as_na', True):
    df = df.dropna(subset=['col1', 'col2'], how='all')

Natürlich kann es zu behandeln eingestellt wird infals NaNdauerhaft mit

pd.set_option('use_inf_as_na', True)

Für ältere Versionen ersetzen use_inf_as_namit use_inf_as_null.

Ayhan
quelle
6
Dies ist die am besten lesbare Antwort und folglich die beste, obwohl sie in Buchstaben (aber nicht im Geiste) gegen die ursprüngliche Frage verstößt.
Ijoseph
2
Pandas ab (mindestens) 0.24: use_inf_as_nullwaren veraltet und werden in einer zukünftigen Version entfernt. Verwenden Sie use_inf_as_nastattdessen. Antwort hinzufügen / aktualisieren?
Håkon T.
1
Dies ist eine bessere Wahl, um infauf globaler Einstellungsebene als auf operativer Ebene als Nullen zu behandeln . Dies könnte möglicherweise Zeit sparen, wenn die Werte zuerst eingegeben werden.
TaoPR
15

Hier ist eine andere Methode, mit .locder inf in einer Serie durch nan ersetzt wird:

s.loc[(~np.isfinite(s)) & s.notnull()] = np.nan

Als Antwort auf die ursprüngliche Frage:

df = pd.DataFrame(np.ones((3, 3)), columns=list('ABC'))

for i in range(3): 
    df.iat[i, i] = np.inf

df
          A         B         C
0       inf  1.000000  1.000000
1  1.000000       inf  1.000000
2  1.000000  1.000000       inf

df.sum()
A    inf
B    inf
C    inf
dtype: float64

df.apply(lambda s: s[np.isfinite(s)].dropna()).sum()
A    2
B    2
C    2
dtype: float64
Alexander
quelle
11

Verwendung (schnell und einfach):

df = df[np.isfinite(df).all(1)]

Diese Antwort basiert auf der Antwort von DougR in einer anderen Frage. Hier ein Beispielcode:

import pandas as pd
import numpy as np
df=pd.DataFrame([1,2,3,np.nan,4,np.inf,5,-np.inf,6])
print('Input:\n',df,sep='')
df = df[np.isfinite(df).all(1)]
print('\nDropped:\n',df,sep='')

Ergebnis:

Input:
    0
0  1.0000
1  2.0000
2  3.0000
3     NaN
4  4.0000
5     inf
6  5.0000
7    -inf
8  6.0000

Dropped:
     0
0  1.0
1  2.0
2  3.0
4  4.0
6  5.0
8  6.0
Markus Dutschke
quelle
7

Eine weitere Lösung wäre die Verwendung der isinMethode. Verwenden Sie diese Option, um festzustellen, ob jeder Wert unendlich ist oder fehlt, und verketten Sie dann die allMethode, um festzustellen, ob alle Werte in den Zeilen unendlich sind oder fehlen.

Verwenden Sie schließlich die Negation dieses Ergebnisses, um die Zeilen auszuwählen, die nicht alle unendlichen oder fehlenden Werte über die boolesche Indizierung haben.

all_inf_or_nan = df.isin([np.inf, -np.inf, np.nan]).all(axis='columns')
df[~all_inf_or_nan]
Ted Petrou
quelle
7

Die obige Lösung ändert die infs, die sich nicht in den Zielspalten befinden. Um dem abzuhelfen,

lst = [np.inf, -np.inf]
to_replace = {v: lst for v in ['col1', 'col2']}
df.replace(to_replace, np.nan)
has2k1
quelle
3
Python 2.7 und höher Unterstützung diktieren Verständnis:{v: lst for v in cols}
Aryeh Leib Taurog
4

Sie können pd.DataFrame.maskmit verwenden np.isinf. Sie sollten zuerst sicherstellen, dass Ihre Datenrahmenserien alle vom Typ sind float. Verwenden Sie dann dropnamit Ihrer vorhandenen Logik.

print(df)

       col1      col2
0 -0.441406       inf
1 -0.321105      -inf
2 -0.412857  2.223047
3 -0.356610  2.513048

df = df.mask(np.isinf(df))

print(df)

       col1      col2
0 -0.441406       NaN
1 -0.321105       NaN
2 -0.412857  2.223047
3 -0.356610  2.513048
jpp
quelle