一个系列的真值是模糊的。使用a.空、a.bool()、a.项()、a.any()或a.all()

python pandas dataframe boolean filtering


在使用 or 条件过滤我的结果数据帧时出现问题。我希望我的结果 df 提取大于0.25且小于-0.25的所有列 var 值。

下面的逻辑为我提供了一个模糊的真实值,但是当我将此过滤分为两个独立的操作时,它可以工作。这是怎么回事 不知道在哪里使用建议的 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


orand Python的语句需要 truth -值。对于 pandas 它们被认为是模棱两可的,因此应使用“按位” | (或)或 & (和)操作:

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

对于此类数据结构,它们会重载以产生按元素 or (或 and )。


只是想对这句话再加一些解释。

当您想获取 pandas.Seriesbool ,抛出该异常:

>>> 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 但也会发生在 andifwhile 上):

>>> 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 调用(如 anyallfilter ,...),这些通常对于 pandas.Series 来说不是问题,但是为了完整起见,我想提及这些。


在您的情况下,该异常并没有真正的帮助,因为它没有提到正确的替代方法。对于 andor 可以使用(如果要逐元素比较):

  • 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应该几个逻辑上的numpy函数


如果您在进行 ifwhile 时遇到它,则Exception中提到的替代方法更适合。我将在下面简短地解释每个:

  • 如果要检查您的系列是否为

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

    通常的Python解释 len 容器的GTH(如 listtuple ,...)作为真值,如果它没有明显的布尔解释。因此,如果您想进行类似python的检查,则可以执行以下操作: if x.sizeif 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
  • 如果要检查是否全部任何项目是否为非零,非空或非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



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

当您有多个条件时,将返回多个列。这就是为什么联接逻辑模棱两可的原因。使用 andor 对待每列,因此您首先需要将该列减少为单个布尔值。例如,查看每个列中的任何值或所有值是否为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

有关更多详细信息,请参阅 文档中的布尔索引。




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 ms vs. 870 µs)

警告:至少其中一种情况并非如此简单,那就是列名恰好是python表达式。我有名为 WT_38hph_IP_2WT_38hph_input_2log2(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

我想这是因为查询解析器试图从前两列中制作出一些东西,而不是用第三列的名称来标识表达式。

这里提出了一种可能的解决方法。