Сравнение массивов numpy, содержащих NaN

Для моего юнит-теста я хочу проверить, идентичны ли два массива. Сокращенный пример:

a = np.array([1, 2, np.NaN])
b = np.array([1, 2, np.NaN])
if np.all(a==b):
    print 'arrays are equal'

Это не работает, потому что nan != nan. Каков наилучший способ продолжить?

Ответ 1

В качестве альтернативы вы можете использовать numpy.testing.assert_equal или numpy.testing.assert_array_equal с a try/except:

In : import numpy as np

In : def nan_equal(a,b):
...:     try:
...:         np.testing.assert_equal(a,b)
...:     except AssertionError:
...:         return False
...:     return True

In : a=np.array([1, 2, np.NaN])

In : b=np.array([1, 2, np.NaN])

In : nan_equal(a,b)
Out: True

In : a=np.array([1, 2, np.NaN])

In : b=np.array([3, 2, np.NaN])

In : nan_equal(a,b)
Out: False

Edit

Поскольку вы используете это для unittesting, голый assert (вместо того, чтобы обертывать его, чтобы получить True/False), может быть более естественным.

Ответ 2

Я не уверен, что это лучший способ продолжить, но это способ:

>>> ((a == b) | (numpy.isnan(a) & numpy.isnan(b))).all()
True

Ответ 3

Самый простой способ - использовать метод numpy.allclose(), который позволяет указывать поведение при значениях nan. Тогда ваш пример будет выглядеть следующим образом:

a = np.array([1, 2, np.nan])
b = np.array([1, 2, np.nan])

if np.allclose(a, b, equal_nan=True):
    print 'arrays are equal'

Затем будет напечатан arrays are equal.

Вы можете найти здесь соответствующую документацию

Ответ 4

Вы можете использовать массивы с маской в ​​маске, замаскировать значения NaN, а затем использовать numpy.ma.all или numpy.ma.allclose:

http://docs.scipy.org/doc/numpy/reference/generated/numpy.ma.all.html

http://docs.scipy.org/doc/numpy/reference/generated/numpy.ma.allclose.html

Например:

a=np.array([1, 2, np.NaN])
b=np.array([1, 2, np.NaN])
np.ma.all(np.ma.masked_invalid(a) == np.ma.masked_invalid(b)) #True

Ответ 5

Когда я использовал приведенный выше ответ:

 ((a == b) | (numpy.isnan(a) & numpy.isnan(b))).all()

Он дал мне несколько эров при оценке списка строк.

Это более общий тип:

def EQUAL(a,b):
    return ((a == b) | ((a != a) & (b != b)))

Ответ 6

Если вы делаете это для таких вещей, как модульные тесты, поэтому вам не очень важны производительность и "правильное" поведение для всех типов, вы можете использовать это для того, чтобы работать со всеми типами массивов, а не только с числовыми:

a = np.array(['a', 'b', None])
b = np.array(['a', 'b', None])
assert list(a) == list(b)

ndarray к list s иногда может быть полезно, чтобы получить поведение, которое вы хотите в некотором тесте. (Но не используйте это в производственном коде или с большими массивами!)