Pregunta Python: índices de intersección numpy array


¿Cómo puedo obtener los índices de los puntos de intersección entre dos matrices numpy? Puedo obtener valores que se cruzan con intersect1d:

import numpy as np

a = np.array(xrange(11))
b = np.array([2, 7, 10])
inter = np.intersect1d(a, b)
# inter == array([ 2,  7, 10])

Pero, ¿cómo puedo obtener los índices en a de los valores en inter?


32
2017-07-14 12:47


origen


Respuestas:


Puede usar la matriz booleana producida por in1d para indexar una arange. Inversión a para que los índices sean diferentes de los valores:

>>> a[::-1]
array([10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0])
>>> a = a[::-1]

intersect1d todavía devuelve los mismos valores ...

>>> numpy.intersect1d(a, b)
array([ 2,  7, 10])

Pero in1d devuelve una matriz booleana:

>>> numpy.in1d(a, b)
array([ True, False, False,  True, False, False, False, False,  True,
       False, False], dtype=bool)

Que se puede usar para indexar un rango:

>>> numpy.arange(a.shape[0])[numpy.in1d(a, b)]
array([0, 3, 8])
>>> indices = numpy.arange(a.shape[0])[numpy.in1d(a, b)]
>>> a[indices]
array([10,  7,  2])

Para simplificar lo anterior, sin embargo, podrías usar nonzero - este es probablemente el enfoque más correcto, porque devuelve una tupla de listas uniformes de X, Y... coordenadas:

>>> numpy.nonzero(numpy.in1d(a, b))
(array([0, 3, 8]),)

O equivalente:

>>> numpy.in1d(a, b).nonzero()
(array([0, 3, 8]),)

El resultado se puede usar como un índice para matrices de la misma forma que a sin problemas

>>> a[numpy.nonzero(numpy.in1d(a, b))]
array([10,  7,  2])

Pero tenga en cuenta que, en muchas circunstancias, tiene sentido utilizar solo la matriz booleana, en lugar de convertirla en un conjunto de índices no booleanos.

Finalmente, también puede pasar la matriz booleana a argwhere, que produce un resultado de forma ligeramente diferente que no es tan adecuado para la indexación, pero podría ser útil para otros fines.

>>> numpy.argwhere(numpy.in1d(a, b))
array([[0],
       [3],
       [8]])

36
2017-07-14 12:59



Si necesita obtener valores únicos como los dados por intersect1d:

import numpy as np

a = np.array([range(11,21), range(11,21)]).reshape(20)
b = np.array([12, 17, 20])
print(np.intersect1d(a,b))
#unique values

inter = np.in1d(a, b)
print(a[inter])
#you can see these values are not unique

indices=np.array(range(len(a)))[inter]
#These are the non-unique indices

_,unique=np.unique(a[inter], return_index=True)

uniqueIndices=indices[unique]
#this grabs the unique indices

print(uniqueIndices)
print(a[uniqueIndices])
#now they are unique as you would get from np.intersect1d()

Salida:

[12 17 20]
[12 17 20 12 17 20]
[1 6 9]
[12 17 20]

2
2017-09-20 21:47



por Python >= 3.5, hay otra solución para hacerlo

Otra solución

Vamos a seguir paso a paso.

Basado en el código original de la pregunta

import numpy as np

a = np.array(range(11))
b = np.array([2, 7, 10])
inter = np.intersect1d(a, b)

Primero, creamos una matriz numpy con ceros

c = np.zeros(len(a))
print (c)
>>> [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]

En segundo lugar, cambie el valor de matriz de c usando el índice de intersección. Por lo tanto, tenemos

c[inter] = 1
print (c)
>>>[ 0.  0.  1.  0.  0.  0.  0.  1.  0.  0.  1.]

El último paso, usa la característica de np.nonzero(), devolverá exactamente el índice del término distinto de cero que desee.

inter_with_idx = np.nonzero(c)
print (inter_with_idx)
>>>array([ 2, 7, 10])

Referencia

[1] numpy.nonzero 


0
2018-01-17 09:30