6

使 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 首先会显示这种行为?

4

2 回答 2

14

你声称

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

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

writeable第一个原因是标志设置为的数组False仍然是可变的。首先,您可以随时writeable=True重新设置并继续对其进行写入,或者做一些更奇特的事情,例如重新分配它shapeeven while writeableis False。其次,即使不接触数组本身,您也可以通过另一个具有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])

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


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

于 2017-10-26T19:25:08.850 回答
7

散列 numpy 数组的最快方法可能是 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
于 2017-10-26T19:14:21.627 回答