Значение истины серии неоднозначно. Используйте команды a.empty, a.bool(), a.item(), a.any() или a.all()
Возникла проблема фильтрации моего результирующего фрейма с условием or
. Я хочу, чтобы мой результат df
извлекал все значения столбца _var_
, которые выше 0,25 и ниже -0.25. Эта логика ниже дает мне двусмысленное значение истины, однако оно работает, когда я разделяю эту фильтрацию в двух отдельных операциях. Что здесь происходит? не знаете, где использовать предлагаемые функции a.empty(), a.bool(), a.item(),a.any() or a.all()
.
result = result[(result['var']>0.25) or (result['var']<-0.25)]
Ответы
Ответ 1
Операторы python or
и and
требуют truth
-значений. Для pandas
они считаются неоднозначными, поэтому вы должны использовать "поразрядные" операции |
(или) или &
(и):
result = result[(result['var']>0.25) | (result['var']<-0.25)]
Они перегружены для этих типов данных, чтобы получить элемент-мудрый or
(или and
).
Чтобы добавить еще одно объяснение к этому утверждению:
Исключение генерируется, если вы хотите получить bool
pandas.Series
:
>>> import pandas as pd
>>> x = pd.Series([1])
>>> bool(x)
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
То, что вы нажали, было местом, где оператор неявно преобразовал операнды в bool
(вы использовали or
, но это также происходит для and
, if
и while
)
>>> x or x
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
>>> x and x
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
>>> if x:
... print('fun')
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
>>> while x:
... print('fun')
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
Помимо этих 4-х операторов существует несколько функций-питонов, которые скрывают некоторые вызовы bool
(например, any
, all
, filter
,...), как правило, это не проблема с pandas.Series
, а для полноты я хотел упомянуть их.
В вашем случае исключение не очень полезно, поскольку оно не упоминает альтернативные права. Для and
и or
вы можете использовать (если вы хотите сравнить по элементам):
Если вы используете операторы, убедитесь, что вы правильно установили свою скобку из-за приоритета оператора.
Есть несколько логических функций numpy, которые должны работать на pandas.Series
.
Альтернативы, упомянутые в Exception, более подходят, если вы столкнулись с этим при выполнении if
или while
. Вкратце объясню каждый из них:
-
Если вы хотите проверить, является ли ваша серия пустой:
>>> x = pd.Series([])
>>> x.empty
True
>>> x = pd.Series([1])
>>> x.empty
False
Python обычно интерпретирует len
gth контейнеров (например, list
, tuple
,...) как значение истинности, если он не имеет явной булевой интерпретации. Поэтому, если вы хотите выполнить проверку типа python, вы можете сделать: if x.size
или if not x.empty
вместо if x
.
-
Если ваш Series
содержит одно и только одно логическое значение:
>>> x = pd.Series([100])
>>> (x > 50).bool()
True
>>> (x < 50).bool()
False
-
Если вы хотите проверить первый и единственный элемент вашей серии (например, .bool()
, но работает даже для не логического содержимого):
>>> x = pd.Series([100])
>>> x.item()
100
-
Если вы хотите проверить, нет ли all или любого элемента, не равного нулю, непустого или не-False:
>>> x = pd.Series([0, 1, 2])
>>> x.all() # because one element is zero
False
>>> x.any() # because one (or more) elements are non-zero
True
Ответ 2
Для логической логики используйте &
и |
.
np.random.seed(0)
df = pd.DataFrame(np.random.randn(5,3), columns=list('ABC'))
>>> df
A B C
0 1.764052 0.400157 0.978738
1 2.240893 1.867558 -0.977278
2 0.950088 -0.151357 -0.103219
3 0.410599 0.144044 1.454274
4 0.761038 0.121675 0.443863
>>> df.loc[(df.C > 0.25) | (df.C < -0.25)]
A B C
0 1.764052 0.400157 0.978738
1 2.240893 1.867558 -0.977278
3 0.410599 0.144044 1.454274
4 0.761038 0.121675 0.443863
Чтобы узнать, что происходит, вы получите столбец логических значений для каждого сравнения, например.
df.C > 0.25
0 True
1 False
2 False
3 True
4 True
Name: C, dtype: bool
Если у вас есть несколько критериев, вы получите несколько столбцов. Вот почему логика объединения неоднозначна. Использование and
или or
обрабатывает каждый столбец отдельно, поэтому вам сначала нужно свести этот столбец к одному логическому значению. Например, чтобы убедиться, что любое значение или все значения в каждом столбце True.
# Any value in either column is True?
(df.C > 0.25).any() or (df.C < -0.25).any()
True
# All values in either column is True?
(df.C > 0.25).all() or (df.C < -0.25).all()
False
Один сложный способ добиться того же самого - это объединить все эти столбцы и выполнить соответствующую логику.
>>> df[[any([a, b]) for a, b in zip(df.C > 0.25, df.C < -0.25)]]
A B C
0 1.764052 0.400157 0.978738
1 2.240893 1.867558 -0.977278
3 0.410599 0.144044 1.454274
4 0.761038 0.121675 0.443863
Подробнее см. Булево индексирование в документах.
Ответ 3
Или, альтернативно, вы можете использовать модуль Operator. Более подробная информация здесь. Документы Python
import operator
import numpy as np
import pandas as pd
np.random.seed(0)
df = pd.DataFrame(np.random.randn(5,3), columns=list('ABC'))
df.loc[operator.or_(df.C > 0.25, df.C < -0.25)]
A B C
0 1.764052 0.400157 0.978738
1 2.240893 1.867558 -0.977278
3 0.410599 0.144044 1.454274
4 0.761038 0.121675 0.4438
Ответ 4
Этот отличный ответ очень хорошо объясняет, что происходит и дает решение. Я хотел бы добавить еще одно решение, которое может быть подходящим в подобных случаях: с помощью метода query
:
result = result.query("(var > 0.25) or (var < -0.25)")
См. также http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-query.
(Некоторые тесты с фреймворком данных, с которым я работаю в настоящее время, предполагают, что этот метод немного медленнее, чем использование побитовых операторов в серии логических: 2 мс против 870 мкс)
Предупреждение. По крайней мере, одна ситуация, когда это непросто, - это когда имена столбцов являются выражениями python. Я имел столбцы с именем WT_38hph_IP_2
, WT_38hph_input_2
и log2(WT_38hph_IP_2/WT_38hph_input_2)
и хотел выполнить следующий запрос: "(log2(WT_38hph_IP_2/WT_38hph_input_2) > 1) and (WT_38hph_IP_2 > 20)"
Я получил следующий каскад исключения:
-
KeyError: 'log2'
-
UndefinedVariableError: name 'log2' is not defined
-
ValueError: "log2" is not a supported function
Я предполагаю, что это произошло потому, что анализатор запросов пытался сделать что-то из первых двух столбцов вместо того, чтобы идентифицировать выражение с именем третьего столбца.
Предлагается возможное обходное решение здесь.