Истинное значение Серии неоднозначно.Используйте a.empty,a.bool(),a.item(),a.any()или a.all().

python pandas dataframe boolean filtering


Возникла проблема с фильтрацией моего результирующего фрейма данных с условием 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)]



Answer 1 MSeifert


or и and заявления питона требуют truth -значения. Для pandas они считаются неоднозначными, поэтому вы должны использовать «побитовый» | (или) или & (и) операции:

result = result[(result['var']>0.25) | (result['var']<-0.25)]

Они перегружены для такого рода структур данных, чтобы получить поэлементное or (или and ).


Просто,чтобы добавить немного больше объяснений к этому заявлению:

Исключение pandas.Series когда вы хотите получить 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 операторов, есть несколько функций python, которые скрывают некоторые вызовы bool (как , например, any , all , filter , ...), они обычно не являются проблематичными для pandas.Series , но для полноты я хотел упомянуть об этом.


В вашем случае исключение не очень полезно, потому что оно не упоминает правильные альтернативы . Для and и or вы можете использовать (если вы хотите поэлементное сравнение):

  • numpy.logical_or:

    >>> import numpy as np
    >>> np.logical_or(x, y)

    или просто | оператор:

    >>> x | y
  • numpy.logical_and:

    >>> np.logical_and(x, y)

    или просто оператор & :

    >>> x & y

Если вы используете операторы, убедитесь, что вы правильно установили круглые скобки из-за приоритета оператора .

Есть несколько логических функций numpy, которые должны работать на pandas.Series .


Альтернативы, упомянутые в Исключении, больше подходят, если вы столкнулись с этим, когда делаете if или while . Я кратко объясню каждый из них:

  • Если вы хотите проверить, пуста ли ваша серия :

    >>> x = pd.Series([])
    >>> x.empty
    True
    >>> x = pd.Series([1])
    >>> x.empty
    False

    Python обычно интерпретирует len GTH контейнеров (например , list , tuple , ...) как истинностное значение , если оно не имеет явное логическое толкования. Поэтому, если вам нужна проверка, if x.size , вы можете сделать: 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
  • Если вы хотите проверить, что все или любой элемент не нулевой, не пустой или не ложный:

    >>> 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



Answer 2 Alexander


Для логической логики используйте & и | ,

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 обрабатывает каждый столбец отдельно, поэтому сначала нужно уменьшить этот столбец до одного логического значения. Например, чтобы увидеть, является ли какое-либо значение или все значения в каждом из столбцов истинными.

# 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

Для получения более подробной информации см. Булево индексирование в документации.




Answer 3 Nipun


Ну, панды используют побитовые '&' '|' и каждое условие должно быть заключено в '()'

Например,следующие работы

data_query = data[(data['year'] >= 2005) & (data['year'] <= 2010)]

Но тот же самый запрос без правильных скобок не

data_query = data[(data['year'] >= 2005 & data['year'] <= 2010)]



Answer 4 Cảnh Toàn Nguyễn


Или, в качестве альтернативы, вы можете использовать модуль оператора. Более подробная информация здесь 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



Answer 5 bli


Этот превосходный ответ очень хорошо объясняет, что происходит, и дает решение. Я хотел бы добавить другое решение, которое может подойти в подобных случаях: используя метод 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

Думаю,это произошло потому,что парсер запросов пытался что-то сделать из первых двух столбцов,вместо того,чтобы идентифицировать выражение с именем третьего столбца.

Возможный обходной путь предлагается здесь .