Сравнение двух массивов NumPy на равенство, поэлементно

Каков самый простой способ сравнить два массива NumPy на равенство (где равенство определяется как: A = B iff для всех индексов i: A[i] == B[i])?

Простое использование == дает мне логический массив:

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

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

Мне нужно and элементы этого массива, чтобы определить, равны ли массивы, или есть более простой способ сравнения?


person clstaudt    schedule 14.05.2012    source источник


Ответы (7)


(A==B).all()

проверьте, все ли значения массива (A == B) верны.

Примечание: возможно, вы также захотите протестировать формы A и B, например A.shape == B.shape

Особые случаи и альтернативы (из ответа dbaupp и комментария yoavram)

Необходимо отметить, что:

  • это решение может иметь странное поведение в конкретном случае: если либо A, либо B пусто, а другое содержит единственный элемент, оно возвращает True. По какой-то причине сравнение A==B возвращает пустой массив, для которого оператор all возвращает True.
  • Другой риск заключается в том, что если A и B не имеют одинаковой формы и не транслируются, этот подход вызовет ошибку.

В заключение, если вы сомневаетесь в форме A и B или просто хотите обезопасить себя: воспользуйтесь одной из специализированных функций:

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
person Juh_    schedule 14.05.2012
comment
Вы почти всегда хотите np.array_equal IME. (A==B).all() приведет к сбою, если A и B имеют разную длину. Начиная с numpy 1.10, == в этом случае выдает предупреждение об устаревании. - person Wilfred Hughes; 01.07.2016
comment
У вас есть хороший аргумент, но в случае, если у меня есть сомнения по поводу формы, я обычно предпочитаю напрямую проверить ее, прежде чем значение. Тогда ошибка явно связана с формами, которые имеют совершенно другое значение, чем разные значения. Но это, вероятно, зависит от каждого варианта использования. - person Juh_; 06.08.2018
comment
другой риск - если массивы содержат nan. В этом случае вы получите False, потому что nan! = Nan - person Vincenzooo; 13.09.2018
comment
Хорошо указать на это. Однако я думаю, что это логично, потому что nan!=nan подразумевает array(nan)!=array(nan). - person Juh_; 13.09.2018
comment
Я не понимаю этого поведения: 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 - это унитарная матрица, поэтому H x H.T.conj - это единичная матрица. Но np.array_equal возвращает False - person Dex; 25.02.2019
comment
Это нужно поставить в другом вопросе. Но ответ прост, значения H * H.T.conj близки, но не равны матрице id из-за числовой точности: используйте np.allclose - person Juh_; 09.09.2019

Решение (A==B).all() очень изящное, но для этой задачи есть несколько встроенных функций. А именно array_equal, _ 3_ и _ 4_.

(Хотя некоторые быстрые тесты с timeit, похоже, указывают на то, что метод (A==B).all() является самым быстрым, что немного странно, учитывая, что он должен выделить целый новый массив.)

person huon    schedule 14.05.2012
comment
вы правы, за исключением того, что если один из сравниваемых массивов пуст, вы получите неправильный ответ с (A==B).all(). Например, попробуйте: (np.array([1])==np.array([])).all(), это дает True, а np.array_equal(np.array([1]), np.array([])) дает False - person yoavram; 17.01.2013
comment
Я только что обнаружил эту разницу в производительности. Это странно, потому что если у вас есть 2 совершенно разных массива, (a==b).all() все равно быстрее, чем np.array_equal(a, b) (который мог бы просто проверить один элемент и выйти). - person Aidan Kane; 16.01.2015
comment
np.array_equal также работает с lists of arrays и dicts of arrays. Это может быть причиной более низкой производительности. - person Bernhard; 22.06.2016
comment
Большое спасибо за функцию allclose, это то, что мне нужно для числовых вычислений. Он сравнивает равенство векторов в пределах допуска. :) - person loved.by.Jesus; 25.09.2018
comment
Обратите внимание, что np.array_equiv([1,1,1], 1) is True. Это потому, что: Согласованность формы означает, что они либо имеют одну и ту же форму, либо один входной массив может транслироваться для создания такой же формы, как и другой. - person EliadL; 26.05.2020

Если вы хотите проверить, имеют ли два массива одинаковые shape И elements, вы должны использовать np.array_equal, поскольку это метод, рекомендованный в документации.

С точки зрения производительности не ожидайте, что одна проверка на равенство превзойдет другую, поскольку для оптимизации comparing two elements не так много места. Ради интереса я еще сделал несколько тестов.

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

Так что почти равные, о скорости говорить не приходится.

(A==B).all() ведет себя примерно так же, как следующий фрагмент кода:

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

Давайте измерим производительность, используя следующий фрагмент кода.

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)

Вывод

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

Согласно приведенным выше результатам, методы numpy кажутся быстрее, чем комбинация оператора == и метода all (), и при сравнении методов numpy самый быстрый - это метод numpy.array_equal.

person funk    schedule 23.02.2016
comment
Для повышения точности эксперимента следует использовать массив большего размера, компиляция которого занимает не менее секунды. - person Vikhyat Agarwal; 06.01.2018
comment
Воспроизводится ли это также при изменении порядка сравнения? или каждый раз переустанавливая A и B в случайном порядке? Это различие также может быть объяснено кешированием в памяти ячеек A и B. - person Or Groman; 06.02.2020
comment
Значимой разницы между этими таймингами нет. - person To마SE; 11.02.2020

Обычно два массива имеют небольшие числовые ошибки,

Вы можете использовать numpy.allclose(A,B) вместо (A==B).all(). Это возвращает логическое значение True / False

person R Zhang    schedule 06.10.2019

Теперь используйте np.array_equal. Из документации:

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
person keramat    schedule 25.05.2020
comment
np.array_equal ссылка на документацию: numpy.org/doc/stable/reference/generated/ numpy.array_equal.html - person Milan; 22.03.2021

В дополнение к другим ответам теперь вы можете использовать утверждение:

numpy.testing.assert_array_equal(x, y)

У вас также есть похожая функция, например numpy.testing.assert_almost_equal()

https://numpy.org/doc/stable/reference/generated/numpy.testing.assert_array_equal.html

person Sylvain    schedule 19.04.2021