2015-11-18 9 views
5

Ich habe ein Pandas.DataFrame-Objekt, das etwa 100 Spalten und 200000 Zeilen von Daten enthält. Ich versuche, es zu einem Bool-Datenrahmen zu konvertieren, wobei True bedeutet, dass der Wert größer als der Schwellenwert ist, False bedeutet, dass es kleiner ist, und NaN-Werte werden beibehalten.Keeping NaNs mit Pandas Dataframe Ungleichungen

Wenn es keine NaN-Werte sind, dauert es etwa 60 ms für mich zu laufen:

df >= threshold 

Aber wenn ich versuche, mit dem NaNs zu behandeln, die unter Methode funktioniert, ist aber sehr langsam (20 sec).

def func(x): 
    if x >= threshold: 
     return True 
    elif x < threshold: 
     return False 
    else: 
     return x 
df.apply(lambda x: x.apply(lambda x: func(x))) 

Gibt es einen schnelleren Weg?

+0

Versuchen Sie, 'func' mit dieser Linie zu ersetzen:' return x> = Schwellenwert, wenn x nicht Keine sonst x' ist, kann es schneller sein. BTW warum hast du zwei 'Lambda x' zugewiesen? 'df.apply (func)' wird den Trick machen. – DeepSpace

+0

@DeepSpace, die die gleiche Zeit in Anspruch nahmen – jsignell

Antwort

3

Sie tun können:

new_df = df >= threshold 
new_df[df.isnull()] = np.NaN 

Aber das ist anders, was Sie die Anwendung Methode erhalten werden. Hier hat Ihre Maske float dtype mit NaN, 0.0 und 1.0. In der Apply-Lösung erhalten Sie object dtype mit NaN, False und True.

Es kann auch nicht als Maske verwendet werden, da Sie möglicherweise nicht bekommen, was Sie wollen. IEEE sagt, dass jeder NaN-Vergleich False ergeben muss und die apply-Methode implizit gegen diese durch Rückgabe von NaN verstößt!

Die beste Option besteht darin, die NaNs separat zu verfolgen und df.isnull() ist ziemlich schnell, wenn der Engpass installiert ist.

+0

https: //pypi.python. org/pypi/Bottleneck –

1

können Sie prüfen, für NaNs separat diesen Beitrag mit: Python - find integer index of rows with NaN in pandas

df.isnull() 

die Ausgabe von isnull mit df >= threshold Kombinieren bitweise mit oder:

df.isnull() | df >= threshold 

Sie können die beiden Masken erwarten nehmen näher 200ms zu berechnen und zu kombinieren, aber das sollte weit genug weg von 20s sein, um in Ordnung zu sein.

+0

Haben Sie Ideen, wie Sie diese kombinieren können? Das ist der Weg, den ich denke, ich muss auch gehen. – jsignell

+0

Aktualisierte Antwort. –

+0

Das hat nicht für mich funktioniert. Ich habe es in Python 2.7.1, Pandas 0.17.0 versucht (was ich normalerweise verwende) und einen NotImplementedError bekommen, dann habe ich es in Python 3.4.3, Pandas 0.17.0 versucht und habe: 'bitwise_or' für den Eingabetyp nicht unterstützt – jsignell

0

In dieser Situation verwende ich eine Indikator-Array von Schwimmern, codiert als: 0 = False, 1 = True, und NaN = fehlt. Ein Pandas DataFrame mit bool dtype kann keine fehlenden Werte haben, und ein DataFrame mit object dtype, der eine Mischung aus Python bool- und float-Objekten enthält, ist nicht effizient. Dies führt uns zu DataFrames mit np.float64 dtype. numpy.sign(x - threshold) gibt -1 = (x < Schwelle), 0 = (x == Schwelle) und +1 = (x> Schwelle) für Ihren Vergleich, der für Ihre Zwecke gut genug sein könnte, aber wenn Sie wirklich 0/1 Codierung benötigen Die Konvertierung kann vor Ort vorgenommen werden. Timings unten sind auf einem 200K Länge Array x:

In [45]: %timeit y = (x > 0); y[pd.isnull(x)] = np.nan 
100 loops, best of 3: 8.71 ms per loop 

In [46]: %timeit y = np.sign(x) 
100 loops, best of 3: 1.82 ms per loop 

In [47]: %timeit y = np.sign(x); y += 1; y /= 2 
100 loops, best of 3: 3.78 ms per loop 
+0

Ich hätte erwähnen sollen, dass alle drei obigen Ansätze Ihnen einen DataFrame y mit dtype 'np.float64' geben und alle NaNs beibehalten. Der zweite Ansatz gibt -1/1 für False/True und die anderen 0/1 Codierung. "y = (1 + np.sign (x))/2" ist ebenfalls kompetitiv. –

+0

Dies kann nicht geben, was Sie wollen, wenn es genaue Gleichheit gibt. 'np.sign (x - threshold)' ist 0, wenn 'x == threshold', also erhalten Sie im Endergebnis 0, wenn x threshold. Wenn Gleichheit eine Möglichkeit ist, könnten Sie mit y = (1 + np.Sign (eps + x - Schwelle))/2 'gehen, wobei "eps = np.finfo (np.float64) .eps". –