"The truth value of an array with more than one element is ambiguous" when comparing lists (not arrays)

huangapple go评论92阅读模式
英文:

"The truth value of an array with more than one element is ambiguous" when comparing lists (not arrays)

问题

我有一个关于列表的相等运算符 (==) 的问题。当我运行我的脚本时,在一个 if 语句中出现了错误:

"ValueError: 具有多个元素的数组的真值是不明确的。请使用 a.any() 或 a.all()。"

if 语句如下所示:

  1. if variable_a == variable_b:

我知道这是由布尔值数组被 if 语句评估引起的,但为了调试,我打印了函数的输入。我知道它们是列表类型。

  1. print(variable_a)
  2. print(variable_b)

我得到的输出看起来像这样:

  1. [[1,2],3]
  2. [3,4]

然后我在控制台中尝试了以下操作:

  1. [[1,2],3] == [3,4]

它返回 False。这不是布尔值数组,所以我不知道为什么 if 语句失败。我正在使用Python 3.9。

编辑:我刚刚运行了以下代码:

  1. print(type(variable_a))
  2. print(type(variable_b))

它们都返回:

  1. <class 'list'>

所以我绝对确定我在比较列表,而不是NumPy数组或Pandas数据框。

英文:

I have a question regarding the equality operator (==) regarding lists. When I run my script, I get an error in an if statement

>"ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()".

The if statement looks like this

  1. if variable_a == variable_b:

I know that that this is caused by an array of boolean values being evaluated by the if statement, however to debug I printed the inputs to the function. I know they are from the type list.

  1. print(variable_a)
  2. print(variable_b)

I get an output that looks like this

  1. [[1,2],3]
  2. [3,4]

But then I try the following in the Console

  1. [[1,2],3] == [3,4]

which returns False. This is not an array of boolean values so I don't know why the if statement fails. I am using python 3.9.

Edit: I just ran

  1. print(type(variable_a))
  2. print(type(variable_b))

which both returned

  1. &lt;class &#39;list&#39;&gt;

So I am definitely sure that I am comparing lists and not numpy arrays or pandas dataframes.

答案1

得分: 4

这是内置list类型的比较与NumPy的比较之间的一个奇特交互,NumPy的比较是由每种NumPy数据类型实现的,不仅仅是数组。

一个真正最小的示例:

  1. >>> import numpy as np
  2. >>> a = np.int64(1)
  3. >>> [a] == [[a, a]]
  4. Traceback (most recent call last):
  5. File "<stdin>", line 1, in <module>
  6. ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

比较涉及以下事件链:

  • [a][[a, a]] 都是列表,因此使用了列表的__eq__方法。
  • 首先检查列表的身份和长度。它们是不同的长度相同的列表,因此代码无法提前退出。
  • 因此,我们必须逐个元素地比较列表,并检查每一对是否相等。
  • 列表的第一个元素是 a[a, a],所以我们比较它们。
  • 调用a.__eq__([a, a])成功:a是NumPy标量,[a, a]是可迭代的,因此NumPy跨列表广播比较。
  • 现在整体列表比较需要检查相等比较是否返回了真值。然而,__eq__调用的结果是一个NumPy数组(array([True, True])),它不允许转换为布尔值(即,标准问题)。因此,引发了异常。

但要注意:

  1. >>> [a] == [[a]]
  2. True

a[a] 比较时,结果的数组恰好有一个总元素。NumPy将这种情况视为特殊情况。

  1. >>> [[a]] == [[a, a]]
  2. False

[a][a, a] 比较时,两者都是列表,因此NumPy尚未干涉。再次调用列表相等方法,并首先检查列表的长度。由于长度不同,任何NumPy广播都发生之前就返回了False

还需要注意的是:

  1. >>> [[a, a]] == [a]
  2. Traceback (most recent call last):
  3. File "<stdin>", line 1, in <module>
  4. ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

尽管列表明显"不等于"NumPy标量,但列表比较操作将返回NotImplemented而不是False,允许在尝试NumPy标量的__eq__之后尝试。

  1. >>> [1] == [[a, a]]
  2. False

这成功了,因为普通整数1将与NumPy对象的列表进行比较,而整数不实现任何广播。

  1. >>> [a] == [[1, 1]]
  2. Traceback (most recent call last):
  3. File "<stdin>", line 1, in <module>
  4. ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

NumPy标量将与整数列表进行比较,并广播,标量值确实可与整数进行比较。

  1. >>> [a] == [['a', 'b']]
  2. <stdin>:1: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison
  3. False
  4. >>> [a] == [['a', 1]]
  5. False
  6. >>> [a] == [[1.0, 1]]
  7. Traceback (most recent call last):
  8. File "<stdin>", line 1, in <module>
  9. ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

当前的行为取决于是否有一个数字类型的列表

英文:

This is a curious interaction between the built-in list type's comparison, and Numpy's comparison - which is implemented by each Numpy datatype, not just arrays.

A truly minimal example:

  1. &gt;&gt;&gt; import numpy as np
  2. &gt;&gt;&gt; a = np.int64(1)
  3. &gt;&gt;&gt; [a] == [[a, a]]
  4. Traceback (most recent call last):
  5. File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;
  6. ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

The comparison involves the following chain of events:

  • [a] and [[a, a]] are both lists, so the list __eq__ method is used.
  • First, the identities and lengths of the lists are checked. They're separate lists of the same length, so the code can't bail out early.
  • So we must compare the lists elementwise, and check that each pair is equal.
  • The first elements of the lists are a and [a, a], so we compare those.
  • The call a.__eq__([a, a]) succeeds: a is a Numpy scalar, and [a, a] is iterable, so Numpy broadcasts the comparison across the list.
  • Now the overall list comparison needs to check whether the equality comparison returned a truthy result.However, the result of the __eq__ call was a Numpy array (array([True, True])), which doesn't allow conversion to boolean (i.e., the standard problem). So an exception is raised.

But notice:

  1. &gt;&gt;&gt; [a] == [[a]]
  2. True

When a is compared to [a], the resulting array has exactly one total element. Numpy treats this case specially.

  1. &gt;&gt;&gt; [[a]] == [[a, a]]
  2. False

When [a] is compared to [a, a], both are lists, so Numpy doesn't get to interfere yet. The list equality method is called again, and it checks the lengths of the lists first. Since the lengths differ, False is returned before any Numpy broadcasting can occur.

Also of note:

  1. &gt;&gt;&gt; [[a, a]] == [a]
  2. Traceback (most recent call last):
  3. File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;
  4. ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

Even though the list is clearly "not equal to" the Numpy scalar, the list comparison operation will return NotImplemented rather than False, allowing the Numpy scalar's __eq__ to be tried after that.

  1. &gt;&gt;&gt; [1] == [[a,a]]
  2. False

This succeeds because the ordinary integer 1 will be compared to a list of Numpy objects, and the integer doesn't implement any broadcasting.

  1. &gt;&gt;&gt; [a] == [[1, 1]]
  2. Traceback (most recent call last):
  3. File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;
  4. ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

The Numpy scalar will be compared to a list of integers, and broadcast across that; and the scalar value is indeed comparable to integer.

  1. &gt;&gt;&gt; [a] == [[&#39;a&#39;, &#39;b&#39;]]
  2. &lt;stdin&gt;:1: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison
  3. False
  4. &gt;&gt;&gt; [a] == [[&#39;a&#39;, 1]]
  5. False
  6. &gt;&gt;&gt; [a] == [[1.0, 1]]
  7. Traceback (most recent call last):
  8. File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;
  9. ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

The current behaviour is dependent upon having a list of numeric types.

答案2

得分: 3

错误是我在列表中使用了 numpy.float32 而不是正常的浮点数据类型。实际上,它是一个列表,但我没有检查列表内的浮点数的数据类型。如果你想重现这个错误,可以像这样做:

  1. a = np.float32(1)
  2. b = np.float32(2)
  3. c = np.float32(3)
  4. d = [[a, b], c]
  5. e = [b, c]
  6. d == e
英文:

The mistake was that I used a numpy.float32 instead of the normal float datatype as the values in my list. It was indeed a list, but I didn't check the datatype of the floats inside the list. If you want to recreate the error, you can do it like this

  1. a = np.float32(1)
  2. b = np.float32(2)
  3. c = np.float32(3)
  4. d = [[a,b],c]
  5. e = [b,c]
  6. d == e

huangapple
  • 本文由 发表于 2023年3月4日 04:44:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/75631715.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定