Comparación de dos matrices numpy para el cumplimiento de dos condiciones

Aug 18 2020

Considere dos matrices numpy que tienen la misma forma, A y B, compuestas por unos y ceros. Se muestra un pequeño ejemplo:

A = [[1 0 0 1]         B = [[0 0 0 0]
     [0 0 1 0]              [0 0 0 0]
     [0 0 0 0]              [1 1 0 0]
     [0 0 0 0]              [0 0 1 0]
     [0 0 1 1]]             [0 1 0 1]]

Ahora quiero asignar valores a las dos variables booleanas test1 y test2 de la siguiente manera:

test1 : ¿Hay al menos una instancia en la que un 1 en una Acolumna y un 1 en la MISMA Bcolumna tengan diferencias de fila de exactamente 1 o 2? Si es así, entonces prueba1 = Verdadero, de lo contrario Falso.

En el ejemplo anterior, la columna 0 de ambas matrices tiene unos que están separados por 2 filas, por lo que test1 = True. (También hay otras instancias en la columna 2, pero eso no importa, solo requerimos una instancia).

test2 : ¿Los valores 1 de Ay Btodos tienen direcciones de matriz diferentes? Si es así, entonces prueba2 = Verdadero, de lo contrario Falso.

En el ejemplo anterior, ambas matrices tienen [4,3] = 1, entonces test2 = False.

Estoy luchando por encontrar una manera eficiente de hacer esto y agradecería alguna ayuda.

Respuestas

1 MadPhysicist Aug 18 2020 at 09:53

Aquí hay una forma sencilla de probar si dos matrices tienen una entrada con un elemento aparte en la misma columna (solo en una dirección):

(A[1:, :] * B[:-1, :]).any(axis=None)

Para que puedas hacer

test1 = (A[1:, :] * B[:-1, :] + A[:-1, :] * B[1:, :]).any(axis=None) or (A[2:, :] * B[:-2, :] + A[:-2, :] * B[2:, :]).any(axis=None)

La segunda prueba se puede realizar convirtiendo las ubicaciones en índices, apilándolos y utilizándolos np.uniquepara contar el número de duplicados. Los duplicados solo pueden provenir del mismo índice en dos matrices, ya que una matriz nunca tendrá índices duplicados. Podemos acelerar aún más el cálculo usando en flatnonzerolugar de nonzero:

test2 = np.all(np.unique(np.concatenate((np.flatnonzero(A), np.flatnonzero(B))), return_counts=True)[1] == 1)

Una prueba más eficiente usaría np.intersect1dde manera similar:

test2 = not np.intersect1d(np.flatnonzero(A), np.flatnonzero(B)).size
1 Ehsan Aug 18 2020 at 08:14

Puede usar masked_arrays y para la segunda tarea puede hacer:

A_m = np.ma.masked_equal(A, 0)
B_m = np.ma.masked_equal(B, 0)

test2 = np.any((A_m==B_m).compressed())

Y una forma ingenua de hacer la primera tarea es:

test1 = np.any((np.vstack((A_m[:-1],A_m[:-2],A_m[1:],A_m[2:]))==np.vstack((B_m[1:],B_m[2:],B_m[:-1],B_m[:-2]))).compressed())

salida:

True
True
ArundeepChohan Aug 18 2020 at 09:56

Para Test2: puede verificar si encontraron índices similares encontrados para un valor de 1.

A =  np.array([[1, 0, 0, 1],[0, 0, 1, 0],[0, 0, 0, 0],[0, 0, 0, 0],[0, 0, 1, 1]])
B = np.array([[0, 0, 0, 0],[0, 0, 0, 0],[1, 1, 0, 0],[0, 0, 1, 0],[0, 1, 0, 1]])
print(len(np.intersect1d(np.flatnonzero(A==1),np.flatnonzero(B==1)))>0))