2009-12-21 249 views
11

我試圖執行設置一個python以下構建從numpy的矩陣

>> from numpy import * 
>> x = array([[3,2,3],[4,4,4]]) 
>> y = set(x) 
TypeError: unhashable type: 'numpy.ndarray' 

我怎樣才能輕鬆而高效地創建一個從numpy的陣列一組?

回答

17

如果你想一組的元素,這裏是另一個,可能更快,w^AY:

y = set(x.flatten()) 

PS:一個10x100陣列上x.flatx.flatten(),和x.ravel()之間執行比較後,我發現,它們都在大約相同的速度來執行。對於一個3x3的陣列,最快的版本是迭代版本:

y = set(x.flat) 

,我會建議,因爲它是較少的內存便宜的版本(它擴展了很好地與數組的大小)。

PS:還有一個NumPy的函數,它類似的東西:

y = numpy.unique(x) 

這確實產生NumPy的陣列作爲set(x.flat)相同的元素,但作爲一個NumPy的陣列。這個速度非常快(幾乎快10倍),但是如果你需要set,那麼做set(numpy.unique(x))比其他程序慢一點(構建一個集會帶來很大的開銷)。

+2

好建議!你也可以使用set(x.ravel()),它可以做同樣的事情,但只有在需要時才創建一個副本。或者,更好的是,使用set(x.flat)。 x.flat是迭代器,用於展平數組的元素,但不會浪費時間實際上展平數組 – musicinmybrain 2009-12-21 12:11:59

+0

@musicinmybrain:非常好的一點!謝謝! – EOL 2009-12-21 14:23:10

+2

警告:這個答案*不會給你一組向量,而是一組數字。如果你想要一組矢量然後看下面的miku的答案,將矢量轉換成元組 – conradlee 2011-08-02 11:30:13

9

不可改變對應到一個數組元組,因此,儘量數組的數組轉換成元組的數組:

>> from numpy import * 
>> x = array([[3,2,3],[4,4,4]]) 

>> x_hashable = map(tuple, x) 

>> y = set(x_hashable) 
set([(3, 2, 3), (4, 4, 4)]) 
+0

以及如何我很容易/高效地把回單嗎? – user989762 2014-02-18 05:57:04

+0

'map(array,y)' – Manuel 2014-03-26 12:07:59

3

如果你想一組的元素:

>> y = set(e for r in x 
      for e in r) 
set([2, 3, 4]) 

對於集中行:

>> y = set(tuple(r) for r in x) 
set([(3, 2, 3), (4, 4, 4)]) 
6

上述答案的工作,如果你想創建一組出元素包含在ndarray,但如果你想創建一套ndarray對象 - 或在字典中使用ndarray對象作爲鍵 - 那麼你必須爲他們提供一個可以打包的包裝。請參見下面的代碼,一個簡單的例子:

from hashlib import sha1 

from numpy import all, array, uint8 


class hashable(object): 
    r'''Hashable wrapper for ndarray objects. 

     Instances of ndarray are not hashable, meaning they cannot be added to 
     sets, nor used as keys in dictionaries. This is by design - ndarray 
     objects are mutable, and therefore cannot reliably implement the 
     __hash__() method. 

     The hashable class allows a way around this limitation. It implements 
     the required methods for hashable objects in terms of an encapsulated 
     ndarray object. This can be either a copied instance (which is safer) 
     or the original object (which requires the user to be careful enough 
     not to modify it). 
    ''' 
    def __init__(self, wrapped, tight=False): 
     r'''Creates a new hashable object encapsulating an ndarray. 

      wrapped 
       The wrapped ndarray. 

      tight 
       Optional. If True, a copy of the input ndaray is created. 
       Defaults to False. 
     ''' 
     self.__tight = tight 
     self.__wrapped = array(wrapped) if tight else wrapped 
     self.__hash = int(sha1(wrapped.view(uint8)).hexdigest(), 16) 

    def __eq__(self, other): 
     return all(self.__wrapped == other.__wrapped) 

    def __hash__(self): 
     return self.__hash 

    def unwrap(self): 
     r'''Returns the encapsulated ndarray. 

      If the wrapper is "tight", a copy of the encapsulated ndarray is 
      returned. Otherwise, the encapsulated ndarray itself is returned. 
     ''' 
     if self.__tight: 
      return array(self.__wrapped) 

     return self.__wrapped 

使用包裝類是很簡單的:

>>> from numpy import arange 

>>> a = arange(0, 1024) 
>>> d = {} 
>>> d[a] = 'foo' 
Traceback (most recent call last): 
    File "<input>", line 1, in <module> 
TypeError: unhashable type: 'numpy.ndarray' 
>>> b = hashable(a) 
>>> d[b] = 'bar' 
>>> d[b] 
'bar'