【问题标题】:Evaluating pandas series values with logical expressions and if-statements使用逻辑表达式和 if 语句评估 pandas 系列值
【发布时间】:2014-06-21 02:34:28
【问题描述】:

我在使用 if 语句评估字典中的值时遇到问题。

鉴于以下字典,我从数据框中导入(以防万一):

>>> pnl[company]
29:   Active Credit       Date   Debit Strike Type
0      1      0 2013-01-08  2.3265  21.15  Put
1      0      0 2012-11-26      40     80  Put
2      0      0 2012-11-26     400     80  Put

我尝试评估以下语句以确定Active 的最后一个值的值:

if pnl[company].tail(1)['Active']==1:
    print 'yay'

但是,我遇到了以下错误消息:

Traceback (most recent call last):
  File "<pyshell#69>", line 1, in <module>
    if pnl[company].tail(1)['Active']==1:
  File "/usr/lib/python2.7/dist-packages/pandas/core/generic.py", line 676, in __nonzero__
    .format(self.__class__.__name__))
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

这让我很惊讶,因为我可以使用上面的命令显示我想要的值,而无需 if 语句:

>>> pnl[company].tail(1)['Active']
30: 2    0
Name: Active, dtype: object

鉴于值显然为零且索引为 2,我尝试了以下方法进行简短的健全性检查,发现事情并没有像我预期的那样发生:

>>> if pnl[company]['Active'][2]==0:
...     print 'woo-hoo'
... else:
...     print 'doh'


doh

我的问题是:

1) 这里可能发生了什么?我怀疑我在某些基本层面上误解了字典。

2) 我注意到,当我调出这本字典的任何给定值时,左边的数字会增加 1。这代表什么?例如:

>>> pnl[company].tail(1)['Active']
31: 2    0
Name: Active, dtype: object
>>> pnl[company].tail(1)['Active']
32: 2    0
Name: Active, dtype: object
>>> pnl[company].tail(1)['Active']
33: 2    0
Name: Active, dtype: object
>>> pnl[company].tail(1)['Active']
34: 2    0
Name: Active, dtype: object

提前感谢您的帮助。

【问题讨论】:

  • 这不是关于字典的问题,而是关于 Pandas Series 对象的问题。
  • 这似乎是您正在使用的 pandas 库所特有的。看起来 pandas 提供的对象有点像字典,但在重要方面有所不同。需要明确的是,您在这里处理的不是通常的 Python 字典,而是使用 pandas 提供的具有类字典语法的数据结构。
  • 你产生一个系列而不是字典,因此它无法评估你的布尔查询,就像错误建议你需要做pnl[company].tail(1)['Active'].any()==1,即使这仍然是一个单一的值
  • 关于您的第二个问题,您是否混淆了序数输出数?所以如果你只是反复打印“yay”或print(“yay”)(对于python 3),这个数字仍然会增加
  • @neanderslob:事实上,您从 pandas 库源文件中收到了诸如 The truth value of a Series is ambiguous 之类的错误。

标签: python pandas if-statement series


【解决方案1】:

您生成的是 Pandas Series 对象,并且无法以您尝试的方式对其进行评估,即使它只是您需要将行更改为的单个值:

if pnl[company].tail(1)['Active'].any()==1:
  print 'yay'

关于您的第二个问题,请参阅我的评论。

编辑

从 cmets 并链接到您的输出,调用 any() 修复了错误消息,但您的数据实际上是字符串,因此比较仍然失败,您可以这样做:

if pnl[company].tail(1)['Active'].any()=='1':
  print 'yay'

进行字符串比较,或修复读取或生成的数据。

或者做:

pnl['Company']['Active'] = pnl['Company']['Active'].astype(int)

转换列的dtype,以便您的比较更正确。

【讨论】:

  • 一如既往,感谢您的帮助!我试了一下解决方案,它确实消除了错误。但是,我仍然无法让它承认它的价值。无论价值如何,我都无法让它打印“耶”。 See the output here 在上面的问题中,我的“健全性检查”也遇到了同样的情况。知道为什么会这样吗?
  • 这看起来像一个字符串 if pnl[company].tail(1)['Active'].any()=='0' 工作吗?你想要它作为一个字符串还是一个 int/float?
  • @EdChum:.any() 将返回 True 或 False。我不确定将 any 的返回值与 1 进行比较是否是 OP 真正想要的......
  • @unutbu 我没有观察到,当我调用 df.tail(1)['col'].any() 它返回值时,比较将产生 True 或 False
  • 要么修复你首先读取数据,要么这样做pnl['Company']['Active'] = pnl['Company']['Active'].astype(int)
【解决方案2】:

系列是 NDFrame 的子类。 NDFrame.__bool__ 方法 always raises a ValueError。因此,尝试在布尔上下文中评估 Series 会引发 ValueError——即使 Series 只有一个值。

NDFrame 没有布尔值(错误,即总是引发 ValueError)的原因是,有多个可能的标准可以合理地预期 NDFrame 为 True。这可能意味着

  1. NDFrame 中的每一项都是 True,或者(如果是,请使用 .all()
  2. NDFrame 中的任何项目都是 True,或者(如果是,请使用 Series.any()
  3. NDFrame 不为空(如果是,请使用.empty()

由于任何一种都是可能的,而且由于不同的用户有不同的期望,因此开发人员不会仅仅选择一个,而是拒绝猜测,而是要求 NDFrame 的用户明确说明他们希望使用什么标准。

错误信息列出了最可能的选择:

使用 a.empty、a.bool()、a.item()、a.any() 或 a.all()

由于在您的情况下您知道 Series 将只包含一个值,因此您可以使用 item:

if pnl[company].tail(1)['Active'].item() == 1:
    print 'yay'

关于您的第二个问题:左边的数字似乎是您的 Python 解释器(PyShell?)生成的行号——但这只是我的猜测。


警告:大概,

if pnl[company].tail(1)['Active']==1:

表示当 Series 中的单个值等于 1 时,您希望条件为 True。代码

if pnl[company].tail(1)['Active'].any()==1:
    print 'yay'

如果 Series 的 dtype 是 numeric 并且 Series 中的值是 任何数字 不是 0,则为 True。例如,如果我们取 pnl[company].tail(1)['Active'] 等于

In [128]: s = pd.Series([2], index=[2])

然后

In [129]: s.any()
Out[129]: True

因此,

In [130]: s.any()==1
Out[130]: True

我认为s.item() == 1 更忠实地保留了您的预期含义:

In [132]: s.item()==1
Out[132]: False

(s == 1).any() 也可以,但使用any 并不能非常清楚地表达您的意图,因为您知道 Series 将只包含一个值。

【讨论】:

    【解决方案3】:

    您的问题与 Python 字典或原生 Python 完全无关。 这是关于熊猫系列的,其他答案给了你正确的语法:

    从更广泛的意义上解释您的问题,它是关于如何将pandas Series 硬塞到NumPyNumPy historically until recently had notoriously poor support for logical values and operators 上。 pandas 利用 NumPy 提供的功能尽其所能。有时不得不手动调用 numpy 逻辑函数,而不仅仅是使用任意 (Python) 运算符编写代码,这既烦人又笨拙,有时还会使 pandas 代码膨胀。此外,您通常必须这样做以提高性能(numpy 比在本地 Python 之间往返更好)。但这就是我们付出的代价。

    有很多限制、怪癖和陷阱(以下示例) - 由于 numpy 的限制,最好的建议是不要相信 boolean 作为 pandas 中的一等公民:

    .

    import numpy as np
    import pandas as pd
    s = pd.Series([True, True, False, True, np.NaN])
    s2  = pd.Series([True, True, False, True, np.NaN])
    dir(s) # look at .all, .any, .bool, .eq, .equals, .invert, .isnull, .value_counts() ...
    
    s.astype(bool) # WRONG: should use the member s.bool ; no parentheses, it's a member, not a function
    # 0     True
    # 1     True
    # 2    False
    # 3     True
    # 4     True  # <--- should be NA!!
    #dtype: bool
    
    s.bool
    # <bound method Series.bool of
    # 0     True
    # 1     True
    # 2    False
    # 3     True
    # 4      NaN
    # dtype: object>
    
    # Limitation: value_counts() currently excludes NAs
    s.value_counts()
    # True     3
    # False    1
    # dtype: int64
    help(s.value_counts) # "... Excludes NA values(!)"
    
    # Equality comparison - vector - fails on NAs, again there's no NA-handling option):
    s == s2 # or equivalently, s.eq(s2)
    # 0     True
    # 1     True
    # 2     True
    # 3     True
    # 4    False  # BUG/LIMITATION: we should be able to choose NA==NA
    # dtype: bool
    
    # ...but the scalar equality comparison says they are equal!!
    s.equals(s2)
    # True
    

    【讨论】:

    猜你喜欢
    • 2012-01-18
    • 1970-01-01
    • 2013-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-16
    • 2023-03-07
    相关资源
    最近更新 更多