【问题标题】:How to make a tuple including a numpy array hashable?如何使包含 numpy 数组的元组可散列?
【发布时间】:2018-04-08 06:52:43
【问题描述】:

使 numpy 数组可散列的一种方法是将其设置为只读。这在过去对我有用。但是当我在一个元组中使用这样一个 numpy 数组时,整个元组不再是可散列的,我不明白。这是我为说明问题而整理的示例代码:

import numpy as np

npArray = np.ones((1,1))
npArray.flags.writeable = False
print(npArray.flags.writeable)

keySet = (0, npArray)
print(keySet[1].flags.writeable)

myDict = {keySet : 1}

首先我创建一个简单的 numpy 数组并将其设置为只读。然后我将它添加到一个元组并检查它是否仍然是只读的(它是)。

当我想将元组用作字典中的键时,我收到错误 TypeError: unhashable type: 'numpy.ndarray'

这是我的示例代码的输出:

False
False
Traceback (most recent call last):
  File "test.py", line 10, in <module>
    myDict = {keySet : 1}
TypeError: unhashable type: 'numpy.ndarray'

我可以做些什么来使我的元组可散列?为什么 Python 首先会显示这种行为?

【问题讨论】:

  • 您从哪里得到将writeable 标志设置为False 会使数组可散列的想法?即使在您将元组带入图片之前,这也行不通。
  • 一个 numpy 数组没有所需的散列方法(类似于__hash__)。

标签: python-3.x numpy tuples hashable


【解决方案1】:

你声称

使 numpy 数组可散列的一种方法是将其设置为只读

但事实并非如此。将数组设置为只读只会使其成为只读。由于多种原因,它不会使数组可散列。

第一个原因是writeable 标志设置为False 的数组仍然是可变的。首先,您始终可以再次设置writeable=True 并继续对其进行写入,或者执行更奇特的事情,例如重新分配其shape,即使writeableFalse。其次,即使不接触数组本身,您也可以通过另一个具有writeable=True 的视图来改变其数据。

>>> x = numpy.arange(5)
>>> y = x[:]
>>> x.flags.writeable = False
>>> x
array([0, 1, 2, 3, 4])
>>> y[0] = 5
>>> x
array([5, 1, 2, 3, 4])

其次,为了使哈希性有意义,对象首先必须是 equatable - == 必须返回一个布尔值,并且必须是一个等价关系。 NumPy 数组不这样做。哈希值的目的是快速定位相等的对象,但是当您的对象甚至没有内置的相等概念时,提供哈希值就没有多大意义了。


你不会得到里面有数组的可散列元组。你甚至不会得到可散列的数组。最接近的方法是将数组数据的其他表示形式放入元组中。

【讨论】:

  • +1,感谢您对内部的澄清。如果散列数组的想法不可行,我将不得不先将其转换为字符串。
  • 是否可以围绕 numpy 数组创建某种包装器,使它们可散列和相等?这样就不必在字节/字符串/等之间来回切换。数组的表示?
【解决方案2】:

hash a numpy array is likely tostring 的最快方式。

In [11]: %timeit hash(y.tostring())

你可以做的不是使用元组定义一个类:

class KeySet(object):
    def __init__(self, i, arr):
        self.i = i
        self.arr = arr
    def __hash__(self):
        return hash((self.i, hash(self.arr.tostring())))

现在你可以在字典中使用它了:

In [21]: ks = KeySet(0, npArray)

In [22]: myDict = {ks: 1}

In [23]: myDict[ks]
Out[23]: 1

【讨论】:

  • 这感觉很pythonic,谢谢你的快速回答!而且我还可以使用包装 numpy.fromstring() 的函数将其转换回来,稍后我将需要它。
  • 还有tobytes()
猜你喜欢
  • 1970-01-01
  • 2016-08-03
  • 2018-03-15
  • 2020-12-13
  • 2019-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-12
相关资源
最近更新 更多