2011-12-19 160 views
20

Estoy usando una matriz de formas 2D para almacenar pares de longitudes + latitudes. En un punto, tengo que fusionar dos de estas matrices 2D y luego eliminar cualquier entrada duplicada. He estado buscando una función similar a numpy.unique, pero no he tenido suerte. Cualquier implementación He estado pensando en miradas muy "no optimizadas". Por ejemplo, estoy tratando con la conversión de la matriz a una lista de tuplas, la eliminación de duplicados con juego, y luego convertir a un array nuevo:Eliminación de columnas y filas duplicadas de una matriz NumPy 2D

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

¿Hay soluciones existentes, por lo que no reinventar la rueda ?

Para que quede claro, yo estoy buscando:

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

Por cierto, que quería utilizar sólo una lista de tuplas para ello, pero las listas eran tan grandes que consumen mi memoria RAM de 4 Gb + 4 Gb swap (matrices numpy son más eficientes en la memoria).

+0

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

Respuesta

16

He aquí una idea, que va a tomar un poco de trabajo, pero podría ser bastante rápido. Te daré el caso 1D y te dejaremos averiguar cómo extenderlo a 2d. La función siguiente busca los elementos únicos de una matriz de 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] 

Ahora extenderlo a 2d necesita cambiar dos cosas. Tendrá que averiguar cómo hacer la clasificación usted mismo, lo importante sobre el género será que dos entradas idénticas terminan una junto a la otra. En segundo lugar, deberá hacer algo como (b != 0).all(axis) porque desea comparar toda la fila/columna. Avísame si eso es suficiente para que comiences.

actualizado: Con un poco de ayuda con Doug, creo que esto debería funcionar para el 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 acaba de publicar mi respuesta, luego lea la suya - parece que la mía es una fiel implementación en 2D suya - la misma secuencia de funciones idénticas (incluso tuve un paso de concatenación de fila al principio, pero lo eliminé y corté en la primera fila fuera de la matriz original en su lugar. – doug

+0

Tenga en cuenta que esto * no parece funcionar con Python3 * – Bzazz

+0

esta respuesta utiliza sobre todo numpy, por lo que python2/3 no debería importar. Si no está funcionando para usted, probablemente haya algo más en marcha –

1

dado que se refiere a numpy.unique, no se preocupa de mantener el orden original, ¿correcto? convertir en conjunto, que elimina duplicados, y luego volver a la lista se utiliza a menudo modismo:

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

Sí, el orden no es importante. La solución de combinar list + set es la que yo uso como ejemplo en el OP (que admito está bastante ofuscado).El problema es que usa listas y, por lo tanto, la memoria utilizada es enorme, y tiene el mismo problema que si solo trabajara con listas en lugar de matrices desde el principio. – Sergi

31

Esto debe hacer el truco:

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

Ejemplo:

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

Bueno y conciso! – erikreed

+1

Nota: esto no funcionará con una matriz transpuesta – user100464

+1

@ user100464, editado para que funcione con arrays transpuestas. – 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, creo que Estás cerca pero vas a tener problemas porque NP.sort (A, axis = 0) ordena cada columna de forma independiente. Intente ejecutar su método en las dos matrices siguientes: '[[0, 0], [1, 1], [2,2]]' y '[[0, 1], [1, 0], [2,2 ]] '. Agregué una función de clasificación, mi respuesta, que mantiene las filas intactas durante la clasificación. –

+0

@Bago gracias por captar eso - solo editado para corregirlo. – doug

+0

No sabía sobre lexsort, voy a incluirlo en mi respuesta si está bien –

5

Mi método es girando una matriz 2D en serie compleja 1d, donde la parte real es 1ra columna, parte imaginaria es la 2da columna. Luego usa np.unique. Aunque esto solo funcionará con 2 columnas.

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] 

Ejemplo -

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

El paquete numpy_indexed (exención de responsabilidad: yo soy su autor) envuelve la solución Publicado por user545424 en una interfaz agradable y probada, además de muchas características relacionadas:

import numpy_indexed as npi 
npi.unique(coordskeys) 
Cuestiones relacionadas