【问题标题】:Adding numpy array to a heap queue将numpy数组添加到堆队列
【发布时间】:2017-07-03 08:56:30
【问题描述】:

有人能解释一下为什么下面的代码会导致 ValueError 吗?

import heapq
import numpy as np

a = np.ones((2, 2), dtype=int)

states = []
heapq.heappush(states, (0, a))
heapq.heappush(states, (0, a.copy()))

错误信息是:

Traceback (most recent call last):
  File "x.py", line 8, in <module>
    heapq.heappush(states, (0, a.copy()))
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

在不将a.copy() 添加到堆中的情况下运行它可以正常工作,第二个/后续一个由于某种原因是一个问题。我确实知道[True, False, True] 数组存在未知的真值方面,并且无法从中确定单个TrueFalse,但为什么heapq 需要这样做?尤其是第二种情况?

【问题讨论】:

  • heapq 需要比较堆元素。堆元素是元组,元组的第一个条目相等,所以它比较第二个元素。比较第二个元素不会产生可以解释为布尔值的东西。
  • 请注意,heapq.heappush(heap, (x, y)) 并不意味着“推送事物 y 优先 x”;它的意思是“推东西(x, y)”。我们没有单独的优先事项和要素;我们只有元素。

标签: python arrays numpy heap


【解决方案1】:

TL;DR:因为如果 numpy 数组包含多个元素,则无法将其转换为布尔值。


关于堆的一些信息:

堆“排序”它们的内容(因此项目必须实现&lt;,但这是一个实现细节)。

但是,您可以通过为项目创建tuples 将项目插入heap,其中第一个元素是某个值,第二个元素是数组。

比较元组首先检查第一个项目是否相等,如果它们相等,则检查第二个项目是否相等,依此类推,直到它们不相等,然后它会检查它是否更小(当操作为&lt;时)或更大(对于&gt;)。但是元组是用 C 实现的,== 检查与 Python 中的检查有点不同。它使用PyObject_RichCompareBool。尤其是“注意”在这里很重要

如果o1o2 是同一个对象,PyObject_RichCompareBool() 将始终为Py_EQ 返回 1,为 Py_NE 返回 0。

现在让我们转到 numpy 数组:

如果 numpy.array 包含多个项目,则无法将其转换为 bool

>>> arr = np.array([1,2,3])
>>> bool(arr)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

if 检查将条件隐式转换为布尔值:

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

即使在比较了 numpy 数组之后,它们仍然是 numpy 数组:

>>> arr > arr
array([False, False], dtype=bool)
>>> arr == arr
array([ True,  True], dtype=bool)

所以这些不能用==评估:

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

因此,您不能将具有多个元素的 numpy 数组转换为布尔值!然而现在有趣的部分来了:heapq-模块使用PyObject_RichCompareBool(),所以它可以检查两个数组是否相等,但当且仅当它们是相同的!

这就是为什么它与多次传递的相同数组一起工作,但复制时失败:

>>> arr is arr
True
>>> arr is arr.copy()
False

【讨论】:

  • “堆是稳定的并且“排序”它们的内容......这意味着比较相等的项目将与它们最初的顺序相同” - 你在说什么? heapq 根本不保证这一点,它也不做你描述的值位置元组的事情。如果你想要这种行为,你必须自己做。
  • @user2357112 感谢您的评论,我更正了答案。
【解决方案2】:

当前答案没有讨论解决方案。 一种解决方法是将np.array 转换为tuple,然后再将其输入到heapq 处理的states 列表中。 tuple 函数仅适用于数组的第一维,因此一种快速的方法是首先展平数组:

states = []
heapq.heappush(states, (0, tuple(a.flat)))
heapq.heappush(states, (0, tuple(a.flat)))

或者,可以通过使用保留所有数组维度 (来自answer):

def totuple(a):
    try:
        return tuple(totuple(i) for i in a)
    except TypeError:
        return a

【讨论】:

    猜你喜欢
    • 2014-03-05
    • 1970-01-01
    • 1970-01-01
    • 2017-05-09
    • 1970-01-01
    • 2021-07-16
    • 2012-06-21
    • 2016-02-27
    • 1970-01-01
    相关资源
    最近更新 更多