2009-12-21 10 views

Odpowiedz

17

Jeśli chcesz zbiór elementów, tu jest inny, prawdopodobnie szybciej w ay:

y = set(x.flatten()) 

PS: po przeprowadzeniu porównań między x.flat, x.flatten() i x.ravel() na tablicy 10x100, okazało się, że wszystkie one spełniają w tym samym tempie. Dla macierzy 3x3, najszybsza wersja jest wersją iterator:

y = set(x.flat) 

które polecam ponieważ jest to mniej kosztowna wersja pamięci (nie skaluje się dobrze z wielkością tablicy).

PS: Istnieje również funkcja NumPy że robi coś podobnego:

y = numpy.unique(x) 

To nie wytwarzają szereg NumPy z tego samego elementu jak set(x.flat), ale jako tablica numpy. Jest to bardzo szybkie (prawie 10 razy szybciej), ale jeśli potrzebujesz set, wykonanie set(numpy.unique(x)) jest nieco wolniejsze niż inne procedury (budowanie zestawu ma duży narzut).

+2

Dobra sugestia! Można również użyć zestawu (x.ravel()), który robi to samo, ale tworzy kopię tylko w razie potrzeby. Lub, lepiej, użyj zestawu (x.flat). x.flat to iterator nad elementami spłaszczonej tablicy, ale nie marnuje czasu na spłaszczanie tablicy – musicinmybrain

+0

@musicinmybrain: bardzo dobre punkty! Dziękuję Ci! – EOL

+2

OSTRZEŻENIE: ta odpowiedź * nie * da ci zestawu wektorów, lecz zbiór liczb. Jeśli chcesz zestaw wektorów, zobacz odpowiedź miku poniżej, która konwertuje wektory na krotki – conradlee

9

niezmienny odpowiednik tablicy jest krotka, a więc spróbuj przekonwertować tablicy tablic na tablicę krotek:

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

i jak łatwo/sprawnie przekształcić z powrotem na liście? – user989762

+0

'mapa (tablica, y)' – Manuel

3

Jeśli chcesz zestaw elementów:

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

za zestaw wierszy:

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

Powyższe odpowiedzi działać, jeśli chcesz utworzyć zestaw Spośród elementów zawartej w ndarray, ale jeśli chcesz utworzyć zestaw ndarray obiektów - lub użyj ndarray przedmiotów jak klucze w słowniku - wtedy Będą musieli podać dla nich owinięte folie. Zobacz poniższy kod na prostym przykładzie:

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 

Korzystanie z klasy otoki jest dość proste:

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