89 votes

Comparaison de tableaux numpy contenant des NaN

Pour mon unittest, je veux vérifier si deux tableaux sont identiques. Exemple réduit :

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

if np.all(a==b):
    print 'arrays are equal'

Cela ne fonctionne pas car nan != nan . Quelle est la meilleure façon de procéder ?

52voto

senderle Points 41607

Pour les versions de numpy antérieures à la 1.19, c'est probablement la meilleure approche dans les situations qui n'impliquent pas spécifiquement des tests unitaires :

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

Cependant, les versions modernes fournissent le array_equal avec un nouvel argument mot-clé, equal_nan qui correspond exactement à la situation.

Ce point a été signalé pour la première fois par flyingdutchman ; voir sa réponse ci-dessous pour plus de détails.

48voto

Avaris Points 11815

Vous pouvez également utiliser numpy.testing.assert_equal o numpy.testing.assert_array_equal avec un 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

Editar

Puisque vous l'utilisez pour l'unittesting, il est inutile d'utiliser l'option assert (au lieu de l'envelopper pour obtenir True/False ) pourrait être plus naturel.

45voto

Le moyen le plus simple est d'utiliser numpy.allclose() qui permettent de spécifier le comportement en cas de valeurs nan. Votre exemple ressemblera alors à ce qui suit :

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

Puis arrays are equal sera imprimé.

Vous pouvez trouver aquí la documentation correspondante

12voto

flyingdutchman Points 546

La fonction numpy array_equal répond parfaitement aux exigences de la question avec le equal_nan ajouté dans la version 1.19. L'exemple serait le suivant :

a = np.array([1, 2, np.NaN])
b = np.array([1, 2, np.NaN])
assert np.array_equal(a, b, equal_nan=True)

Mais attention au fait que cela ne fonctionnera pas si un élément est de type dtype object . Je ne sais pas si c'est un bug ou pas.

9voto

JoshAdel Points 15911

Vous pourriez utiliser des tableaux masqués numpy, masquer les NaN et ensuite utiliser numpy.ma.all o numpy.ma.allclose :

Par exemple :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X