2009-10-23 34 views
37

¿Alguna vez se ha enfrentado a este problema? Digamos que usted tiene dos matrices como las siguientesNumPy: Comparación de elementos en dos matrices

a = array([1,2,3,4,5,6]) 
b = array([1,4,5]) 

¿Hay una manera de comparar qué elementos en un existir en B? Por ejemplo,

c = a == b # Wishful example here 
print c 
array([1,4,5]) 
# Or even better 
array([True, False, False, True, True, False]) 

Estoy tratando de evitar los bucles, ya que llevaría años con millones de elementos. ¿Algunas ideas?

Saludos

+0

¿Qué datos tienes en las matrices? ¿Números únicos como índices como el ejemplo? – u0b34a0f6ae

Respuesta

47

En realidad, hay una solución aún más simple que cualquiera de estos:

import numpy as np 

a = array([1,2,3,4,5,6]) 
b = array([1,4,5]) 

c = np.in1d(a,b) 

El c resultante es entonces:

array([ True, False, False, True, True, False], dtype=bool) 
+6

¿Hay una versión "casi_equal" de esto? ¿Dónde puede especificar la condición utilizada para evaluar la igualdad? – endolith

-2

Su ejemplo implica establecen similar comportamiento, preocuparse más por existencia en la matriz de tener el elemento correcto en el lugar correcto. Numpy hace esto de manera diferente con sus matrices y matrices matemáticas, solo le informará sobre los artículos en el lugar exacto. ¿Puedes hacer que funcione para ti?

>>> import numpy 
>>> a = numpy.array([1,2,3]) 
>>> b = numpy.array([1,3,3]) 
>>> a == b 
array([ True, False, True], dtype=bool) 
+0

lo siento, este ejemplo no funciona si lo intentas; además, tendrías que ordenar las matrices primero. – dalloliogm

+0

@dalloligom: Uh, copié de mi sesión interactiva así que al menos funciona exactamente así para algunas versiones de Python y Numpy. – u0b34a0f6ae

+0

bien, pero no funciona si las dos matrices tienen diferente longitud; en cualquier caso, debe ordenarlos primero (pruebe array ([1,2,3]) == array ([2,3,1]). Quiere saber qué elementos de una matriz existen en otra. – dalloliogm

2

Gracias por su respuesta kaizer.se. No es exactamente lo que estaba buscando, pero con una sugerencia de un amigo y lo que dijiste, se me ocurrió lo siguiente.

import numpy as np 

a = np.array([1,4,5]).astype(np.float32) 
b = np.arange(10).astype(np.float32) 

# Assigning matching values from a in b as np.nan 
b[b.searchsorted(a)] = np.nan 

# Now generating Boolean arrays 
match = np.isnan(b) 
nonmatch = match == False 

Es un poco de un proceso engorroso, pero es mejor que escribir bucles o el uso de tejido con bucles.

Saludos

+0

Problema con este enfoque es que devuelve índices incluso para valores en 'a' que no existen en' b' (así como en índices duplicados en otros casos). Por ejemplo: 'numpy.searchsorted ([1, 2], [1.2, 1.3 ]) 'devuelve' [1, 1] 'que no es adecuado para el OP. – sirfz

2

Numpy tiene una numpy.setmember1d función set() que funciona en arreglos ordenados y uniqued y devuelve exactamente la matriz booleana que desee. Si las matrices de entrada no coinciden con los criterios, deberá convertir al formato establecido e invertir la transformación en el resultado.

import numpy as np 
a = np.array([6,1,2,3,4,5,6]) 
b = np.array([1,4,5]) 

# convert to the uniqued form 
a_set, a_inv = np.unique1d(a, return_inverse=True) 
b_set = np.unique1d(b) 
# calculate matching elements 
matches = np.setmea_set, b_set) 
# invert the transformation 
result = matches[a_inv] 
print(result) 
# [False True False False True True False] 

Editar: Desafortunadamente el método setmember1d en numpy es muy ineficiente. El método de búsqueda ordenado y asignación que ha propuesto funciona más rápido, pero si puede asignarlo directamente, también puede asignarlo directamente al resultado y evitar muchas copias innecesarias. También su método fallará si b contiene algo que no está en a. A continuación se corrige esos errores:

result = np.zeros(a.shape, dtype=np.bool) 
idxs = a.searchsorted(b) 
idxs = idxs[np.where(idxs < a.shape[0])] # Filter out out of range values 
idxs = idxs[np.where(a[idxs] == b)] # Filter out where there isn't an actual match 
result[idxs] = True 
print(result) 

Mis puntos de referencia muestran en esta 91us 6,6 ms vs. para su enfoque y 109ms para setmember1d numpy en 1M elemento a elemento y 100 b.

+0

Es una buena solución. Voy a probar su sugerencia y lo que acabo de escribir para ver qué es lo más óptimo en velocidad. Muchas gracias a todos por su ¡Ayuda! – ebressert

+0

El método que escribí es un poco más rápido. Para una matriz de elementos de 10000, el tiempo que llevó usar timeit en iPython es de aproximadamente 3 μs. ethod tomó 3 ms. Creo que tu método es más elegante, pero necesito la velocidad. – ebressert

+0

olvidó cerrar un paréntesis en la 3ra línea. deberías arreglarlo antes de que algún profesor de informática lo note ... – dalloliogm

18

Utilice np.intersect1d.

#!/usr/bin/env python 
import numpy as np 
a = np.array([1,2,3,4,5,6]) 
b = np.array([1,4,5]) 
c=np.intersect1d(a,b) 
print(c) 
# [1 4 5] 

Tenga en cuenta que np.intersect1d da la respuesta equivocada si aob tienen elementos no únicos. En ese caso, use np.intersect1d_nu.

También hay np.setdiff1d, setxor1d, setmember1d y union1d. Ver Numpy Example List With Doc

+0

+1: excelente. La función correcta para esta tarea. – tom10

0

ebresset, your answer no funcionará a menos que a sea un subconjunto de b (y a y b estén ordenados). De lo contrario, searchsorted arrojará índices falsos.Tenía que hacer algo similar, y la combinación de que con su código:

# Assume a and b are sorted 
idxs = numpy.mod(b.searchsorted(a),len(b)) 
idxs = idxs[b[idxs]==a] 
b[idxs] = numpy.nan 
match = numpy.isnan(b) 
Cuestiones relacionadas