Pregunta

sorted([2, float('nan'), 1]) devoluciones [2, nan, 1]

(Al menos en la implementación de activación de Python 3.1).

entiendo nan es un objeto extraño, por lo que no me sorprendería si aparece en lugares aleatorios en el resultado del tipo. Pero también arruina el tipo para los números que no son NAN en el contenedor, lo cual es realmente inesperado.

Le pregunté a un pregunta relacionada sobre max, y según eso entiendo por qué sort funciona como este. ¿Pero debería considerarse un error?

La documentación solo dice "Devuelve una nueva lista ordenada [...] sin especificar ningún detalle.

EDITAR: Ahora estoy de acuerdo en que esto no está en violación del estándar IEEE. Sin embargo, es un error desde cualquier punto de vista de sentido común, creo. Incluso Microsoft, que no se sabe que admite sus errores a menudo, ha reconocido este como un error y lo arregló en la última versión: http://connect.microsoft.com/visualstudio/feedback/details/3633379/bug-in-list-double-sort-in-list- whichhich-contains-double-nan.

De todos modos, terminé siguiendo la respuesta de @Khachik:

sorted(list_, key = lambda x : float('-inf') if math.isnan(x) else x)

Sospecho que resulta en un éxito de rendimiento en comparación con el lenguaje que lo hace de forma predeterminada, pero al menos funciona (salvo cualquier error que introduje).

¿Fue útil?

Solución

Las respuestas anteriores son útiles, pero quizás no están claras con respecto a la raíz del problema.

En cualquier idioma, el tipo de orden aplica un orden dado, definido por una función de comparación o de alguna otra manera, sobre el dominio de los valores de entrada. Por ejemplo, menos que, también conocido como operator <, podría usarse en todo momento si y solo si menos define un pedido adecuado sobre los valores de entrada.

Pero esto no es específicamente cierto para los valores de puntos flotantes y menos que: "Nan no está ordenado: no es igual a, mayor o menos que nada, incluido sí mismo". (Prosa clara del manual de gnu c, pero se aplica a todos los modernos IEEE754 establecido punto flotante)

Entonces las posibles soluciones son:

  1. Elimine primero los NANS, haciendo que el dominio de entrada sea bien definido a través de <(o la otra función de clasificación que se usa)
  2. Defina una función de comparación personalizada (también conocida como predicado) que define un orden para NAN, como menos que cualquier número, o mayor que cualquier número.

Cualquiera de los enfoques se puede usar, en cualquier idioma.

Prácticamente, teniendo en cuenta que Python, preferiría eliminar los NAN si no le importa mucho el rendimiento más rápido o si eliminar los NAN es un comportamiento deseado en contexto.

De lo contrario, puede usar una función de predicado adecuada a través de "CMP" en versiones de Python más antiguas, o a través de esto y functools.cmp_to_key(). Este último es un poco más incómodo, naturalmente, que eliminar primero a los Nans. Y se requerirá cuidado para evitar peor rendimiento, al definir esta función de predicado.

Otros consejos

El problema es que no hay un orden correcto si la lista contiene una nan, ya que una secuencia a1, a2, a3, ..., se clasifica si a1 <= a2 <= a3 <= ... <= an. Si alguno de estos valores A es un NAN, entonces la propiedad ordenada se rompe, ya que para todos A, a <= nan y nan <= a son falsos.

No estoy seguro sobre el error, pero la solución puede ser lo siguiente:

sorted(
    (2, 1, float('nan')),
    lambda x,y: x is float('nan') and -1 
                or (y is float('nan') and 1
                or cmp(x,y)))

lo que resulta en:

('nan', 1, 2)

O quitar nans antes de clasificar o cualquier otra cosa.

IEEE754 es el estándar que define las operaciones de puntos flotantes en este caso. Este estándar define la operación de comparación de operandos, al menos uno de los cuales es un NAN, para ser un error. Por lo tanto, esto no es un error. Debe lidiar con los NANS antes de operar en su matriz.

Suponiendo que desea mantener los Nans y ordenarlos como los "valores" más bajos, aquí hay una solución que funciona con tanto con nan no unique, NaN NUMPY EN, numérico y no numérico objetos:

def is_nan(x):
    return (x is np.nan or x != x)

list_ = [2, float('nan'), 'z', 1, 'a', np.nan, 4, float('nan')]
sorted(list_, key = lambda x : float('-inf') if is_nan(x) else x)
# [nan, nan, nan, 1, 2, 4, 'a', 'z']
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top