Как я могу получить поэлементное логическое НЕ Серии Панд?
У меня есть панды 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