column - python numpy sort
Python: la función de ordenación se rompe en presencia de nan (5)
Asumiendo que quiere mantener los NaN y ordenarlos como los "valores" más bajos, aquí hay una solución que funciona tanto con objetos no únicos como con números únicos , numéricos y no numéricos únicos :
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'']
sorted([2, float(''nan''), 1])
devuelve [2, nan, 1]
(Al menos en la implementación de Activestate Python 3.1.)
Entiendo que nan
es un objeto raro, así que no me sorprendería si aparece en lugares al azar en el resultado de la clasificación. Pero también arruina el tipo de números no nan en el contenedor, lo cual es realmente inesperado.
Hice una pregunta relacionada sobre max
, y en base a eso, entiendo por qué el sort
funciona así. Pero, ¿se debe considerar esto como un error?
La documentación solo dice "Devolver una nueva lista ordenada [...]" sin especificar ningún detalle.
EDITAR: ahora estoy de acuerdo en que esto no infringe el estándar IEEE. Sin embargo, es un error desde cualquier punto de vista de sentido común, creo. Incluso Microsoft, que no es conocido por admitir sus errores a menudo, ha reconocido este como un error y lo corrigió en la última versión: http://connect.microsoft.com/VisualStudio/feedback/details/363379/bug-in-list-double-sort-in-list-which-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 golpe de rendimiento en comparación con el idioma que lo hace de forma predeterminada, pero al menos funciona (salvo los errores que introduje).
El problema es que no hay un orden correcto si la lista contiene un NAN, ya que una secuencia a1, a2, a3, ..., an se clasifica si a1 <= a2 <= a3 <= ... <= an. Si alguno de estos valores es un NAN, la propiedad ordenada se rompe, ya que para todos a, a <= NAN y NAN <= a son ambos falsos.
IEEE754 es el estándar que define las operaciones de punto flotante en esta instancia. Este estándar define que la operación de comparación de operandos, al menos uno de los cuales es un NaN, es un error. Por lo tanto, esto no es un error. Debe tratar con los NaN antes de operar en su matriz.
Las respuestas anteriores son útiles, pero quizás no son claras con respecto a la raíz del problema.
En cualquier idioma, sort aplica un orden determinado, definido por una función de comparación o de alguna otra forma, sobre el dominio de los valores de entrada. Por ejemplo, less-than, aka operator <,
podría usarse en todo si y solo si es menor que define un orden adecuado sobre los valores de entrada.
Pero esto NO es específicamente cierto para los valores de coma flotante y menor que: "NaN no está ordenado: no es igual a, mayor que, o menor que cualquier otra cosa, incluido él mismo". ( Borrado en prosa del manual GNU C, pero se aplica a todos los modernos IEEE754
flotantes basados en IEEE754
)
Entonces las posibles soluciones son:
- elimine los NaN primero, haciendo que el dominio de entrada esté bien definido mediante <(o la otra función de clasificación que se esté usando)
- define 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 más que cualquier número.
Cualquiera de los enfoques se puede usar en cualquier idioma.
Prácticamente, considerando 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, podría usar una función de predicado adecuada a través de "cmp" en versiones anteriores de python, o mediante esto y functools.cmp_to_key()
. Esto último es un poco más incómodo, naturalmente, que eliminar primero los NaN. Y será necesario tener cuidado para evitar un peor rendimiento al definir esta función de predicado.
No estoy seguro sobre el error, pero la solución alternativa puede ser la 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 eliminar nan
s antes de ordenar o cualquier otra cosa.