Frage

sorted([2, float('nan'), 1]) kehrt zurück [2, nan, 1]

(Zumindest bei Aktivität Python 3.1 Implementierung.)

Ich verstehe nan ist ein seltsames Objekt, also wäre ich nicht überrascht, wenn es an zufälligen Orten im Sortierergebnis auftaucht. Aber es macht auch die Sorte für die Nicht-Nan-Zahlen im Container durcheinander, was wirklich unerwartet ist.

Ich fragte a Verwandte Frage um max, und basierend darauf verstehe ich warum sort funktioniert so. Aber sollte dies als Fehler angesehen werden?

Die Dokumentation sagt nur "eine neue sortierte Liste zurückgeben [...], ohne Details anzugeben.

Bearbeiten: Ich stimme jetzt zu, dass dies nicht gegen den IEEE -Standard verstößt. Ich denke, es ist jedoch ein Fehler aus dem gesunden Menschenverstand. Sogar Microsoft, der nicht bekannt ist, dass sie ihre Fehler oft zugeben, hat diesen als Fehler erkannt und in der neuesten Version behoben: http://connect.microsoft.com/visualstudio/feedback/details/363379/bug-in-list-double-sort-in-list-which-contains-double-nan.

Wie auch immer, ich folgte @Khachiks Antwort:

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

Ich vermute, dass es im Vergleich zu der Sprache, die dies standardmäßig tut, zu einem Leistungstreffer führt, aber zumindest funktioniert es (abgesehen von den von mir eingeführten Fehlern).

War es hilfreich?

Lösung

Die vorherigen Antworten sind nützlich, aber vielleicht nicht klar in Bezug auf die Wurzel des Problems.

In jeder Sprache wendet die Sortierung eine bestimmte Bestellung an, die durch eine Vergleichsfunktion oder auf andere Weise über die Domäne der Eingabewerte definiert wird. Zum Beispiel weniger als, auch bekannt als operator <, könnte überall verwendet werden, wenn weniger als eine geeignete Bestellung über die Eingangswerte definiert.

Dies gilt jedoch nicht für schwimmende Punktwerte und weniger als: "Nan ist nicht ordnungsgemäß: Es ist nicht gleich, größer als alles andere, einschließlich sich selbst." (Klare Prosa aus GNU C -Handbuch, gilt aber für alle modernen IEEE754 basierend schwimmender Punkt)

Die möglichen Lösungen sind also:

  1. Entfernen Sie zuerst die NANS und machen Sie die Eingangsdomäne gut definiert über <(oder die andere Sortierfunktion, die verwendet wird).
  2. Definieren Sie eine benutzerdefinierte Vergleichsfunktion (auch bekannt als Prädikat), die eine Bestellung für NAN definiert, z. B. weniger als eine beliebige Anzahl oder größer als eine beliebige Zahl.

Bei jedem Ansatz kann in jeder Sprache verwendet werden.

In Anbetracht von Python würde ich praktisch die NANS bevorzugen, wenn Sie sich entweder nicht viel für die schnellste Leistung interessieren oder wenn das Entfernen von NANS ein gewünschtes Verhalten im Kontext ist.

Andernfalls könnten Sie eine geeignete Prädikatfunktion über "CMP" in älteren Python -Versionen oder über diese und und und über diese und verwenden functools.cmp_to_key(). Letzteres ist natürlich etwas unangenehmer, als zuerst die Nans zu entfernen. Und Sorgfalt wird erforderlich sein, um zu vermeiden schlechter Leistung, bei der Definition dieser Prädikatfunktion.

Andere Tipps

Das Problem ist, dass es keine korrekte Reihenfolge gibt, wenn die Liste eine Nan enthält, da eine Sequenz A1, A2, A3, ..., A sortiert wird, wenn a1 <= a2 <= a3 <= ... <= an. Wenn einer von diesen A -Werten eine Nan ist, dann bricht die sortierte Eigenschaft, da für alle a <= nan und nan <= a beide falsch sind.

Ich bin mir nicht sicher über den Fehler, aber die Problemumgehung kann Folgendes sein:

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

was in ... endet:

('nan', 1, 2)

Oder entfernen nans vor dem Sortieren oder etwas anderes.

IEEE754 ist der Standard, der in diesem Fall Gleitkommaoperationen definiert. Dieser Standard definiert den Vergleich der Operanden, von denen mindestens einer ein Nan ist, als Fehler. Daher ist dies kein Fehler. Sie müssen sich mit den NANs befassen, bevor Sie in Ihrem Array arbeiten.

Angenommen, Sie möchten die Nans behalten und sie als die niedrigsten "Werte" bestellen, ist hier eine Problemumgehung, die beides funktioniert Nicht eindeutiger Nan, Einzigartige Numpy Nan, numerisch und nicht numerisch Objekte:

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']
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top