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

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

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

True
True
True
False

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

False
False
False
True

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

7 ответов

Решение

Чтобы инвертировать логическую серию, используйте~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 точен, просто хотел добавить предупреждение, что ваша маска должна быть dtype bool, а не 'object'. Т.е. у твоей маски не могло быть ни одной няньки. Смотрите здесь - даже если ваша маска теперь не содержит наночастиц, она останется типа "объект".

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

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

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

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

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

В поддержку отличных ответов здесь и для удобства в будущем может быть случай, когда вы захотите перевернуть значения истинности в столбцах и оставить другие значения такими же (например, значения nan)

In[1]: series = pd.Series([True, np.nan, False, np.nan])
In[2]: series = series[series.notna()] #remove nan values
 
In[3]: series # without nan                                            
Out[3]: 
0     True
2    False
dtype: object

# Out[4] expected to be inverse of Out[3], pandas applies bitwise complement 
# operator instead as in `lambda x : (-1*x)-1`

In[4]: ~series
Out[4]: 
0    -2
2    -1
dtype: object

в качестве простого невекторизованного решения вы можете просто 1. проверить типы2. обратные буллы

In[1]: series = pd.Series([True, np.nan, False, np.nan])

In[2]: series = series.apply(lambda x : not x if x is bool else x)
Out[2]: 
Out[2]: 
0     True
1      NaN
2    False
3      NaN
dtype: object

Если в вашем ответе есть какой-либо вид<NA> np.nanили что-то подобное, я бы рекомендовал сделать что-то вроде этого:

      inverted_series = (1 - original_series).astype('boolean')

Он поддерживает ваши значения na и успешно инвертирует их.

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

Другие вопросы по тегам