Número: comparación de elementos en dos matrices
Pregunta
¿Alguien se ha topado con este problema? Digamos que tienes dos matrices como las siguientes
a = array([1,2,3,4,5,6])
b = array([1,4,5])
¿Hay una manera de comparar qué elementos en a existen 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 siglos con millones de elementos. ¿Algunas ideas?
Saludos
Solución
En realidad, hay una solución aún más simple que cualquiera de estas:
import numpy as np
a = array([1,2,3,4,5,6])
b = array([1,4,5])
c = np.in1d(a,b)
La c resultante es entonces:
array([ True, False, False, True, True, False], dtype=bool)
Otros consejos
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 incorrecta si a o b tienen elementos no únicos. En ese caso usar np.intersect1d_nu.
También hay np.setdiff1d, setxor1d, setmember1d y union1d. Ver Lista de ejemplos desiguales con Doc
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 proceso un tanto engorroso, pero es mejor que escribir bucles o usar el tejido con bucles.
Saludos
Numpy tiene una función de conjunto numpy.setmember1d () que funciona en arreglos ordenados y sin etiquetar y devuelve exactamente el arreglo booleano que desea. Si las matrices de entrada no coinciden con los criterios, deberá convertirlos 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 realmente ineficiente. El método de búsqueda ordenado y de asignación que propuso funciona más rápido, pero si puede asignarlo directamente, también puede asignarlo directamente al resultado y evitar una gran cantidad de copias innecesarias. También su método fallará si b contiene algo que no esté en a. Lo siguiente 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 esto en 91us vs. 6.6ms para su aproximación y 109ms para numpy setmember1d en 1M elemento a y 100 elemento b.
ebresset, su respuesta no funcionará a menos que a es un subconjunto de b (y a y b están ordenados). De lo contrario, el resultado de la búsqueda devolverá índices falsos. Tuve que hacer algo similar, y combinando eso con tu 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)
Su ejemplo implica un comportamiento similar a un conjunto, preocupándose más por la existencia de en la matriz que por 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 elementos en el lugar exacto correcto. ¿Puedes hacer que eso 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)