Как я могу получить поэлементное логическое НЕ Серии Панд?

229

У меня есть Seriesобъект Pandas, содержащий логические значения. Как я могу получить серию, содержащую логическое NOTкаждого значения?

Например, рассмотрим серию, содержащую:

True
True
True
False

Ряд, который я хотел бы получить, содержал бы:

False
False
False
True

Кажется, это должно быть достаточно просто, но, видимо, я потерял моё умение = (

БИК
источник
1
Важно, чтобы данные не содержали objectтипов для ответов ниже, чтобы работать, поэтому используйте:~ df.astype('bool')
LearnOPhile
Я написал обо всех логических операторах в этом посте . Пост также включает альтернативы.
cs95

Ответы:

260

Чтобы инвертировать логическую серию, используйте~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

Используя 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

Начиная с Pandas 0.13.0, Серии больше не являются подклассами numpy.ndarray; теперь они подклассы pd.NDFrame. Это может иметь какое-то отношение к тому, почему np.invert(s)это не так быстро, как ~sили -s.

Предостережение: timeitрезультаты могут отличаться в зависимости от многих факторов, включая аппаратное обеспечение, компилятор, ОС, Python, NumPy и версии Pandas.

unutbu
источник
Верно подмечено. В чем разница между тильдой и тимидой -?
Blz
Я действительно протестировал, tildeкак было упомянуто в документации, но он не работал так же, как np.invert: S
root,
@blz: По крайней мере , на моей машине Ubuntu, работает NumPy 1.6.2, производительность np.invert(s), ~sи -sвсе же.
unutbu
@root: Я не уверен, почему в наших результатах так много расхождений, но это, безусловно, может произойти. Какую ОС и версию NumPy вы используете?
unutbu
Также в Ubuntu, но с использованием NumPy 1.7.0 ... ( np.bitwise_not(s)работает так же, как np.inverse).
root
32

Ответ @ unutbu точен, просто хотел добавить предупреждение, что ваша маска должна быть dtype bool, а не 'object'. Т.е. у твоей маски не могло быть ни одной няньки. Смотрите здесь - даже если ваша маска теперь не содержит наночастиц, она останется типом «объект».

Инверсия серии 'object' не выдаст ошибку, вместо этого вы получите мусорную маску int, которая не будет работать так, как вы ожидаете.

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

После разговора с коллегами об этом у меня есть объяснение: похоже, панда возвращается к побитовому оператору:

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

Как говорит @geher, вы можете преобразовать его в bool с помощью astype, прежде чем обратное с ~

~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
источник
в вашем примере маску выходных целых можно преобразовать в .astype(bool)~df['A'].astype(bool)
нужную
Это работает, потому что astype(bool)происходит до ~ ~df['A'].astype(bool)VS(~df['A']).astype(bool)
JSharm
16

Я просто дать ему шанс:

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
источник
Я буквально пытался каждый оператор, кроме -! Я буду помнить это в следующий раз.
Blz
6

Вы также можете использовать 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

РЕДАКТИРОВАТЬ: Разница в производительности появляется в Ubuntu 12.04, Python 2.7, NumPy 1.7.0 - кажется, не существует при использовании 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
корень
источник
это может быть неправильно на другой платформе. Win 7, python 3.6.3 numpy 1.13.3, pandas 0.20.3, (-s) будет самым быстрым, (~ s) - вторым, а np.invert (s) - самым медленным
gaozhidf
0

NumPy медленнее, потому что вводит входные данные в логические значения (поэтому None и 0 становятся False, а все остальное становится True).

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

дает тебе

0    False
1     True
2     True
3    False
dtype: object

тогда как ~ s потерпит крах. В большинстве случаев тильда будет более безопасным выбором, чем NumPy.

Панды 0,25, NumPy 1,17

grofte
источник