2011-12-19 6 views
20

Utilizzo una matrice di forme 2D per memorizzare coppie di longitudini + latitudini. A un certo punto, devo unire due di questi array 2D e quindi rimuovere qualsiasi voce duplicata. Ho cercato una funzione simile a numpy.unique, ma non ho avuto fortuna. Qualsiasi implementazione sono stato pensando a un aspetto molto "non ottimizzato". Per esempio, io sto cercando di convertire l'array in una lista di tuple, rimuovendo i duplicati con set, e poi la conversione ad un array di nuovo:Rimozione di colonne e righe duplicate da un array NumPy 2D

coordskeys = np.array(list(set([tuple(x) for x in coordskeys]))) 

Ci sono delle soluzioni esistenti, in modo da non reinventare la ruota ?

mettere in chiaro, sto cercando:

>>> a = np.array([[1, 1], [2, 3], [1, 1], [5, 4], [2, 3]]) 
>>> unique_rows(a) 
array([[1, 1], [2, 3],[5, 4]]) 

BTW, ho voluto usare solo una lista di tuple per esso, ma le liste erano così grande che hanno consumato la mia RAM 4GB + 4GB swap (gli array numpy sono più efficienti in termini di memoria).

+0

Vedere http://stackoverflow.com/questions/7989722/finding-unique-points-in-numpy-array – joris

risposta

16

Ecco un idea, ci vorrà un po 'di lavoro, ma potrebbe essere abbastanza veloce. Ti darò il caso 1d e ti consentirò di capire come estenderlo a 2d. La seguente funzione trova gli elementi unici di di un array di 1d:

import numpy as np 
def unique(a): 
    a = np.sort(a) 
    b = np.diff(a) 
    b = np.r_[1, b] 
    return a[b != 0] 

Ora di estenderlo a 2d è necessario cambiare due cose. Avrai bisogno di capire come fare da solo l'ordinamento, l'importante è che due voci identiche finiscono l'una accanto all'altra. In secondo luogo, devi fare qualcosa come (b != 0).all(axis) perché vuoi confrontare l'intera riga/colonna. Fammi sapere se è abbastanza per iniziare.

aggiornato: con un po 'di aiuto con doug, penso che questo dovrebbe funzionare per il caso 2d.

import numpy as np 
def unique(a): 
    order = np.lexsort(a.T) 
    a = a[order] 
    diff = np.diff(a, axis=0) 
    ui = np.ones(len(a), 'bool') 
    ui[1:] = (diff != 0).any(axis=1) 
    return a[ui] 
+0

+1 ho appena postato la mia risposta, poi ho letto la tua - sembra che la mia sia una fedele implementazione 2D della tua - stessa sequenza di funzioni identiche (ho anche avuto un passaggio di concatenazione di righe all'inizio, ma l'ho rimosso e tagliato la prima riga invece la matrice originale. – doug

+0

Si noti che questo * non sembra funzionare con Python3 * – Bzazz

+0

questa risposta utilizza principalmente numpy quindi python2/3 non dovrebbe avere importanza. Se non funziona per voi, probabilmente c'è qualcos'altro in corso –

1

poiché si fa riferimento a numpy.unique, non si cura di mantenere l'ordine originale, corretto? conversione in serie, che rimuove duplicati, e poi di nuovo alla lista è spesso usato idioma:

>>> x = [(1, 1), (2, 3), (1, 1), (5, 4), (2, 3)] 
>>> y = list(set(x)) 
>>> y 
[(5, 4), (2, 3), (1, 1)] 
>>> 
+1

Sì, l'ordine non è importante.La soluzione di combinare lista + set è quella che uso come esempio sull'OP (che ammetto è abbastanza offuscato).Il problema è che usa liste, e quindi la memoria utilizzata è enorme, avendo lo stesso problema di come stavo lavorando solo con liste invece di matrici dall'inizio. – Sergi

31

Questo dovrebbe fare il trucco:

def unique_rows(a): 
    a = np.ascontiguousarray(a) 
    unique_a = np.unique(a.view([('', a.dtype)]*a.shape[1])) 
    return unique_a.view(a.dtype).reshape((unique_a.shape[0], a.shape[1])) 

Esempio:

>>> a = np.array([[1, 1], [2, 3], [1, 1], [5, 4], [2, 3]]) 
>>> unique_rows(a) 
array([[1, 1], 
     [2, 3], 
     [5, 4]]) 
+0

Nice e concisa! – erikreed

+1

Nota: questo non funzionerà con un array trasposto. – user100464

+1

@ user100464, modificato in modo che funzioni con gli array trasposti. – user545424

3
>>> import numpy as NP 
>>> # create a 2D NumPy array with some duplicate rows 
>>> A 
    array([[1, 1, 1, 5, 7], 
      [5, 4, 5, 4, 7], 
      [7, 9, 4, 7, 8], 
      [5, 4, 5, 4, 7], 
      [1, 1, 1, 5, 7], 
      [5, 4, 5, 4, 7], 
      [7, 9, 4, 7, 8], 
      [5, 4, 5, 4, 7], 
      [7, 9, 4, 7, 8]]) 

>>> # first, sort the 2D NumPy array row-wise so dups will be contiguous 
>>> # and rows are preserved 
>>> a, b, c, d, e = A.T # create the keys for to pass to lexsort 
>>> ndx = NP.lexsort((a, b, c, d, e)) 
>>> ndx 
    array([1, 3, 5, 7, 0, 4, 2, 6, 8]) 
>>> A = A[ndx,] 

>>> # now diff by row 
>>> A1 = NP.diff(A, axis=0) 
>>> A1 
    array([[0, 0, 0, 0, 0], 
      [4, 3, 3, 0, 0], 
      [0, 0, 0, 0, 0], 
      [0, 0, 0, 1, 0], 
      [0, 0, 1, 0, 0], 
      [2, 5, 0, 2, 1], 
      [0, 0, 0, 0, 0], 
      [0, 0, 0, 0, 0]]) 

>>> # the index array holding the location of each duplicate row 
>>> ndx = NP.any(A1, axis=1) 
>>> ndx 
    array([False, True, False, True, True, True, False, False], dtype=bool) 

>>> # retrieve the duplicate rows: 
>>> A[1:,:][ndx,] 
    array([[7, 9, 4, 7, 8], 
      [1, 1, 1, 5, 7], 
      [5, 4, 5, 4, 7], 
      [7, 9, 4, 7, 8]]) 
+0

Doug, penso che tu Stai vicino ma avrai problemi perché NP.sort (A, axis = 0) ordina ogni colonna in modo indipendente. Prova a eseguire il tuo metodo sui due seguenti array: '[[0, 0], [1, 1], [2,2]]' e '[[0, 1], [1, 0], [2,2 ]] '. Ho aggiunto una funzione di ordinamento, la mia risposta, che mantiene intatte le righe durante l'ordinamento. –

+0

@Bago, grazie per averlo capito, appena modificato per risolvere il problema. – doug

+0

Non sapevo di lexsort, lo includerò nella mia risposta se è ok –

5

Il mio metodo è quello di trasformare una matrice 2D in 1d matrice complessa, dove la parte reale è 1a colonna, la parte immaginaria è la 2a colonna. Quindi usa np.unique. Anche se questo funzionerà solo con 2 colonne.

import numpy as np 
def unique2d(a): 
    x, y = a.T 
    b = x + y*1.0j 
    idx = np.unique(b,return_index=True)[1] 
    return a[idx] 

Esempio -

a = np.array([[1, 1], [2, 3], [1, 1], [5, 4], [2, 3]]) 
unique2d(a) 
array([[1, 1], 
     [2, 3], 
     [5, 4]]) 
3

Il pacchetto numpy_indexed (disclaimer: io sono il suo autore) avvolge la soluzione pubblicato da user545424 in un'interfaccia piacevole e testato, più molte caratteristiche correlate:

import numpy_indexed as npi 
npi.unique(coordskeys)