python numpy containers nan

python - en operador, flotador("NaN") y np.nan



numpy containers (2)

Solía ​​creer que in operador en Python se comprueba la presencia del elemento en alguna colección que usa la verificación de igualdad == , por lo que el element in some_list es aproximadamente equivalente a any(x == element for x in some_list) . Por ejemplo:

True in [1, 2, 3] # True because True == 1

o

1 in [1., 2., 3.] # also True because 1 == 1.

Sin embargo, es bien sabido que NaN no es igual a sí mismo. Así que esperaba que float("NaN") in [float("NaN")] sea False . Y es False cierto.

Sin embargo, si usamos numpy.nan lugar de float("NaN") , la situación es bastante diferente:

import numpy as np np.nan in [np.nan, 1, 2] # True

Pero np.nan == np.nan todavía da False !

¿Como es posible? ¿Cuál es la diferencia entre np.nan y float("NaN") ? ¿Cómo hacer frente a np.nan ?


Para verificar si el elemento está en la lista, Python prueba primero la identidad del objeto, y luego prueba la igualdad solo si los objetos son diferentes. 1

float("NaN") in [float("NaN")] es False porque hay dos objetos NaN diferentes involucrados en la comparación. Por lo tanto, la prueba de identidad devuelve Falso, y luego la prueba de igualdad también devuelve Falso desde NaN != NaN .

np.nan in [np.nan, 1, 2] sin embargo, es verdadero porque el mismo objeto NaN está involucrado en la comparación. La prueba de identidad de objeto devuelve Verdadero, por lo que Python reconoce inmediatamente que el elemento está en la lista.

El método __contains__ (invocado usando in ) para muchos de los otros tipos de Contenedores incorporados de Python, como tuplas y conjuntos, se implementa usando la misma verificación.

1 Al menos esto es cierto en CPython. La identidad del objeto aquí significa que los objetos se encuentran en la misma dirección de memoria: el método que contiene las listas se realiza mediante PyObject_RichCompareBool que compara rápidamente los punteros del objeto antes que una comparación de objetos potencialmente más complicada. Otras implementaciones de Python pueden diferir.


Una cosa que vale la pena mencionar es que las matrices numpy se comportan como se espera:

a = np.array((np.nan,)) a[0] in a # False

Variaciones del tema:

[np.nan]==[np.nan] # True [float(''nan'')]==[float(''nan'')] # False {np.nan: 0}[np.nan] # 0 {float(''nan''): 0}[float(''nan'')] # Traceback (most recent call last): # File "<stdin>", line 1, in <module> # KeyError: nan

Todo lo demás está cubierto en la excelente respuesta de @AlexRiley.