2009-12-21 15 views
11

Sto cercando di eseguire il seguenteCostruire un pitone insieme da una matrice NumPy

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

Come posso modo semplice ed efficiente creare un insieme da una matrice numpy?

risposta

17

Se si desidera una serie di elementi, ecco un altro, probabilmente più veloce w ay:

y = set(x.flatten()) 

PS: dopo aver eseguito il confronto tra x.flat, x.flatten() e x.ravel() su una matrice 10x100, ho scoperto che svolgono tutti a circa la stessa velocità. Per una matrice 3x3, la versione più veloce è la versione iteratore:

y = set(x.flat) 

che consiglio perché è la versione costosi meno memoria (una scalabilità bene con la dimensione della matrice).

PS: V'è anche una funzione NumPy che fa qualcosa di simile:

y = numpy.unique(x) 

Questo fa produrre una matrice NumPy con lo stesso elemento set(x.flat), ma come una matrice NumPy. Questo è molto veloce (quasi 10 volte più veloce), ma se hai bisogno di un set, quindi fare set(numpy.unique(x)) è un po 'più lento rispetto alle altre procedure (costruire un set viene fornito con un grande overhead).

+2

Buon suggerimento! Puoi anche usare set (x.ravel()), che fa la stessa cosa ma crea una copia solo se necessario. O, meglio, usa set (x.flat). x.flat è un iteratore sugli elementi dell'array appiattito, ma non perde tempo a livellare l'array – musicinmybrain

+0

@musicinmybrain: ottimi punti! Grazie! – EOL

+2

ATTENZIONE: questa risposta * non * ti fornirà un set di vettori, ma piuttosto una serie di numeri. Se si desidera un set di vettori, consultare la risposta di miku sotto la quale converte i vettori in tuple – conradlee

9

La controparte immutabile di un array è la tupla, quindi, provare a convertire l'array di array in un array di tuple:

>> 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

e come ho facilmente/efficiente trasformare di nuovo ad una lista? – user989762

+0

'map (array, y)' – Manuel

3

Se si desidera una serie di elementi:

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

Per una serie di righe:

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

Le risposte di cui sopra funziona se si desidera creare un insieme fuori dalle elementi contenuto in un ndarray, ma se si vuole creare un set di ndarray oggetti - o utilizzare ndarray oggetti come chiavi in ​​un dizionario - allora Dovrò fornire un involucro lavabile per loro. Vedere il codice qui sotto per un semplice esempio:

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 

Uso della classe wrapper è abbastanza semplice:

>>> 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' 
Problemi correlati