Comparando duas matrizes NumPy para igualdade, em termos de elementos

252

Qual é a maneira mais simples de comparar duas matrizes NumPy para igualdade (onde igualdade é definida como: A = B iff para todos os índices i:) A[i] == B[i]?

Simplesmente usar ==me fornece uma matriz booleana:

 >>> numpy.array([1,1,1]) == numpy.array([1,1,1])

array([ True,  True,  True], dtype=bool)

Preciso anddos elementos dessa matriz para determinar se as matrizes são iguais ou se há uma maneira mais simples de comparar?

clstaudt
fonte

Respostas:

379
(A==B).all()

teste se todos os valores da matriz (A == B) são True.

Nota: talvez você também queira testar as formas A e B, como A.shape == B.shape

Casos e alternativas especiais (da resposta do dbaupp e do comentário do yoavram)

Note-se que:

  • Essa solução pode ter um comportamento estranho em um caso específico: se um Aou Bestá vazio e o outro contém um único elemento, então ele retorna True. Por algum motivo, a comparação A==Bretorna uma matriz vazia, para a qual o alloperador retorna True.
  • Outro risco é se Ae Bnão têm a mesma forma e não são irradiável, então esta abordagem irá gerar um erro.

Concluindo, se você tiver alguma dúvida Ae Bforme ou simplesmente deseja estar seguro: use uma das funções especializadas:

np.array_equal(A,B)  # test if same shape, same elements values
np.array_equiv(A,B)  # test if broadcastable shape, same elements values
np.allclose(A,B,...) # test if same shape, elements have close enough values
Juh_
fonte
26
Você quase sempre quer np.array_equalIME. (A==B).all()irá falhar se A e B têm diferentes comprimentos . A partir do numpy 1.10, == gera um aviso de descontinuação neste caso .
Wilfred Hughes
Você tem um bom argumento, mas no caso de eu ter uma dúvida sobre a forma, geralmente prefiro testá-lo diretamente, antes do valor. Então, o erro está claramente nas formas que têm um significado completamente diferente do que ter valores diferentes. Mas isso provavelmente depende de cada caso de uso
Juh_ 06/08/19
2
outro risco é se as matrizes contiverem nan. Nesse caso, você obterá False porque nan! = Nan #
Vincenzooo
1
É bom ressaltar. No entanto, acho que isso é lógico, porque nan!=nanimplica isso array(nan)!=array(nan).
Juh_
Eu não entendo esse comportamento: import numpy as np H = 1/np.sqrt(2)*np.array([[1, 1], [1, -1]]) #hadamard matrix np.array_equal(H.dot(H.T.conj()), np.eye(len(H))) # checking if H is an unitary matrix or not H é uma matriz unitária, então H x H.T.conjé uma matriz de identidade. Mas np.array_equalretorna False
Dex
91

A (A==B).all()solução é muito elegante, mas existem algumas funções internas para esta tarefa. Ou seja array_equal, allclosee array_equiv.

(Embora alguns testes rápidos timeitpareçam indicar que o (A==B).all()método é o mais rápido, o que é um pouco peculiar, já que ele precisa alocar uma matriz totalmente nova).

huon
fonte
15
você está certo, exceto que se uma das matrizes comparadas estiver vazia, você receberá a resposta errada (A==B).all(). Por exemplo, tente (np.array([1])==np.array([])).all()Truenp.array_equal(np.array([1]), np.array([]))False
:,
1
Acabei de descobrir essa diferença de desempenho também. É estranho, porque se você tiver duas matrizes completamente diferentes, (a==b).all()ainda será mais rápido do que np.array_equal(a, b)(o que poderia ter verificado apenas um elemento e ter sido encerrado).
Aidan Kane
np.array_equaltambém trabalha com lists of arrayse dicts of arrays. Isso pode ser um motivo para um desempenho mais lento.
Bernhard
Muito obrigado pela função allclose, era disso que eu precisava para cálculos numéricos . Ele compara a igualdade de vetores dentro de uma tolerância . :)
loved.by.Jesus
Note isso np.array_equiv([1,1,1], 1) is True. Isso ocorre porque: Forma consistente significa que eles têm a mesma forma ou uma matriz de entrada pode ser transmitida para criar a mesma forma que a outra.
EliadL
13

Vamos medir o desempenho usando o seguinte trecho de código.

import numpy as np
import time

exec_time0 = []
exec_time1 = []
exec_time2 = []

sizeOfArray = 5000
numOfIterations = 200

for i in xrange(numOfIterations):

    A = np.random.randint(0,255,(sizeOfArray,sizeOfArray))
    B = np.random.randint(0,255,(sizeOfArray,sizeOfArray))

    a = time.clock() 
    res = (A==B).all()
    b = time.clock()
    exec_time0.append( b - a )

    a = time.clock() 
    res = np.array_equal(A,B)
    b = time.clock()
    exec_time1.append( b - a )

    a = time.clock() 
    res = np.array_equiv(A,B)
    b = time.clock()
    exec_time2.append( b - a )

print 'Method: (A==B).all(),       ', np.mean(exec_time0)
print 'Method: np.array_equal(A,B),', np.mean(exec_time1)
print 'Method: np.array_equiv(A,B),', np.mean(exec_time2)

Resultado

Method: (A==B).all(),        0.03031857
Method: np.array_equal(A,B), 0.030025185
Method: np.array_equiv(A,B), 0.030141515

De acordo com os resultados acima, os métodos numpy parecem ser mais rápidos que a combinação do operador == e o método all () e, comparando os métodos numpy, o mais rápido parece ser o método numpy.array_equal .

funk
fonte
4
Você deve usar um tamanho de matriz maior que leve pelo menos um segundo para compilar para aumentar a precisão do experimento.
Vikhyat Agarwal
Isso também se reproduz quando a ordem de comparação é alterada? ou reiniciar A e B para aleatoriamente cada vez? Essa diferença também pode ser explicada pelo armazenamento em cache de memória das células A e B.
Ou Groman
3
Não há diferença significativa entre esses horários.
Para SE
13

Se você deseja verificar se duas matrizes têm o mesmo shapeAND, elementsvocê deve usá- np.array_equallo, pois é o método recomendado na documentação.

Em termos de desempenho, não espere que nenhuma verificação de igualdade supere outra, pois não há muito espaço para otimizar comparing two elements. Só por uma questão, eu ainda fiz alguns testes.

import numpy as np
import timeit

A = np.zeros((300, 300, 3))
B = np.zeros((300, 300, 3))
C = np.ones((300, 300, 3))

timeit.timeit(stmt='(A==B).all()', setup='from __main__ import A, B', number=10**5)
timeit.timeit(stmt='np.array_equal(A, B)', setup='from __main__ import A, B, np', number=10**5)
timeit.timeit(stmt='np.array_equiv(A, B)', setup='from __main__ import A, B, np', number=10**5)
> 51.5094
> 52.555
> 52.761

Tão praticamente igual, não há necessidade de falar sobre a velocidade.

O (A==B).all()comportamento se comporta praticamente como o seguinte trecho de código:

x = [1,2,3]
y = [1,2,3]
print all([x[i]==y[i] for i in range(len(x))])
> True
user1767754
fonte
5

Normalmente, duas matrizes apresentam pequenos erros numéricos,

Você pode usar numpy.allclose(A,B), em vez de (A==B).all(). Isso retorna um booleano Verdadeiro / Falso

R Zhang
fonte
0

Agora use np.array_equal. Da documentação:

np.array_equal([1, 2], [1, 2])
True
np.array_equal(np.array([1, 2]), np.array([1, 2]))
True
np.array_equal([1, 2], [1, 2, 3])
False
np.array_equal([1, 2], [1, 4])
False
keramat
fonte