Jak mogę uzyskać elementarne logiczne NOT serii pand?

229

Mam Seriesobiekt pandy zawierający wartości logiczne. Jak mogę uzyskać serię zawierającą logikę NOTkażdej wartości?

Rozważmy na przykład serię zawierającą:

True
True
True
False

Seria, którą chciałbym uzyskać, zawierałaby:

False
False
False
True

Wydaje się, że powinno to być dość proste, ale najwyraźniej zgubiłem moje mojo = (

blz
źródło
1
Ważne jest, aby dane nie zawierały objecttypów odpowiedzi poniżej, aby działały, więc użyj:~ df.astype('bool')
LearnOPhile
W tym poście pisałem o wszystkich operatorach logicznych . Post zawiera także alternatywy.
cs95

Odpowiedzi:

259

Aby odwrócić liczbę logiczną, użyj~s :

In [7]: s = pd.Series([True, True, False, True])

In [8]: ~s
Out[8]: 
0    False
1    False
2     True
3    False
dtype: bool

Korzystanie z Python2.7, NumPy 1.8.0, Pandas 0.13.1:

In [119]: s = pd.Series([True, True, False, True]*10000)

In [10]:  %timeit np.invert(s)
10000 loops, best of 3: 91.8 µs per loop

In [11]: %timeit ~s
10000 loops, best of 3: 73.5 µs per loop

In [12]: %timeit (-s)
10000 loops, best of 3: 73.5 µs per loop

Począwszy od Pand 0.13.0, Serie nie są już podklasami numpy.ndarray; są teraz podklasami pd.NDFrame. Może to mieć coś wspólnego z tym, dlaczego np.invert(s)nie jest już tak szybki jak ~slub -s.

Uwaga: timeitwyniki mogą się różnić w zależności od wielu czynników, w tym wersji sprzętu, kompilatora, systemu operacyjnego, Pythona, NumPy i Pandas.

unutbu
źródło
Zanotowano. Poza tym, że jest znacznie wolniejszy, jaka jest różnica między tyldą a -?
blz
Dziwnie, faktycznie przetestowałem taki, tildejak wspomniano w dokumentacji, ale nie działał on tak samo jak np.invert: S
root
@blz: Przynajmniej na moim komputerze Ubuntu, bieganie NumPy 1.6.2, wydajność np.invert(s), ~sa -swszystkie są takie same.
unutbu
@root: Nie jestem pewien, dlaczego w naszych wynikach czasowych występuje tak duża rozbieżność, ale na pewno może się zdarzyć. Z jakiego systemu operacyjnego i wersji NumPy korzystasz?
unutbu
Także na Ubuntu, ale używając NumPy 1.7.0 ... ( np.bitwise_not(s)działa tak samo jak np.inverse).
root
32

Odpowiedź @ unutbu jest na miejscu, chciałem tylko dodać ostrzeżenie, że twoja maska ​​musi być dtype bool, a nie „obiekt”. To znaczy, twoja maska nigdy nie miała żadnych nan. Zobacz tutaj - nawet jeśli maska ​​jest teraz wolna od nanometrów, pozostanie typem „obiektowym”.

Odwrotna seria „obiektowa” nie wyrzuci błędu, zamiast tego otrzymasz maskę śmieci int, która nie będzie działać zgodnie z oczekiwaniami.

In[1]: df = pd.DataFrame({'A':[True, False, np.nan], 'B':[True, False, True]})
In[2]: df.dropna(inplace=True)
In[3]: df['A']
Out[3]:
0    True
1   False
Name: A, dtype object
In[4]: ~df['A']
Out[4]:
0   -2
0   -1
Name: A, dtype object

Po rozmowie z kolegami na ten temat mam wyjaśnienie: wygląda na to, że pandy wracają do operatora bitowego:

In [1]: ~True
Out[1]: -2

Jak mówi @geher, możesz przekonwertować go na bool za pomocą astype, zanim odwrócisz za pomocą ~

~df['A'].astype(bool)
0    False
1     True
Name: A, dtype: bool
(~df['A']).astype(bool)
0    True
1    True
Name: A, dtype: bool
JSharm
źródło
w twoim przykładzie wyjściową maskę ints można przekonwertować na serię bool, którą chcesz, .astype(bool)np.~df['A'].astype(bool)
geher
To działa, ponieważ astype(bool)dzieje się przed ~ ~df['A'].astype(bool)vs(~df['A']).astype(bool)
JSharm
16

Po prostu daję temu szansę:

In [9]: s = Series([True, True, True, False])

In [10]: s
Out[10]: 
0     True
1     True
2     True
3    False

In [11]: -s
Out[11]: 
0    False
1    False
2    False
3     True
herrfz
źródło
Dosłownie wypróbowałem każdego operatora oprócz -! Będę o tym pamiętać następnym razem.
blz
6

Możesz także użyć numpy.invert:

In [1]: import numpy as np

In [2]: import pandas as pd

In [3]: s = pd.Series([True, True, False, True])

In [4]: np.invert(s)
Out[4]: 
0    False
1    False
2     True
3    False

EDYCJA: Różnica w wydajności pojawia się w Ubuntu 12.04, Python 2.7, NumPy 1.7.0 - nie wydaje się jednak istnieć przy użyciu NumPy 1.6.2:

In [5]: %timeit (-s)
10000 loops, best of 3: 26.8 us per loop

In [6]: %timeit np.invert(s)
100000 loops, best of 3: 7.85 us per loop

In [7]: %timeit ~s
10000 loops, best of 3: 27.3 us per loop
korzeń
źródło
może nie być poprawne na innej platformie. Win 7, python 3.6.3 numpy 1.13.3, pandy 0.20.3, (-s) będą najszybsze, (~ s) jest drugi, a np.invert (s) jest najwolniejszy
gaozhidf
0

NumPy działa wolniej, ponieważ przekazuje dane wejściowe do wartości boolowskich (więc None i 0 stają się False, a wszystko inne staje się True).

import pandas as pd
import numpy as np
s = pd.Series([True, None, False, True])
np.logical_not(s)

daje Ci

0    False
1     True
2     True
3    False
dtype: object

podczas gdy ~ s ulegnie awarii. W większości przypadków tylda byłaby bezpieczniejszym wyborem niż NumPy.

Pandy 0,25, NumPy 1,17

grofte
źródło