Numpy: BUG: Die Ausgabe von numpy.percentile ist nicht sortiert

Erstellt am 12. Okt. 2019  ·  16Kommentare  ·  Quelle: numpy/numpy

Die Ausgabe von numpy.percentile ist nicht immer sortiert

Beispiel für die Wiedergabe von Code:

import numpy as np
q = np.arange(0, 1, 0.01) * 100
percentile = np.percentile(np.array([0, 1, 1, 2, 2, 3, 3 , 4, 5, 5, 1, 1, 9, 9 ,9, 8, 8, 7]) * 0.1, q)
equals_sorted = np.sort(percentile) == percentile
print(equals_sorted)
assert equals_sorted.all()

Fehlermeldung:

[True True True True True True True True True True True True True True
True True True True True True True True True True True True True True
True True True True True True True True True True True True True True
True True True True True True True True True True True True True True
True True True True True True True True True True True True True True
True True True True True True True True True True True True True
True True True True True True True True True True True True True
Richtig Richtig Richtig Richtig Falsch Falsch Richtig Richtig Richtig Richtig Richtig Falsch
Richtig Richtig Richtig Falsch]
AssertionError Traceback (letzter Aufruf zuletzt)
im
1 q = np.Perzentil (np.array ([0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 1, 1, 9, 9, 9, 8, 8, 7]) * 0,1, np. Bereich (0, 1, 0,01) * 100)
2 equals_sorted = np.sort (q) == q
----> 3 assert equals_sorted.all ()

AssertionError:

Informationen zur Numpy / Python-Version:

1.17.2 3.6.8 (v3.6.8: 3c6b436a57, 24. Dezember 2018, 02.04.31)
[GCC 4.2.1 Kompatibles Apple LLVM 6.0 (clang-600.0.57)]

00 - Bug numpy.lib good first issue

Hilfreichster Kommentar

Hey, es scheint ein Update für eine der von @ eric-wieser bereitgestellten Stapelaustauschantworten mit einer guten alternativen Interpolation gegeben zu haben.
Der Thread enthält einen Beweis der Monotonie, und der vorgeschlagene Fix scheint alle genannten Probleme zu beheben.
Wenn dies für das Problem sinnvoll wäre, wäre ich bereit, dies als erstes Commit zu implementieren, oder jemand anderes könnte es versuchen.
20191209_020250

Alle 16 Kommentare

Warum würden Sie erwarten, dass es sortiert wird? Das Perzentil ist elementweise - die Ausgaben sind in der Reihenfolge der Eingaben.

Hallo !
In der Tat ist Perzentil elmenet-weise - wenn man q , was in unserem Fall der Fall ist
np.arange(0, 1, 0.01) * 100 .
Ich erwarte, dass die Ausgabe sortiert wird, da q sortiert ist.

Es gibt einige numerische Fehler innerhalb eines einzelnen ULP, die sich für verschiedene Eingänge mit demselben Ausgabewert unterscheiden. Ich bezweifle, dass etwas dagegen unternommen werden kann.

Ein leicht reduzierter Fehlerfall:

In [40]: np.percentile(np.array([0, 1, 1, 2, 2, 3, 3 , 4, 5, 5, 1, 1, 9, 9 ,9, 8, 8, 7]) * 0.1, [89, 90, 95, 96, 98, 99])
Out[40]: array([0.9, 0.9, 0.9, 0.9, 0.9, 0.9])

In [41]: np.diff(_)
Out[41]:
array([-1.11022302e-16,  2.22044605e-16, -1.11022302e-16,  1.11022302e-16,
       -1.11022302e-16])

hier zeigt die Nicht-Sortierung über das Diff.

Ich denke, wir können wahrscheinlich etwas dagegen tun. Ich denke, dies hängt von der Stabilität dieser Linien ab, die eine lerp ausführen (im Wesentlichen add(v_below*weights_below, v_above*weights_above) ):

https://github.com/numpy/numpy/blob/b9fa88eec62e34e906689408096beb2450830d9a/numpy/lib/function_base.py#L3907 -L3908

https://github.com/numpy/numpy/blob/b9fa88eec62e34e906689408096beb2450830d9a/numpy/lib/function_base.py#L3928 -L3929

https://github.com/numpy/numpy/blob/b9fa88eec62e34e906689408096beb2450830d9a/numpy/lib/function_base.py#L3939 -L3942

Bei der linearen Interpolation von Gleitkommawerten müssen einige Kompromisse eingegangen werden, aber ich vermute, dass es hier eine "richtige" Wahl gibt, und wir haben es einfach nicht geschafft.

Weitere Hintergrundinformationen finden Sie hier: https://math.stackexchange.com/questions/907327/accurate-floating-point-linear-interpolation

Ja, ich stimme zu, +1 bei der Neuorganisation der Operationen, so dass sie streng monoton (numerisch) sind. Wäre gut, wenn es auch nicht schlechter oder zumindest nahezu identisch präzise ist. Ich bin sicher, wir müssen uns hier wirklich nicht um ein paar zusätzliche Operationen / Geschwindigkeit kümmern.

EDIT: Als gute erste Ausgabe markiert. Aber danach ist dies wahrscheinlich eine ziemlich einfache Reorganisation innerhalb des Python-Codes.

Ich würde mich gerne mit diesem Thema befassen. Ich habe mir einige der fehlgeschlagenen Fälle angesehen und festgestellt, dass es sich bei allen um eine lineare Interpolation zwischen derselben Zahl handelt. dh in Erics Beispiel befinden sich alle von ihm aufgelisteten Perzentile zwischen zwei Neunern. Daher denke ich, dass die lineare Interpolation zwischen ihnen 9 genau richtig sein muss? Das Problem der linearen Interpolation zwischen zwei gleichen Zahlen zu beheben, scheint die in diesem Fehler dargestellten Probleme zu lösen und keinen spürbaren Leistungseinbruch zu verursachen. Wenn wir jedoch sicherstellen möchten, dass die lineare Interpolation immer monoton ist, können wir dies tun, aber es wird eine stückweise Funktion erforderlich sein, von der ich denke, dass sie die Leistung verringern würde.

@ ngonzo95 Es sollte eine Möglichkeit geben, die Arithmetik der Interpolation anders zu buchstabieren, um dies zu erreichen, dh die für die Berechnung verwendete Formel zu ändern / neu

Es sollte keine stückweise Berechnung erforderlich sein.

Es hängt davon ab, welche Anforderungen Sie an lerp stellen. Einige, die uns vielleicht interessieren oder nicht:

  • monoton ( (lerp(a, b, t1) - lerp(a, b, t0)) * (b - a) * (t1 - t0) >= 0 )
  • begrenzt ( a <= lerp(a, b, t) <= b )
  • symmetrisch ( lerp(a, b, t) == lerp(b, a, 1-t) )

( 0 <= t <= 1 )

Oh, OK, ich hatte nicht erwartet, dass stückweise notwendig sein würde, aber ich kenne die Besonderheiten davon nicht gut genug, denke ich.

Bei näherer Betrachtung stellte ich fest, dass die Funktion a + (ba) * t die Eigenschaft hat, sowohl monoton (Definition oben angegeben) als auch konsistent (lerp (a, a, t) = a) zu sein. Ich glaube, dies sollte für die Funktionsanforderungen ausreichen. Es scheint, dass einer der Hauptnachteile dieser Funktion darin besteht, dass lerp (a, b, 1)! = B. Ich denke jedoch, dass die Art und Weise, wie wir Gewichte berechnen, sicherstellt, dass 0 <= t <1 ist.

Es scheint, dass einer der Hauptnachteile dieser Funktion darin besteht, dass lerp (a, b, 1)! = B. Ich denke jedoch, dass die Art und Weise, wie wir Gewichte berechnen, sicherstellt, dass 0 <= t <1 ist.

Beachten Sie, dass mit dieser Formulierung leider lerp(a, b. 1-eps) > b) möglich ist.

Neu bei Open Source.
Wollte dies als mein gutes erstes Problem lösen. Wie kann ich dazu beitragen? Gibt es irgendwelche Voraussetzungen?

Ich habe mir einige der fehlgeschlagenen Fälle angesehen und festgestellt, dass es sich bei allen um eine lineare Interpolation zwischen derselben Zahl handelt

Beim Scikit-Lernen sind wir kürzlich auf diese Ausgabe gestoßen: https://github.com/scikit-learn/scikit-learn/issues/15733

Da wir davon ausgehen, dass q streng zunimmt, können wir np.maximum.accumulate anwenden, um das Array neu zu ordnen. Wenn wir das Problem jedoch direkt in NumPy lösen könnten, wäre dies großartig. Gibt es irgendwo etwas, in das wir uns vertiefen können, um eine gute Lösung zu finden?

@glemaitre : Alle relevanten Zeilen in numpy sind in meinem obigen Kommentar unter https://github.com/numpy/numpy/issues/14685#issuecomment -541467915 verlinkt

Hey, es scheint ein Update für eine der von @ eric-wieser bereitgestellten Stapelaustauschantworten mit einer guten alternativen Interpolation gegeben zu haben.
Der Thread enthält einen Beweis der Monotonie, und der vorgeschlagene Fix scheint alle genannten Probleme zu beheben.
Wenn dies für das Problem sinnvoll wäre, wäre ich bereit, dies als erstes Commit zu implementieren, oder jemand anderes könnte es versuchen.
20191209_020250

Beachten Sie, dass es ein weiteres Problem mit lerp in quantile() : inf-Werte werden nicht korrekt behandelt, siehe # 12282.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen