Comparando duas matrizes numpy para conformidade com duas condições

Aug 18 2020

Considere duas matrizes numpy com a mesma forma, A e B, compostas por 1s e 0s. Um pequeno exemplo é mostrado:

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]]

Agora quero atribuir valores às duas variáveis ​​booleanas test1 e test2 da seguinte maneira:

test1 : Há pelo menos uma instância em que 1 em uma Acoluna e 1 na mesma Bcoluna têm diferenças de linha de exatamente 1 ou 2? Se sim, então test1 = True, caso contrário, False.

No exemplo acima, a coluna 0 de ambas as matrizes tem 1s com 2 linhas de distância, então test1 = True. (também há outras instâncias na coluna 2, mas isso não importa - exigimos apenas uma instância.)

test2 : Os valores 1 em Ae Btodos têm endereços de array diferentes? Em caso afirmativo, test2 = True, caso contrário, False.

No exemplo acima, ambos os arrays têm [4,3] = 1, portanto, test2 = False.

Estou lutando para encontrar uma maneira eficiente de fazer isso e gostaria de receber alguma ajuda.

Respostas

1 MadPhysicist Aug 18 2020 at 09:53

Esta é uma maneira simples de testar se duas matrizes têm uma entrada separada por um elemento na mesma coluna (apenas em uma direção):

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

Então você pode fazer

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

O segundo teste pode ser feito convertendo os locais em índices, empilhando-os e usando np.uniquepara contar o número de duplicatas. As duplicatas só podem vir do mesmo índice em dois arrays, pois um array nunca terá índices duplicados. Podemos acelerar ainda mais o cálculo usando em flatnonzerovez de nonzero:

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

Um teste mais eficiente seria usado de np.intersect1dmaneira semelhante:

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

Você pode usar masked_arrays e para a segunda tarefa você pode fazer:

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

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

E uma maneira ingênua de fazer a primeira tarefa é:

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())

resultado:

True
True
ArundeepChohan Aug 18 2020 at 09:56

Para Test2: Você pode apenas verificar se eles encontraram algum índice semelhante para um 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))