Сравнение массивов 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 иногда может быть полезно, чтобы получить поведение, которое вы хотите в некотором тесте. (Но не используйте это в производственном коде или с большими массивами!)