Entfernen von Nanowerten aus einem Array

222

Ich möchte herausfinden, wie man Nanowerte aus meinem Array entfernt. Mein Array sieht ungefähr so ​​aus:

x = [1400, 1500, 1600, nan, nan, nan ,1700] #Not in this exact configuration

Wie kann ich die nanWerte entfernen x?

Dax Feliz
quelle
Um klar zu sein, meinen Sie mit "NaNs entfernen", dass nur die Teilmenge der Nicht-Null-Werte herausgefiltert wird . Nicht "Füllen Sie die NaNs mit einem Wert (Null, Konstante, Mittelwert, Median usw.)"
smci

Antworten:

361

Wenn Sie numpy für Ihre Arrays verwenden, können Sie auch verwenden

x = x[numpy.logical_not(numpy.isnan(x))]

Gleichwertig

x = x[~numpy.isnan(x)]

[Danke an chbrown für die zusätzliche Abkürzung]

Erläuterung

Die innere Funktion numpy.isnangibt ein boolesches / logisches Array zurück, das Trueüberall den Wert hat, der xkeine Zahl ist. Da wir das Gegenteil wollen, verwenden wir den Operator logisch-nicht, ~um Trueüberall ein Array mit s zu erhalten, x das eine gültige Zahl ist.

Zuletzt verwenden wir dieses logische Array, um in das ursprüngliche Array zu indizieren und xnur die Nicht-NaN-Werte abzurufen.

jmetz
quelle
31
Oderx = x[numpy.isfinite(x)]
faul1
14
Oder x = x[~numpy.isnan(x)], was der ursprünglichen Antwort von Mutzmatron entspricht, aber kürzer ist. Wenn Sie Ihre Unendlichkeiten behalten möchten, wissen Sie das numpy.isfinite(numpy.inf) == Falsenatürlich, aber ~numpy.isnan(numpy.inf) == True.
Chbrown
8
Für Leute, die dies mit einem ndarray lösen und die Abmessungen beibehalten möchten, verwenden Sie numpy, wobei :np.where(np.isfinite(x), x, 0)
BoltzmannBrain
1
TypeError: Nur ganzzahlige skalare Arrays können in einen skalaren Index konvertiert werden
Towry
1
@towry: Dies geschieht, weil Ihre Eingabe xkein Numpy-Array ist. Wenn Sie die logische Indizierung verwendet werden soll, muss es ein Array sein - zum Beispielx = np.array(x)
jmetz
50
filter(lambda v: v==v, x)

funktioniert sowohl für Listen als auch für Numpy-Arrays, da v! = v nur für NaN ist

udibr
quelle
5
Ein Hack, der jedoch besonders nützlich ist, wenn Sie Nans aus einem Array von Objekten mit gemischten Typen wie Strings und Nans filtern.
Austin Richardson
Sehr saubere Lösung.
Moondra
2
Dies mag klug erscheinen, aber wenn die Logik verdeckt ist und theoretisch andere Objekte (wie benutzerdefinierte Klassen) ebenfalls diese Eigenschaft haben können
Chris_Rands
Auch nützlich, weil es xim Gegensatz zu Lösungen dieses Typs nur einmal angegeben werden muss x[~numpy.isnan(x)]. Dies ist praktisch, wenn dies xdurch einen langen Ausdruck definiert ist und Sie den Code nicht durch Erstellen einer temporären Variablen zum Speichern des Ergebnisses dieses langen Ausdrucks überladen möchten.
Christian O'Reilly
34

Versuche dies:

import math
print [value for value in x if not math.isnan(value)]

Weitere Informationen finden Sie unter Listenverständnisse .

liori
quelle
5
Wenn Sie numpy verwenden, sind sowohl meine Antwort als auch die von @ lazy1 fast eine Größenordnung schneller als das Listenverständnis - die Lösung von lazy1 ist etwas schneller (obwohl technisch auch keine Unendlichkeitswerte zurückgegeben werden).
Jmetz
Vergessen Sie nicht die Klammern :)print ([value for value in x if not math.isnan(value)])
Hypers
Wenn Sie numpy wie die Top-Antwort verwenden, können Sie diese Antwort zum Listenverständnis mit dem npPaket verwenden: Geben Sie Ihre Liste also ohne die nans zurück:[value for value in x if not np.isnan(value)]
yeliabsalohcin
23

Für mich hat die Antwort von @jmetz nicht funktioniert, die Verwendung von pandas isnull () jedoch.

x = x[~pd.isnull(x)]
Daniel Kislyuk
quelle
6

Gehen Sie wie folgt vor:

x = x[~numpy.isnan(x)]

oder

x = x[numpy.logical_not(numpy.isnan(x))]

Ich fand heraus, dass das Zurücksetzen auf dieselbe Variable (x) die tatsächlichen Nanowerte nicht entfernte und eine andere Variable verwenden musste. Wenn Sie eine andere Variable festlegen, werden die Nans entfernt. z.B

y = x[~numpy.isnan(x)]
melissaOu
quelle
Das ist merkwürdig; Laut den Dokumenten befindet sich die Boolesche Array-Indizierung (was dies ist) in der erweiterten Indizierung, die anscheinend "immer eine Kopie der Daten zurückgibt", daher sollten Sie xmit dem neuen Wert überschreiben (dh ohne die NaNs ...). . Können Sie weitere Informationen darüber geben, warum dies passieren könnte?
Jmetz
5

Wie von anderen gezeigt

x[~numpy.isnan(x)]

funktioniert. Es wird jedoch ein Fehler ausgegeben, wenn der numpy dtype kein nativer Datentyp ist, z. B. wenn es sich um ein Objekt handelt. In diesem Fall können Sie Pandas verwenden.

x[~pandas.isna(x)] or x[~pandas.isnull(x)]
koliyat9811
quelle
4

Die akzeptierte Antwort ändert ihre Form für 2D-Arrays. Ich präsentiere hier eine Lösung mit der Pandas dropna () -Funktionalität. Es funktioniert für 1D- und 2D-Arrays. Im 2D-Fall können Sie das Wetter auswählen, um die Zeile oder Spalte mit zu löschen np.nan.

import pandas as pd
import numpy as np

def dropna(arr, *args, **kwarg):
    assert isinstance(arr, np.ndarray)
    dropped=pd.DataFrame(arr).dropna(*args, **kwarg).values
    if arr.ndim==1:
        dropped=dropped.flatten()
    return dropped

x = np.array([1400, 1500, 1600, np.nan, np.nan, np.nan ,1700])
y = np.array([[1400, 1500, 1600], [np.nan, 0, np.nan] ,[1700,1800,np.nan]] )


print('='*20+' 1D Case: ' +'='*20+'\nInput:\n',x,sep='')
print('\ndropna:\n',dropna(x),sep='')

print('\n\n'+'='*20+' 2D Case: ' +'='*20+'\nInput:\n',y,sep='')
print('\ndropna (rows):\n',dropna(y),sep='')
print('\ndropna (columns):\n',dropna(y,axis=1),sep='')

print('\n\n'+'='*20+' x[np.logical_not(np.isnan(x))] for 2D: ' +'='*20+'\nInput:\n',y,sep='')
print('\ndropna:\n',x[np.logical_not(np.isnan(x))],sep='')

Ergebnis:

==================== 1D Case: ====================
Input:
[1400. 1500. 1600.   nan   nan   nan 1700.]

dropna:
[1400. 1500. 1600. 1700.]


==================== 2D Case: ====================
Input:
[[1400. 1500. 1600.]
 [  nan    0.   nan]
 [1700. 1800.   nan]]

dropna (rows):
[[1400. 1500. 1600.]]

dropna (columns):
[[1500.]
 [   0.]
 [1800.]]


==================== x[np.logical_not(np.isnan(x))] for 2D: ====================
Input:
[[1400. 1500. 1600.]
 [  nan    0.   nan]
 [1700. 1800.   nan]]

dropna:
[1400. 1500. 1600. 1700.]
Markus Dutschke
quelle
3

Wenn Sie verwenden numpy

# first get the indices where the values are finite
ii = np.isfinite(x)

# second get the values
x = x[ii]
Aloha
quelle
0

Dies ist mein Ansatz, um ndarray "X" nach NaNs und infs zu filtern.

Ich erstelle eine Karte von Zeilen ohne NaNund ohne infwie folgt:

idx = np.where((np.isnan(X)==False) & (np.isinf(X)==False))

idx ist ein Tupel. Die zweite Spalte ( idx[1]) enthält die Indizes des Arrays, in denen weder NaN noch inf in der Zeile gefunden wurden.

Dann:

filtered_X = X[idx[1]]

filtered_Xenthält X ohne NaN noch inf.

Aerijman
quelle
0

@ jmetz 'Antwort ist wahrscheinlich die, die die meisten Leute brauchen; Es ergibt sich jedoch ein eindimensionales Array, das es beispielsweise unbrauchbar macht, ganze Zeilen oder Spalten in Matrizen zu entfernen.

Dazu sollte man das logische Array auf eine Dimension reduzieren und dann das Zielarray indizieren. Im Folgenden werden beispielsweise Zeilen entfernt, die mindestens einen NaN-Wert haben:

x = x[~numpy.isnan(x).any(axis=1)]

Weitere Details finden Sie hier .

M4urice
quelle