Numpy: Perzentilmethoden umstrukturieren

Erstellt am 12. März 2018  ·  53Kommentare  ·  Quelle: numpy/numpy

Wie auf der Wikipedia-Seite veranschaulicht: https://en.wikipedia.org/wiki/Percentile#The_nearest -rank_method

00 - Bug 01 - Enhancement high

Alle 53 Kommentare

Ich denke das gibt es schon? Verwenden Sie das Wikipedia-Beispiel:

>>> np.percentile(15, 20, 35, 40, 50], [5, 30, 40, 50, 100], interpolation='lower')
array([15, 20, 20, 35, 50])

Es tut nicht. Schauen Sie sich Beispiel 2 auf der Wikipedia-Seite an:

>>> np.percentile([3, 6, 7, 8, 8, 10, 13, 15, 16, 20], [25,50,75,100], interpolation='lower')
array([ 7,  8, 13, 20])

Wann sollte es [7,8,15,20]

Im dritten Beispiel schlägt dies ebenfalls fehl

Am nächsten klingt viel nach "am nächsten"? Es gibt jedoch immer einen anderen Punkt darüber, wie genau die Grenzen funktionieren.
EDIT: Das heißt, wo genau werden 0 und 100 am Datenpunkt oder vor dem Datenpunkt betrachtet? (das ist IIRC, jedenfalls gibt es hier viele nervige Komplexitäten)

Ich möchte es nicht lesen, ich denke, der Unterschied könnte der C-Parameter weiter unten sein. Wenn also jemand, der das weiß, dies hinzufügen möchte ...

Ehrlich gesagt denke ich, dass das Hinzufügen des C-Parameters wahrscheinlich wirklich gut wäre. Aber meistens wäre eine bessere Dokumentation nett, und jemand, der dieses Zeug wirklich kennt, wird gebraucht ...

Ich weiß nicht, ob dies etwas mit dem C-Parameter zu tun hat, obwohl ich der Meinung bin, dass die Option zur Auswahl wünschenswert sein könnte.

Ich habe einen anderen Thread gefunden , der dieses Problem übrigens angesprochen hat (Dez. 2016). Es scheint, dass der Algorithmus, nach dem ich suche (und den Wikipedia als nächsten Rang bezeichnet), in diesem häufig zitierten Artikel von Hyndman-Fan (H & F) als die älteste und am besten untersuchte Definition von Perzentil erwähnt wird (es war die, in der ich gelernt habe Statistik natürlich). Es ist eine diskontinuierliche Funktion, daher denke ich, dass der Parameter C hier nicht gilt (ich kann mich irren).

Hier ist, wie es gegen die anderen von numpy bereitgestellten Optionen aussehen würde, die intuitiv eine ähnliche Sache zu berechnen scheinen (dh 'niedriger', 'am nächsten'):

percentiles

Für mich sieht es auf den ersten Blick genauso aus wie der C-Parameter. Die nächste Kurve ist stärker gestreckt als die H & F-Kurve, was erwartet wird, da numpy 1 und anscheinend H & F 0 verwendet.

Wenn Sie Beweise wollen. Wiederholen Sie das Ganze mit den gleichen Werten, die 1000 Mal wiederholt wurden. Ich vermute, sie werden konvergieren.
EDIT: Oder vielleicht auch nicht, haben Sie nicht die Geduld oder Zeit, um wirklich darüber nachzudenken. Aber ich denke immer noch, dass es der C-Parameter ist, den Wikipedia erwähnt, also beweise mich bitte falsch :)

Ein solches Diagramm wäre eine großartige Ergänzung zu den Perzentildokumenten

edit: vorzugsweise eine, die die Offenheit / Geschlossenheit der Diskontinuitäten zeigt

Hinweis für Leser: Um diesen Thread überschaubar zu halten, habe ich alle nachfolgenden Diskussionen zum Hinzufügen dieses Diagramms zu den Dokumenten als "behoben" markiert. Das Diagramm befindet sich jetzt am Ende von https://numpy.org/devdocs/reference/generated/numpy.percentile.html.

@ Eric-Wieser Es macht mir nichts aus, diese Grafik zu machen. Ich werde später heute mit etwas zurückkommen, sollte ich es hier posten?

@seberg Ich werde hier ehrlich sein, ich weiß nicht, wie die Interpolation basierend auf dem C-Parameter berechnet wird. Was mich denken lässt, dass es nicht verwandt ist, ist, dass der C-Parameter nur im Abschnitt über lineare Interpolation (Wikipedia) diskutiert wird, und sowohl in Wikipedia als auch in Hyndmand & Fan wird der Algorithmus, den ich angefordert habe, in separaten Abschnitten von den Interpolationsabschnitten diskutiert.

Ich weiß nicht, ob es Interpolationsparameter gibt, die immer die gleichen Ergebnisse liefern wie der Algorithmus, an dem ich interessiert bin.

Selbst wenn ja, sollte dies der Weg sein, um dorthin zu gelangen? Das Ändern eines "seltsamen" Parameters, um die häufigste Definition des Perzentils zu erhalten, scheint nicht der beste Weg zu sein, um es imho zu implementieren.

@ ricardoV94 , vielleicht, aber Sie können nicht einfach die

In den C-Parametern definieren Sie 0% und 100% in Bezug auf die Datenpunkte (auf dem Datenpunkt oder nicht usw.). Als Parameter C auf Wikipedia kann es durchaus nur zur Interpolation sein, aber das gleiche Problem verursacht hier den Unterschied, da bin ich mir sicher. C ist natürlich zweifelhaft, ein Eigenname könnte so etwas wie range = 'min-max' oder range = 'extrapolated' oder wahrscheinlich etwas völlig anderes sein. Wie gesagt, wiederholen Sie die Diagramme mit vielen, vielen Datenpunkten (möglicherweise mit winzigem Rauschen), und ich denke, Sie werden sehen, wie sie konvergieren, da die Bereichsdefinition weniger offensichtlich wird.

@seberg Mir geht es gut mit method = "H & K" oder vielleicht method = "classic". Interpolation = "keine" könnte auch Sinn machen.

Ich bin mir nicht sicher, wie der Mechanismus zum Einfügen von Bildern in die Dokumente aussieht oder ob es einen Präzedenzfall dafür gibt.

Ich weiß, dass Sie Matplotlib-Code in den Dokumenten ausführen können, wie wir es an anderer Stelle tun - was auch sicherstellt, dass er mit der Realität synchronisiert bleibt.

Okay, ich werde in diesem Fall an das beste Code-Image denken.

Der problematischste Teil sind die offenen, geschlossenen Marker für Diskontinuität, da matplotlib dafür keine eingebaute Funktion hat (afaik). Eine harte Codierung würde in diesem Fall wenig Sinn machen.

Vielleicht überspringen Sie diese dann erstmal. Es wäre schön, wenn matplotlib diese automatisch unterstützen würde.

Hoffentlich hat jemand einen besseren Vorschlag, der in Bezug auf die Diskontinuität immer noch elegant ist.

import matplotlib.pyplot as plt

a = [0,1,2,3]
p = np.arange(101)

plt.step(p, np.percentile(a, p, interpolation='linear'), label='linear')
plt.step(p, np.percentile(a, p, interpolation='higher'), label='higher', linestyle='--')
plt.step(p, np.percentile(a, p, interpolation='lower'), label='lower', linestyle='--')
plt.step(p, np.percentile(a, p, interpolation='nearest'), label='nearest', linestyle='-.',)
plt.step(p, np.percentile(a, p, interpolation='midpoint'), label='midpoint', linestyle='-.',)

plt.title('Interpolation methods for list: ' + str(a))
plt.xlabel('Percentile')
plt.ylabel('List item returned')
plt.yticks(a)
plt.legend()

Image

Ich denke, das interpolation = 'linear' sollte eine reguläre, nicht gestufte Linie sein, sieht aber ansonsten gut aus. Können Sie eine PR erstellen, die dies zu den Dokumenten hinzufügt?

Tatsächlich verursacht step im Allgemeinen irreführende Artefakte, daher würde ich dies gerne vermeiden. linspace(0, 100, 60) würde auch genauere Zwischenkoordinaten erzeugen

Ich habe keine Ahnung, wie man eine PR macht.

Fühlen Sie sich frei, dies mit Ihrem Konto zu tun und die vorgeschlagenen Änderungen hinzuzufügen oder zu diskutieren.

Ich denke, Sie können C mit so etwas ändern (testen Sie es an etwas). Rufen Sie die Funktion für Ihre Perzentile auf und schließen Sie sie an die Numpy-Version an (die C = 1 verwendet, was ein No-Op ist, außer das Korrigieren von gebundenen Perzentilen):

def scale_percentiles(p, num, C=0):
     """
     p : float
          percentiles to be used (within 0 and 100 inclusive)
     num : int
         number of data points.
     C : float
         parameter C, should be 0, 0.5 or 1. Numpy uses 1, matlab 0.5, H&K is 0.
     """
     p = np.asarray(p)
     fact = (num-1.+2*C)/(num-1)
     p *= fact
     p -= 0.5 * (fact-1) * 100
     p[p < 0] = 0
     p[p > 100] = 100
     return p

Und voila, mit "am nächsten" erhalten Sie Ihr "H & F" und mit linear erhalten Sie die Handlung von Wikipedia. (bis ich etwas falsch gemacht habe, aber ich bin mir ziemlich sicher, dass ich es richtig gemacht habe).

Wie gesagt, der Unterschied besteht darin, wo Sie die Datenpunkte von 0-100 (gleichmäßig) in Bezug auf den letzten Punkt platzieren. Für C = 1 setzen Sie min (Daten) auf das 0. Perzentil usw. Ich habe keine Ahnung, "was sinnvoller ist", es ist wahrscheinlich ein bisschen von der allgemeinen Ansicht. Der Name inklusive für 1 und exklusiv für 0 macht ein bisschen Sinn, denke ich (wenn Sie über den Gesamtbereich der Perzentile nachdenken, da exklusiv der mögliche Bereich außerhalb des Datenbereichs liegt). C = 1/2 ist aber auch in diesem Sinne exklusiv.

Ich würde den C-Parameter hinzufügen, aber ich möchte, dass jemand, wenn möglich, einen beschreibenden Namen findet. Ich hätte auch nichts gegen eine "Methode" oder so, um die besten Standardeinstellungen offensichtlich zu machen (Kombination aus Interpolation + C). Oder Sie entscheiden im Grunde, dass die meisten Kombinationen nie verwendet werden und nicht nützlich sind, gut dann ...

Am Ende ist mein Problem: Ich möchte, dass ein Statistiker mir sagt, welche Methoden einen Konsens haben (R hat einige Dinge, aber das letzte Mal, als jemand hierher kam, war es nur eine Kopie von R doc oder ähnlichem, ohne es in einen numpy-Kontext zu setzen Alles in allem war es für ein allgemeines Publikum nutzlos, das Zitieren von Papieren wäre hilfreicher gewesen.

Ich möchte dieses H & F-Papier nicht lesen (ehrlich gesagt sieht es auch nicht besonders gut aus), aber ich denke, Sie könnten es auch unter unterstützenden Gesichtspunkten betrachten. Die numpy "nächste" (oder eine andere) Version hat nicht die gleiche Unterstützung (in den Perzentilen) für jeden Datenpunkt, H & F hat die gleiche Unterstützung für "am nächsten" und möglicherweise für den Mittelpunkt wäre es C = 1/2, nicht sicher.
Ich wiederhole mich immer wieder, ich weiß nicht, ob ein solches Unterstützungsargument (gegen C = 1, wie es numpy verwendet) tatsächlich ein echter Grund ist.

BEARBEITEN: Der Mittelpunkt hat die gleiche Unterstützung (für den Bereich zwischen Datenpunkten, nicht für den Punkt selbst) in numpy, also mit "C = 1".

@seberg Es scheint bei mir nicht zu funktionieren. Können Sie Ihren Code veröffentlichen, der zeigt, dass er funktioniert?

Nun, ich habe das Vorzeichen in diesem Code dort oben falsch verstanden, also war es umgekehrt (C = 0 a no-op nicht C = 1):

def scale_percentiles(p, num, C=0):
     """
     p : float
          percentiles to be used (within 0 and 100 inclusive)
     num : int
         number of data points.
     C : float
         parameter C, should be 0, 0.5 or 1. Numpy uses 1, matlab 0.5, H&F is 0.
     """
     p = np.asarray(p)
     fact = (num+1.-2*C)/(num-1)
     p *= fact
     p -= 0.5 * (fact-1) * 100
     p[p < 0] = 0
     p[p > 100] = 100
     return p
plt.figure()
plt.plot(np.percentile([0, 1, 2, 3], scale_percentiles(np.linspace(0, 100, 101), 5, C=0), interpolation='nearest'))
plt.plot(np.percentile([0, 1, 2, 3], scale_percentiles(np.linspace(0, 100, 101), 5, C=1), interpolation='nearest'))
plt.figure()
plt.plot(np.percentile([15, 20, 35, 40, 50], scale_percentiles(np.linspace(0, 100, 101), 5, C=1), interpolation='linear'))
plt.plot(np.percentile([15, 20, 35, 40, 50], scale_percentiles(np.linspace(0, 100, 101), 5, C=0.5), interpolation='linear'))
plt.plot(np.percentile([15, 20, 35, 40, 50], scale_percentiles(np.linspace(0, 100, 101), 5, C=0), interpolation='linear'))

@seberg Schließen aber noch nicht da. Für a = [0,1,2,3] und percentiles = [25, 50, 75, 100] gibt np.percentile (a, scale_percentiles(percentiles, len(a), C=0), interpolation='nearest) [0, 2, 3, 3] , wenn es [0,1,2,3] .

Ich musste die Liste Perzentile dtype=np.float sonst würde Ihre Funktion einen Fehler geben, aber ich denke nicht, dass dies das Problem ist.

Die Funktion für die klassische Methode ist einfach:
Perzentil / 100 * N -> Wenn es sich um eine ganze Zahl handelt, die der Index ist, verwenden Sie die Obergrenze als Index, wenn nicht.

Trotzdem scheint das C-Argument wie erwartet zu funktionieren, sodass es implementiert werden könnte, wenn Benutzer es für die Interpolation verwenden möchten. Ich hätte immer noch gerne eine Methode = 'klassisch' oder Interpolation = 'keine', die als Wikipedia funktionieren würde.

Für das Debuggen ist dies meine hässliche, nicht numpy Implementierung der klassischen Methode:

def percentile (arr, p):
    arr = sorted(arr)

    index = p /100 * len(arr)

    # If index is a whole number, and larger than zero, subtract one unit (due to 0-based indexing)
    if index%1 < 0.0001 and index//1 > 0:
        index -= 1

    return arr[int(index)]

und eine numpythonischere:

def indexes_classic(percentiles, set_size):
    percentiles = np.asarray(percentiles)

    indexes = percentiles / 100* set_size
    indexes[np.isclose(indexes%1, 0)] -= 1
    indexes = np.asarray(indexes, dtype=np.int)
    indexes[indexes < 0] = 0
    indexes[indexes > 100] = 100

    return indexes

Diese Unterschiede klingen nach Gleitkomma- / Rundungsproblemen (die Sie
scheinen sich dessen bewusst zu sein), und vielleicht war meine Vermutung mit C = 0 falsch und du willst
C = 0,5.
Mein Punkt war zu sagen, woher der Unterschied kommt (Der "C-Parameter"
IMO, obwohl es wahrscheinlich gute Gründe gibt, viele nicht zu mögen
Kombinationen). Es sollte Ihnen keine Problemumgehung geben / implementieren.

Was die "klassische" Methode betrifft, ist mir ehrlich gesagt egal, was klassisch ist
sollte sein. Nach allem, was ich weiß, bedeutet Klassik nur "ziemlich viele"
Leute benutzen es ".

In Bezug auf die Lösung ist mein erster Eindruck "klassisch" oder was auch immer
Name, fügt nur eine weitere verwirrende Option mit einem unklaren Namen hinzu. Ich hoffe
dass diese Diskussion in die Richtung gehen könnte, tatsächlich alles zu machen
Gute (allgemeine) Optionen, die den Benutzern sauber und transparent zur Verfügung stehen
Weg. Am besten auf eine Weise, die die Leute tatsächlich verstehen könnten.

Wir können noch eine Methode hinzufügen, aber ehrlich gesagt mag ich es nur zur Hälfte. Wenn wir
Zuletzt wurden weitere Methoden hinzugefügt (ich erinnere mich nicht, was sich genau geändert hat)
schon verspätet und gehofft, dass jemand aufspringen und herausfinden würde
was wir haben sollten. Unnötig zu erwähnen, dass es nie wirklich passiert ist. Und nun
Ich versuche auf die Unterschiede hinzuweisen und zu sehen, wie es passen könnte
mit dem, was wir aktuell haben.

Mein Eindruck ist also (mit möglichen Rundungsproblemen und genau
Perzentil-Übereinstimmungen) Wir haben (wahrscheinlich zu) viele "Interpolations" -Optionen
und würde den "C-Parameter" oder was auch immer Sie es aufrufen möchten erfordern
in der Lage sein, fast alles zu tun.
Und ich würde mich sehr freuen, wenn mir jemand sagen könnte, wie das alles ist
(häufig) "Methoden" da draußen fallen in diese Kategorien, so scheint es
mehr als C = 0,0,5,1 existieren sogar und vielleicht sogar außerhalb dieser
Optionen....

Vielleicht gehe ich auf die falsche Spur, füge aber "Method1" mit einem hinzu
unklarer Name, der niemandem wirklich sagt, wie er sich von dem unterscheidet
andere Methoden scheinen mir nicht hilfreich zu sein (außer für jemanden, der
kennt zufällig schon den Namen "Method1" und sucht danach. Und
Bitte sagen Sie nicht, dass der "Klassiker" der offensichtlichste ist, den es gibt
viel zu viel Varianz bei den Implementierungen da draußen.

Eine andere Möglichkeit könnte darin bestehen, die "Interpolation" zu verwerfen, aber eine Liste zu haben
von Methoden ist auch viel weniger schön als die Andeutung einer "linearen Interpolation"
zu sagen, dass es kein Schrittverhalten ist, etc .... Und wenn wir diesen Weg gehen,
Ich möchte immer noch einen vernünftigen Überblick.

Sie müssen es nicht tun, aber wenn wir eine neue Methode hinzufügen möchten, benötigen wir eine
Weg, um es hinzuzufügen, das nicht alle noch mehr verwirrt und klar ist!

Lassen Sie es mich dann zusammenfassen:

1) Im Moment bietet numpy nur eine nützliche Methode: Interpolation = 'linear', und die anderen sind nur kleine Variationen, die von niemandem wirklich verwendet zu werden scheinen. Andere Pakete haben viel mehr relevante Optionen.

2) Das Hinzufügen der anderen Werte für C = 0 oder C = 0,5 ist für mich sinnvoll. Alle Interpolationsmethoden können in Kombination mit ihnen arbeiten, obwohl sie wahrscheinlich nie wieder verwendet werden.

3) Wenn es einer der Kombinationen zwischen Interpolationsmethoden und C-Argument gelingt, die klassische Methode zu replizieren (Referenz und Wikipedia und meine persönliche Erfahrung stimmen darin überein, dass es die am häufigsten gelehrte Methode ist), bin ich damit zufrieden. In den Dokumenten kann festgestellt werden, dass eine solche Kombination die klassische Nichtinterpolationsmethode erzeugt. Ich bin mir nicht sicher, ob dies nur auf Probleme mit der Schwebepräzision zurückzuführen ist, aber ich schätze Ihre Bemühungen, dies integrierter anzugehen!

4) Wenn keine der Combos das gleiche Ergebnis erzielt, wäre meiner Meinung nach eine andere Methode sinnvoll. Möglicherweise Interpolation = 'keine' genannt, wäre weniger verwirrend.

Zusammenfassend: Die aktuellen Optionen von numpy.percentile wirken sowohl verwirrend als auch begrenzt. Das oben erwähnte Papier bietet einen guten Überblick über andere nützliche Methoden. Zusammen mit der Wikipedia-Seite könnten sie als Ausgangspunkt für die Gestaltung eines umfassenderen und nützlicheren Satzes von Optionen für numpy.percentile dienen. Hoffentlich möchte jemand an dieser Aufgabe arbeiten.

Ist der aktuelle "nächste" in einigen Fällen sinnvoll? Wenn die Abstandsmethode ("C") oder was auch immer einen so großen Unterschied für lineare Interpolation / gebrochene Dinge macht, bin ich vielleicht nur überrascht, dass niemand dies jemals für nicht gebrochene Näherungen getan hat?! Ist ständige Unterstützung so wichtig und gibt es einen Grund, das inverse CDF-Argument für die Interpolationsmethoden zu löschen?

Combos sind nutzlos, es sei denn, sie sind verständlich und die häufig verwendeten leicht zu finden, daher bezweifle ich es. Für die Interpolation scheinen viele Optionen zu existieren (z. B. http://mathworld.wolfram.com/Quantile.html Q4 bis Q9, ich denke, die R-Dokumentation ist praktisch identisch, aber ich denke, sie ist wahrscheinlich nicht vollständig, z. B. Matlab ...) Ich habe keine Ahnung, ob sie tatsächlich alle Sinn machen;).

Die Sache ist, dass "Interpolation" zeigt, was zwischen genau definierten Punkten zu tun ist, aber es gibt viele (seltsamerweise viele) Möglichkeiten, diese Punkte zu platzieren, zumindest wenn "lineare Interpolation" verwendet wird. Es scheint also ein schlechter Ansatz zu sein, sie zu ergänzen. Sie wollten einen "nächstgelegenen Rang", der viel klingt (und im Geiste ist). Interpolation = "am nächsten", aber die Wahl der exakten "Plotposition" scheint "nicht standardisiert" zu sein, daher ist es unmöglich zu erraten und somit eine schlechte Wahl.

Dann würde ich es sogar vorziehen, alles aggressiv abzulehnen (außer wahrscheinlich linear).

Aber wenn wir ablehnen, möchte ich es zu 100% richtig machen, und das könnte etwas mehr Klarheit darüber erfordern, was existiert, was existieren sollte und was definitiv nicht existieren sollte.

ich stimme dir vollkommen zu

@ ricardoV94 : linear für den bei # 9211 vorgeschlagenen Fall des gewichteten Quantils? Es gibt dort einige Grafiken im gleichen Stil.

Vielleicht kann @ ricardoV94 es kommentieren (das wäre cool), aber ich denke, das Problem ist ziemlich orthogonal. Gewichte sind wahrscheinlich einfach Frequenzgewichte, vorausgesetzt, es gibt keine anderen vernünftig definierten Gewichte für Perzentile (ich verstehe nicht wie), es sollte keine Mehrdeutigkeit bei der Implementierung geben, aber ich weiß es nicht genau.

Sie könnten auch versuchen, josef-pkt auf diese PR zu pingen und hoffen, dass er einen kurzen Kommentar hat, ob er es für eine gute Idee / richtig hält.

Wenn jemand es von hier nehmen möchte, habe ich eine nicht optimierte Funktion geschrieben, die das berechnet
9 Perzentil / Quantil-Schätzmethoden, die von Hyndman und Fan (1996) beschrieben und auch in R verwendet wurden .

Methode 1 entspricht der in Wikipedia diskutierten "klassischen Methode des nächsten Ranges". Methode 7 entspricht der aktuellen Numpy-Implementierung (Interpolation = 'linear'). Die übrigen Methoden der Numpy-Interpolation sind nicht enthalten (und sie scheinen sowieso nicht nützlich zu sein).

def percentile(x, p, method=7):
    '''
    Compute the qth percentile of the data.

    Returns the qth percentile(s) of the array elements.

    Parameters
    ----------
    x : array_like
        Input array or object that can be converted to an array.
    p : float in range of [0,100] (or sequence of floats)
        Percentile to compute, which must be between 0 and 100 inclusive.
    method : integer in range of [1,9]
        This optional parameter specifies one of the nine sampling methods 
        discussed in Hyndman and Fan (1996). 

        Methods 1 to 3 are discontinuous:
        * Method 1: Inverse of empirical distribution function (oldest
        and most studied method).
        * Method 2: Similar to type 1 but with averaging at discontinuities.
        * Method 3: SAS definition: nearest even order statistic.

        Methods 4 to 9 are continuous and equivalent to a linear interpolation 
        between the points (pk,xk) where xk is the kth order statistic. 
        Specific expressions for pk are given below:
        * Method 4: pk=kn. Linear interpolation of the empirical cdf.
        * Method 5: pk=(k−0.5)/n. Piecewise linear function where the knots 
        are the values midway through the steps of the empirical cdf 
        (Popular amongst hydrologists, used by Mathematica?).
        * Method 6: pk=k/(n+1), thus pk=E[F(xk)]. The sample space is divided
        in n+1 regions, each with probability of 1/(n+1) on average
        (Used by Minitab and SPSS).
        * Method 7: pk=(k−1)/(n−1), thus pk=mode[F(xk)]. The sample space
        is divided into n-1 regions (This is the default method of 
        Numpy, R, S, and MS Excell).
        * Method 8: pk=(k−1/3)/(n+1/3), thus pk≈median[F(xk)]. The resulting
        estimates are approximately median-unbiased regardless of the
        distribution of x (Recommended by Hyndman and Fan (1996)).
        * Method 9: k=(k−3/8)/(n+1/4), thus pk≈F[E(xk)]if x is normal (?).
        The resulting estimates are approximately unbiased for the expected 
        order statistics if x is normally distributed (Used for normal QQ plots).

        References:
        Hyndman, R. J. and Fan, Y. (1996) Sample quantiles in statistical packages, 
        American Statistician 50, 361--365.
        Schoonjans, F., De Bacquer, D., & Schmid, P. (2011). Estimation of population
        percentiles. Epidemiology (Cambridge, Mass.), 22(5), 750.

        '''

    method = method-1    
    x = np.asarray(x)
    x.sort()
    p = np.array(p)/100

    n = x.size  
    m = [0, 0, -0.5, 0, 0.5, p, 1-p, (p+1)/3, p/4+3/8][method]

    npm = n*p+m
    j = np.floor(npm).astype(np.int)
    g = npm-j

    # Discontinuous functions
    if method < 3:
        yg0 = [0, 0.5, 0][method]
        y = np.ones(p.size)
        if method < 2:
            y[g==0] = yg0
        else:
            y[(g==0) & (j%2 == 0)] = yg0      
    # Continuous functions
    else:
        y = g

    # Adjust indexes to work with Python
    j_ = j.copy()
    j[j<=0] = 1
    j[j > n] = n
    j_[j_ < 0] = 0
    j_[j_ >= n] = n-1 

    return (1-y)* x[j-1] + y*x[j_]

Auf diese Weise können die kontinuierlichen Methoden auch effizienter implementiert werden.

def percentile_continuous(x, p, method=7):
    '''
    Compute the qth percentile of the data.

    Returns the qth percentile(s) of the array elements.

    Parameters
    ----------
    x : array_like
        Input array or object that can be converted to an array.
    p : float in range of [0,100] (or sequence of floats)
        Percentile to compute, which must be between 0 and 100 inclusive.
    method : integer in range of [4,9]
        This optional parameter specifies one of the 5 continuous sampling
        methods discussed in Hyndman and Fan (1996). 
        '''

    x = np.asarray(x)
    x.sort()
    p = np.asarray(p)/100
    n = x.size

    if method == 4:
        r = p * n
    elif method == 5:
        r = p * n + .5
    elif method == 6:
        r = p * (n+1)
    elif method == 7:
        r = p * (n-1) + 1
    elif method == 8:
        r = p * (n+1/3) + 1/3
    elif method == 9:
        r = p * (n+1/4) + 3/8

    index = np.floor(r).astype(np.int)

    # Adjust indexes to work with Python
    index_ = index.copy()
    index[index_ <= 0] = 1
    index[index_  > n] = n
    index_[index_ < 0] = 0
    index_[index_ >= n] = n-1

    i = x[index - 1]
    j = x[index_]

    return i + r%1* (j-i)

Möchte es jemand von hier nehmen? Ich bin dazu nicht qualifiziert.

Wie im vorherigen Beitrag erwähnt, scheint die aktuelle Standardimplementierung von Quantil durch numpy mit der in R übereinzustimmen.

In R :

> quantile(c(15, 20, 35, 40, 50), probs=c(0.05, 0.3, 0.4, 0.5, 1))
  5%  30%  40%  50% 100% 
  16   23   29   35   50 
> quantile(c(3, 6, 7, 8, 8, 10, 13, 15, 16, 20), probs=c(0.25, 0.5, 0.75, 1))
  25%   50%   75%  100% 
 7.25  9.00 14.50 20.00
> quantile(c(3, 6, 7, 8, 8, 9, 10, 13, 15, 16, 20), probs=c(0.25, 0.5, 0.75, 1))
 25%  50%  75% 100% 
 7.5  9.0 14.0 20.0 

In np.quantile :

>>> np.quantile([15, 20, 35, 40, 50], q=[0.05, 0.3, 0.4, 0.5, 1])
array([16., 23., 29., 35., 50.])
>>> np.quantile([3, 6, 7, 8, 8, 10, 13, 15, 16, 20], q=[0.25, 0.5, 0.75, 1])
array([ 7.25,  9.  , 14.5 , 20.  ])
>>> np.quantile([3, 6, 7, 8, 8, 9, 10, 13, 15, 16, 20], q=[0.25, 0.5, 0.75, 1])
array([ 7.5,  9. , 14. , 20. ])

die natürlich die in Wikipedia angegebenen Beispiele nicht wiedergeben:
https://en.wikipedia.org/wiki/Percentile

Wenn Sie zur R-Hilfeseite für Quantil https://www.rdocumentation.org/packages/stats/versions/3.5.0/topics/quantile gehen
Sie würden sehen, dass die R-Standardmethode (Typ 7) die Randbedingungen identisch mit denen von np.quantile festlegt: p_k = (k-1) / (n-1) , wobei n die Stichprobengröße ist und k = 1 die kleinste bezeichnet Wert, während k = n der größte ist. Dies bedeutet, dass der kleinste Wert im sortierten Array bei Quantil = 0 und der größte bei Quantil = 1 fixiert ist.

Wie bereits im vorherigen Beitrag erwähnt, können Sie die 3 Beispiele in Wikipedia mit Typ 1 reproduzieren:

> quantile(c(15, 20, 35, 40, 50), probs=c(0.05, 0.3, 0.4, 0.5, 1), type=1)
  5%  30%  40%  50% 100% 
  15   20   20   35   50 
> quantile(c(3, 6, 7, 8, 8, 10, 13, 15, 16, 20), probs=c(0.25, 0.5, 0.75, 1), type=1)
 25%  50%  75% 100% 
   7    8   15   20 
> quantile(c(3, 6, 7, 8, 8, 9, 10, 13, 15, 16, 20), probs=c(0.25, 0.5, 0.75, 1), type=1)
 25%  50%  75% 100% 
   7    9   15   20 

Das wirft einige interessante Fragen auf:

1.) Sollte der Standardwert von np.quantile den Standardwert von R.quantile verfolgen?
2.) Sollte np.quantile auf den Typ 1-Algorithmus umschalten?

Da sogar Wikipedia selbst zustimmt, dass es keine Standarddefinition für Perzentile gibt, denke ich, solange der Algorithmus solide ist und der Benutzer weiß, wie er funktioniert, ist weder (1) noch (2) so wichtig. Ich bin eher für (1), weil Python und R zwei der beliebtesten Datenanalyseplattformen sind, und es wäre schön, wenn sie sich gegenseitig überprüfen könnten. Angesichts dessen halte ich (2) für unnötig.

Ja, sowohl R als auch Numpy verwenden standardmäßig Methode 7 und sollten so beibehalten werden. Die Frage ist, ob die anderen Methoden hinzugefügt werden sollen oder nicht.

Wenn jemand Interesse ist, habe ich ein unabhängiges Modul mit den 9 - Perzentil Methoden auf, hier . Fühlen Sie sich frei, es zu verwenden oder sich an Numpy anzupassen, wenn Sie wissen, wie.

Vielen Dank an ricardoV94 .

Also habe ich nur zum Spaß eine Umfrage bei den R-Benutzern durchgeführt. Von den 20 Personen, die geantwortet haben, verwenden 20 nur die Standardmethode in quantile . Sie reichen von Masterstudenten im Bereich der öffentlichen Gesundheit bis zu Doktoranden in Statistik.

Persönlich bin ich mir nicht sicher, ob es sich für numpy lohnt, 9 verschiedene Methoden zur Berechnung des Quantils zu unterstützen. Ich denke, die meisten Benutzer werden nur die Standardeinstellung verwenden.

Für das, was es wert ist, gibt es die Funktion scipy.stats.mstats.mquantiles , die 6 der 9 Methoden (die kontinuierlichen) unterstützt, und das Dokument gibt die Verknüpfungen mit der R-Implementierung sehr explizit an.

@ Albertcthomas ah, das ist gut zu wissen. Obwohl ich denke, dass wir diese Komplexität im Idealfall ein wenig in Zahlen verbergen würden. Und wir müssen meistens die nicht zusammenhängenden Versionen IIRC reparieren. Weil diese grundsätzlich nicht die gängigsten Methoden angeben.

Ja, numpy muss diese Methoden möglicherweise nicht unbedingt unterstützen, wenn sie im scipy stats-Modul implementiert sind.

Persönlich wäre ich für eine Methode zur Berechnung des Quantils aus der verallgemeinerten Umkehrung der kumulativen Verteilungsfunktion. Die Tatsache, dass eine solche Methode nicht verfügbar ist, hat mich zu diesem Problem geführt :).

@albertcthomas Wenn Sie irgendwelche Hinweise / Kenntnisse dazu haben, sagen Sie es bitte! Wir stecken ein bisschen fest, weil es an Klarheit mangelt, was eigentlich ein guter Standard ist. Und ich denke, es ist ein ziemlich nerviges Problem.

Vor allem brauchen wir ein paar gute Standardeinstellungen. Und das bedeutet wahrscheinlich, 2-3 Methoden zu implementieren (die nicht zusammenhängenden Methoden komplett zu überarbeiten). Ich bin damit einverstanden, mehr oder komplexere Dinge zu unterstützen, aber ich würde mich freuen, wenn wir uns für einige "typische / gute" entscheiden können.

Ich würde sagen, dass die lineare Methode (aktuelle Standardeinstellung) und die Umkehrung der kumulativen Verteilungsfunktion (nach der ich gesucht habe, als ich dieses Problem erstellt habe, sowie

Und die anderen derzeit implementierten Alternativen sollten definitiv entfernt werden.

Die Umkehrung der kumulativen Verteilungsfunktion sollte definitiv hinzugefügt werden. Es ist einer der beliebtesten Schätzer eines Quantils aus einer bestimmten Stichprobe von Beobachtungen in der Statistik.

Und die anderen derzeit implementierten Alternativen sollten definitiv entfernt werden.

@ ricardoV94 sagst du das, weil weder in Wikipedia noch in der Zeitung von Hyndman und Fan auf die Alternativen verwiesen wird?

Ja, afaik sie sind in keinem anderen Paket implementiert.

Ich verstehe nicht, warum jemand diese Methoden verwenden möchte, und ihre Namen sind
auch möglicherweise irreführend.

Albert Thomas [email protected] escreveu no dia quarta, 01.02.2019
à (s) 14:18:

Und die anderen derzeit implementierten Alternativen sollten auf jeden Fall sein
entfernt.

@ ricardoV94 https://github.com/ricardoV94 sagst du das, weil
Keine der Alternativen wird in Wikipedia oder im Hyndman und erwähnt
Fanpapier?

- -
Sie erhalten dies, weil Sie erwähnt wurden.
Antworte direkt auf diese E-Mail und sieh sie dir auf GitHub an
https://github.com/numpy/numpy/issues/10736#issuecomment-450861068 oder stumm schalten
der Faden
https://github.com/notifications/unsubscribe-auth/AbpAmfUoJNk3YHOSHNeVN03Va5wtvkHQks5u_LGugaJpZM4SnVpE
.

Vielen Dank! Warum nicht eine PR öffnen, um die Umkehrung der kumulativen Verteilung als in np.percentile verfügbare Methode hinzuzufügen? Halten Sie dieses Problem offen, wenn Sie weiterhin über Alternativen diskutieren möchten (mit Ausnahme der aktuellen Standardeinstellung, die die Standardeinstellung beibehalten sollte). Wie wird mit der Abwertung in numpy umgegangen?

Einige weitere Informationen hier - Python 3.8 hat statistics.quantiles hinzugefügt - wir sollten versuchen, np.quantile einen äquivalenten Modus hinzuzufügen

Der Weg nach vorne besteht wahrscheinlich darin, ein method kwarg hinzuzufügen, das das statistics widerspiegelt, und möglicherweise 0-2 weitere hinzuzufügen (in diesem Fall wäre es gut, die ursprünglichen Autoren bei Python anzupingen). .

Ich bin mir nicht sicher, ob die Standardeinstellungen zwischen unseren und ihren übereinstimmen, was eine Schande wäre, wenn sie dies nicht tun, aber es scheint immer noch die beste Idee zu sein (und so ziemlich das, was wir sowieso im Sinn hatten). 0-2 neue "Methoden" wären ebenfalls in Ordnung. In diesem Fall wäre es gut, die Python-Statistik-Leute auf die tatsächlichen Namen zu pingen ...

PRs sehr willkommen, ich möchte, dass dies vorwärts geht, aber ich werde es in naher Zukunft nicht tun.

@ eric-wieser Ich stelle fest, dass Sie ein paar verwandte PRs ausstehen, befasst sich einer von ihnen damit?

Ich werde dies auf 1.19 verschieben, damit es kein Blocker ist. Das heißt aber nicht, dass es nicht für 1.18 repariert werden kann :)

@charris : Welche PRs hast du im Sinn?

Ich glaube leider noch keine in diese Richtung.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen