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

370

Возникла проблема с фильтрацией моего результирующего кадра данных с 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)]
obabs
источник
47
использовать |вместоor
MaxU
1
Вот обходной путь:abs(result['var'])>0.25
ColinMac

Ответы:

567

Для операторов orи andpython требуются truth-values. Потому что 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 заявлений есть несколько функций 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

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

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


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

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

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

    Python обычно интерпретирует lenGTH контейнеров (например list, tuple...) , как истинностное значение , если оно не имеет явное логическое толкования. Поэтому, если вы хотите проверку, подобную питону, вы можете сделать: 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
MSeifert
источник
Почему эти операторы python не перегружены для работы с сериями панд?
Mudit Jain
@MuditJain Там нет никакого способа непосредственно от перегрузки and, orи notв Python. Эти операторы напрямую используют то, boolчто возвращается из операндов. И в некотором роде Pandas / NumPy перегружены, что уже поднять, ValueErrorпотому что они считают истинную ценность такой структуры данных неоднозначной.
MSeifert
решение в порядке, но объяснение далеко не хорошее
blacksheep
2
@blacksheep У вас есть предложения, что я мог бы объяснить лучше?
MSeifert
Это отличное объяснение. Это на самом деле помогло мне понять побитовое и логическое так, как не смогли сделать более абстрактные примеры.
RockNwaves
41

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

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

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

Александр
источник
20

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

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

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

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

data_query = data[(data['year'] >= 2005 & data['year'] <= 2010)]
Nipun
источник
8

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

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

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

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

бли
источник
1

Я столкнулся с той же ошибкой и несколько дней зависал с фреймом данных pyspark, и мне удалось успешно ее исправить, заполнив n значениями 0, так как я сравнивал целочисленные значения из 2 полей.

iretex
источник