Necesito encontrar filas únicas en a numpy.array.
Por ejemplo:
>>> a # I have
array([[1, 1, 1, 0, 0, 0],
[0, 1, 1, 1, 0, 0],
[0, 1, 1, 1, 0, 0],
[1, 1, 1, 0, 0, 0],
[1, 1, 1, 1, 1, 0]])
>>> new_a # I want to get to
array([[1, 1, 1, 0, 0, 0],
[0, 1, 1, 1, 0, 0],
[1, 1, 1, 1, 1, 0]])
Sé que puedo crear un conjunto y un bucle sobre la matriz, pero estoy buscando una numpysolución pura eficiente . Creo que hay una manera de configurar el tipo de datos para anular y luego podría usar numpy.unique, pero no pude encontrar la manera de hacerlo funcionar.

Respuestas:
A partir de NumPy 1.13, uno simplemente puede elegir el eje para la selección de valores únicos en cualquier matriz N-dim. Para obtener filas únicas, uno puede hacer:
unique_rows = np.unique(original_array, axis=0)fuente
np.unique(list_cor, axis=0)obtiene la matriz con filas duplicadas eliminadas ; no filtra la matriz a elementos que son únicos en la matriz original . Ver aquí , por ejemplo ..original_array.sort(axis=1)Otra posible solución
fuente
np.vstack(list({tuple(row) for row in AIPbiased[i, :, :]}))FutureWarning: las matrices para apilar deben pasarse como un tipo de "secuencia" como lista o tupla. El soporte para iterables no secuenciales, como los generadores, está en desuso a partir de NumPy 1.16 y generará un error en el futuro.Otra opción para el uso de matrices estructuradas es usar una vista de un
voidtipo que une toda la fila en un solo elemento:EDITAR Añadido
np.ascontiguousarraysiguiendo la recomendación de @ seberg. Esto ralentizará el método si la matriz aún no es contigua.EDITAR Lo anterior se puede acelerar un poco, quizás a costa de la claridad, haciendo:
Además, al menos en mi sistema, en cuanto al rendimiento, está a la par, o incluso mejor, que el método lexsort:
fuente
b = a.view(np.dtype((np.void, a.dtype.itemsize * a.shape[1])))?np.voidtipo de datos del tamaño del número de bytes en una fila completa. Es similar a lo que obtienes si tienes una matriz denp.uint8s y la ves comonp.uint16s, que combina cada dos columnas en una sola, pero más flexible.np.ascontiguousarrayo similar para ser generalmente seguro (sé que es un poco más restrictivo de lo necesario, pero ...). Las filas deben ser contiguas para que la vista funcione como se espera.np.uniqueen una matriz denp.voidretornos , aparece un error relacionado con mergesort no implementado para ese tipo. Sin embargo, funciona bien en 1.7.-0.no se comparará como igual+0., mientras que una comparación elemento por elemento sí-0.==+0.(como lo especifica el estándar de flotación ieee). Ver stackoverflow.com/questions/26782038/…Si desea evitar el gasto de memoria de convertir a una serie de tuplas u otra estructura de datos similar, puede explotar las matrices estructuradas de numpy.
El truco consiste en ver su matriz original como una matriz estructurada donde cada elemento corresponde a una fila de la matriz original. Esto no hace una copia, y es bastante eficiente.
Como un ejemplo rápido:
Para comprender lo que está sucediendo, eche un vistazo a los resultados intermedios.
Una vez que vemos las cosas como una matriz estructurada, cada elemento de la matriz es una fila en su matriz original. (Básicamente, es una estructura de datos similar a una lista de tuplas).
Una vez que ejecutamos
numpy.unique, obtendremos una matriz estructurada:Que luego debemos ver como una matriz "normal" (
_almacena el resultado del último cálculo enipython, por lo que está viendo_.view...):Y luego vuelva a formar una matriz 2D (
-1es un marcador de posición que le dice a numpy que calcule el número correcto de filas, proporcione el número de columnas):Obviamente, si quieres ser más conciso, puedes escribirlo como:
Lo que resulta en:
fuente
lexsort. Pensé que te referías a usar una lista de tuplas. Sí,lexsortes probablemente la mejor opción en este caso. Me olvidé de eso y salté a una solución demasiado compleja.np.uniquecuando lo ejecutonp.random.random(100).reshape(10,10)devuelve todos los elementos individuales únicos, pero desea las filas únicas, por lo que primero debe ponerlas en tuplas:Esa es la única forma en que veo que cambias los tipos para hacer lo que quieres, y no estoy seguro de si la iteración de la lista para cambiar a tuplas está bien con tu "no recorrer"
fuente
< 100filas por invocación. Esto describe con precisión cómo se realiza la realización de filas únicas.uniquescontiene elementos únicos. Potencialmente, no entiendo la forma esperada dearray¿podría ser más preciso aquí?uniquesestá ordenada (y, por lo tanto, es diferente de las filasarray).B = np.array([[1,2],[2,1]]); A = np.unique([tuple(row) for row in B]); print(A) = array([[1, 2],[1, 2]])np.unique funciona ordenando una matriz aplanada y luego observando si cada elemento es igual al anterior. Esto se puede hacer manualmente sin aplanar:
Este método no usa tuplas, y debería ser mucho más rápido y simple que otros métodos dados aquí.
NOTA: Una versión anterior de esto no tenía el ind justo después de un [, lo que significa que se usaron los índices incorrectos. Además, Joe Kington señala que esto hace una variedad de copias intermedias. El siguiente método genera menos, haciendo una copia ordenada y luego usando vistas de ella:
Esto es más rápido y usa menos memoria.
Además, si desea encontrar filas únicas en un ndarray independientemente de cuántas dimensiones hay en la matriz, lo siguiente funcionará:
Un problema pendiente interesante sería si quisiera ordenar / único a lo largo de un eje arbitrario de una matriz de dimensiones arbitrarias, algo que sería más difícil.
Editar:
Para demostrar las diferencias de velocidad, ejecuté algunas pruebas en ipython de los tres métodos diferentes descritos en las respuestas. Con su a exacta, no hay demasiada diferencia, aunque esta versión es un poco más rápida:
Sin embargo, con una versión más grande, esta versión termina siendo mucho, mucho más rápida:
fuente
a[ind[1:]]es una copia, etc.) Por otro lado, su solución es generalmente 2-3 veces más rápida que la mía hasta que se queda sin ram.dtypeen tus tiempos? Creo que te equivocaste. En mi sistema, llamarnp.uniquecomo se describe en mi respuesta es un poco más rápido que usar cualquiera de los dos tipos denp.lexsort. Y es aproximadamente 5 veces más rápido si la matriz para encontrar elementos únicos tiene forma(10000, 100). Incluso si decide volver a implementar lo quenp.uniquehace para recortar un tiempo de ejecución (menor), al colapsar cada fila en un solo objeto se realizan comparaciones más rápidas que tener que recurrirnp.anya la comparación de las columnas, especialmente para conteos de columnas más altos.dtypees justoa.dtype, es decir, el tipo de datos de los datos que se están viendo, como lo hizo Joe Kington en su respuesta. Si hay muchas columnas, otra forma (¡imperfecta!) De mantener las cosas rápidas usandolexsortes ordenar solo en unas pocas columnas. Esto es específico de los datos, ya que uno necesita saber qué columnas proporcionan suficiente variación para ordenar perfectamente. Por ejemploa.shape = (60000, 500)- más o menos en las primeras 3 columnas:ind = np.lexsort((a[:, 2], a[:, 1], a[:, 0])). El ahorro de tiempo es bastante considerable, pero nuevamente el descargo de responsabilidad: es posible que no atrape todos los casos, depende de los datos.Aquí hay otra variación para @Greg respuesta pitónica
fuente
Comparé la alternativa sugerida para la velocidad y descubrí que, sorprendentemente, la
uniquesolución de vista vacía es incluso un poco más rápida que la nativa de numpyuniquecon elaxisargumento. Si buscas velocidad, querrásCódigo para reproducir la trama:
fuente
vstack_dictnunca utiliza un dict, las llaves son una comprensión fija y, por lo tanto, su comportamiento es casi idénticovstatck_set. Dado quevstack_dictfalta la línea de rendimiento para el gráfico para, parece que solo está siendo cubierta por elvstack_setgráfico de rendimiento, ¡ya que son muy similares!vstackvariante.No me gustó ninguna de estas respuestas porque ninguna maneja matrices de punto flotante en un álgebra lineal o sentido de espacio vectorial, donde dos filas siendo "iguales" significa "dentro de algún 𝜀". La única respuesta que tiene un umbral de tolerancia, https://stackoverflow.com/a/26867764/500207 , consideró que el umbral era tanto de precisión de elementos como de precisión decimal , lo que funciona en algunos casos, pero no es tan matemáticamente general como un verdadera distancia vectorial.
Aquí está mi versión:
La función de dominio público anterior utiliza
scipy.spatial.distance.pdistpara encontrar la distancia euclidiana (personalizable) entre cada par de filas. Luego, compara cada distancia con unathreshantigua para encontrar las filas que están dentrothreshde cada una, y devuelve solo una fila de cadathreshgrupo.Como se insinuó, la distancia
metricno necesita ser euclidiana:pdistpuede calcular varias distancias, incluyendocityblock(norma de Manhattan) ycosine(el ángulo entre vectores).Si
thresh=0(el valor predeterminado), entonces las filas deben ser exactas para ser consideradas "únicas". Otros valores buenos parathreshel uso escalados máquina de precisión, es decir,thresh=np.spacing(1)*1e3.fuente
set) como representante de cadathreshvecindario de tamaño, la función podría permitir usuario para especificar cómo elegir ese punto, por ejemplo, usar la "mediana" o el punto más cercano al centroide, etc.threshgrupo sería aleatoria debido a la naturaleza desordenada deset. Por supuesto, es una idea mental de mi parte, lassettuplas de las tiendas almacenan índices que se encuentran en elthreshvecindario, por lofindRowsque, de hecho, esto devuelve, para cadathreshgrupo, la primera fila.¿Por qué no usar
drop_duplicatespandas?fuente
El paquete numpy_indexed (descargo de responsabilidad: soy su autor) envuelve la solución publicada por Jaime en una interfaz agradable y probada, además de muchas más características:
fuente
np.unique funciona dada una lista de tuplas:
Con una lista de listas plantea un
TypeError: unhashable type: 'list'fuente
Basado en la respuesta en esta página, he escrito una función que replica la capacidad de la
unique(input,'rows')función de MATLAB , con la característica adicional de aceptar tolerancia para verificar la unicidad. También devuelve los índices tales quec = data[ia,:]ydata = c[ic,:]. Informe si ve alguna discrepancia o error.fuente
Más allá de la excelente respuesta de @Jaime, otra forma de colapsar una fila es usar
a.strides[0](suponiendo queasea C-contiguo) que es igual aa.dtype.itemsize*a.shape[0]. Ademásvoid(n)es un atajo paradtype((void,n)). llegamos finalmente a esta versión más corta:por
fuente
Para fines generales como 3D o matrices anidadas multidimensionales superiores, intente esto:
que satisface su conjunto de datos 2D:
da:
Pero también matrices 3D como:
da:
fuente
uniquereturn_indexcomo hace Jaime debería simplificar esa últimareturnlínea. Simplemente indexe el originalaren el eje derecho.Ninguna de estas respuestas funcionó para mí. Supongo que mis filas únicas contenían cadenas y no números. Sin embargo, esta respuesta de otro hilo funcionó:
Fuente: https://stackoverflow.com/a/38461043/5402386
Puede usar los métodos de la lista .count () y .index ()
fuente
En realidad, podemos convertir la matriz numérica numérica mxn en una matriz de cadenas numpy mx 1, intente utilizar la siguiente función, proporciona count , inverse_idx y etc., al igual que numpy.unique:
Ejemplo:
fuente
Consigamos toda la matriz numpy como una lista, luego eliminemos los duplicados de esta lista y finalmente regresemos nuestra lista única a una matriz numpy:
fuente
La solución más sencilla es hacer que las filas sean un solo elemento convirtiéndolas en cadenas. Cada fila se puede comparar como un todo por su singularidad usando numpy. Esta solución es generalizable, solo necesita remodelar y transponer su matriz para otras combinaciones. Aquí está la solución para el problema proporcionado.
Daré:
Envía mi premio nobel por correo
fuente
fuente