2015-11-18 28 views
5

Mam obiekt pandas.DataFrame, który zawiera około 100 kolumn i 200000 wierszy danych. Próbuję przekonwertować go do ramek danych bool gdzie True oznacza, że ​​wartość jest większa niż próg, False oznacza, że ​​jest mniejsza, a wartości NaN są utrzymywane.Zachowanie NaNs z nierównościami ramek danych pandy

Jeśli nie ma wartości NaN, trwa około 60 ms dla mnie do uruchomienia:

df >= threshold 

Ale gdy próbuję radzić sobie z Nans, poniższa metoda działa, ale jest bardzo powolny (20 sek).

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))) 

Czy jest szybszy sposób?

+0

Spróbuj zastąpić 'func' z tej linii:' powrócić x> = próg jeśli x nie ma innego x', może to być szybciej. BTW dlaczego przydzieliłeś dwa 'lambda x'? 'df.apply (func)' zrobi lewy. – DeepSpace

+0

@DeepSpace, które trwały w tym samym czasie – jsignell

Odpowiedz

3

można zrobić:

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

Ale to jest inny od tego, co dostaniesz za pomocą zastosowania metody. Tutaj twoja maska ​​ma zmiennoprzecinkowe dtype zawierające NaN, 0.0 i 1.0. W stosowanym rozwiązaniu otrzymujesz object dtyp z NaN, False i True.

Żadne z nich nie może być używane jako maska, ponieważ możesz nie dostać tego, czego chcesz. IEEE mówi, że każde porównanie NaN musi dawać Fałsz, a metoda stosowania jest domyślnie naruszeniem tego, zwracając NaN!

Najlepszym rozwiązaniem jest osobne śledzenie NaN, a df.isnull() jest dość szybki, gdy zainstalowane jest wąskie gardło.

+0

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

1

Można sprawdzić Koncepcja nieliczby oddzielnie za pomocą tego posta: Python - find integer index of rows with NaN in pandas

df.isnull() 

połączyć wyjście isnull z df >= threshold używając bitowego lub:

df.isnull() | df >= threshold 

Można oczekiwać, że dwie maski do podjęcia bliżej 200 ms do obliczenia i połączenia, ale to powinno być wystarczająco daleko od 20 lat, aby było OK.

+0

Czy masz pomysły na temat ich łączenia? To jest ścieżka, którą myślę, że muszę też zejść. – jsignell

+0

Zaktualizowana odpowiedź. –

+0

To nie działa dla mnie. Wypróbowałem go w pythonie 2.7.1, pandach 0.17.0 (z czego zwykle korzystam) i otrzymałem NotImplementedError, potem wypróbowałem go w pythonie 3.4.3, pandach 0.17.0 i otrzymałem: 'bitwise_or' nie jest obsługiwane dla typu wejścia – jsignell

0

W tej sytuacji używam tablicy wskaźnikowej z wartościami zmiennymi zakodowanymi jako: 0 = False, 1 = True, a NaN = missing. Pandas DataFrame z bool dtype nie może mieć brakujących wartości, a DataFrame z typem object dtrzymującym mieszankę obiektów bool i float w języku Python nie jest wydajne. To prowadzi nas do korzystania z DataFrames z dtypem np.float64. numpy.sign(x - threshold) daje -1 = (x < próg), 0 = (x == próg) i +1 = (x> próg) dla twojego porównania, które może być wystarczająco dobre dla twoich celów, ale jeśli naprawdę potrzebujesz 0/1 kodowania , konwersja może być wykonana na miejscu. Czasy poniżej są na tablicy 200K długości 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

Powinienem wspomnieć, że wszystkie trzy powyższe podejścia dają dane DataFrame y z dtype 'np.float64', a wszystkie zachowują NaN. Drugie podejście daje -1/1 kodowania False/True, a pozostałe dają kodowanie 0/1. 'y = (1 + np.sign (x))/2' również jest konkurencyjny. –

+0

To może nie dać ci tego, czego chcesz, kiedy jest dokładnie równa. 'np.sign (x - próg)' będzie 0, jeśli 'x == próg', więc w końcowym wyniku otrzymasz 0, jeśli x próg. Jeśli równość jest możliwa, możesz użyć 'y = (1 + np.sign (eps + x - threshold))/2', gdzie' eps = np.finfo (np.float64) .eps'. –

Powiązane problemy