Истинностное значение ряда неоднозначно. Использовать.пустая.типа bool(), а.пункт(), а.любой() или.все()


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

4 ответа:

The or и and операторы python требуют 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 операторов есть несколько функций 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ГТХ контейнеров (например,list,tuple, ...) как истинностное значение, если оно не имеет явной булевой интерпретации. Поэтому, если вы хотите проверить python-like, вы можете сделать:if x.size или if not x.empty вместо if x.

  • если Series содержит один и только один boolean значение:

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

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

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

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

или, в качестве альтернативы, вы можете использовать модуль оператора. Более подробная информация здесь Python docs

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

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

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

возможное решение предложил!--38-->здесь.