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 numpy
solució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
void
tipo que une toda la fila en un solo elemento:EDITAR Añadido
np.ascontiguousarray
siguiendo 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.void
tipo 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.uint8
s y la ves comonp.uint16
s, que combina cada dos columnas en una sola, pero más flexible.np.ascontiguousarray
o 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.unique
en una matriz denp.void
retornos , 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 (
-1
es 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í,lexsort
es probablemente la mejor opción en este caso. Me olvidé de eso y salté a una solución demasiado compleja.np.unique
cuando 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
< 100
filas por invocación. Esto describe con precisión cómo se realiza la realización de filas únicas.uniques
contiene elementos únicos. Potencialmente, no entiendo la forma esperada dearray
¿podría ser más preciso aquí?uniques
está 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.dtype
en tus tiempos? Creo que te equivocaste. En mi sistema, llamarnp.unique
como 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.unique
hace 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.any
a la comparación de las columnas, especialmente para conteos de columnas más altos.dtype
es 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 usandolexsort
es 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
unique
solución de vista vacía es incluso un poco más rápida que la nativa de numpyunique
con elaxis
argumento. Si buscas velocidad, querrásCódigo para reproducir la trama:
fuente
vstack_dict
nunca utiliza un dict, las llaves son una comprensión fija y, por lo tanto, su comportamiento es casi idénticovstatck_set
. Dado quevstack_dict
falta la línea de rendimiento para el gráfico para, parece que solo está siendo cubierta por elvstack_set
gráfico de rendimiento, ¡ya que son muy similares!vstack
variante.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.pdist
para encontrar la distancia euclidiana (personalizable) entre cada par de filas. Luego, compara cada distancia con unathresh
antigua para encontrar las filas que están dentrothresh
de cada una, y devuelve solo una fila de cadathresh
grupo.Como se insinuó, la distancia
metric
no necesita ser euclidiana:pdist
puede 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 parathresh
el uso escalados máquina de precisión, es decir,thresh=np.spacing(1)*1e3
.fuente
set
) como representante de cadathresh
vecindario 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.thresh
grupo sería aleatoria debido a la naturaleza desordenada deset
. Por supuesto, es una idea mental de mi parte, lasset
tuplas de las tiendas almacenan índices que se encuentran en elthresh
vecindario, por lofindRows
que, de hecho, esto devuelve, para cadathresh
grupo, la primera fila.¿Por qué no usar
drop_duplicates
pandas?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 quea
sea 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
unique
return_index
como hace Jaime debería simplificar esa últimareturn
línea. Simplemente indexe el originalar
en 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