Wie berechne ich Perzentile mit Python / Numpy?

214

Gibt es eine bequeme Möglichkeit, Perzentile für eine Sequenz oder ein eindimensionales Numpy-Array zu berechnen?

Ich suche etwas Ähnliches wie die Perzentilfunktion von Excel.

Ich habe in NumPys Statistikreferenz nachgesehen und konnte dies nicht finden. Ich konnte nur den Median (50. Perzentil) finden, aber nichts Spezifischeres.

Uri
quelle
Eine verwandte Frage zur Berechnung von Perzentilen aus Frequenzen: stackoverflow.com/questions/25070086/…
newtover

Antworten:

282

Das SciPy Stats- Paket könnte Sie interessieren . Es hat die Perzentilfunktion, nach der Sie suchen, und viele andere statistische Extras.

percentile() ist auch in verfügbarnumpy .

import numpy as np
a = np.array([1,2,3,4,5])
p = np.percentile(a, 50) # return 50th percentile, e.g median.
print p
3.0

Dieses Ticket lässt mich glauben, dass sie sich nicht so schnell percentile()in Numpy integrieren werden.

Jon W.
quelle
2
Danke dir! Dort hat es sich also versteckt. Ich war mir von Scipy bewusst, aber ich glaube, ich nahm an, dass einfache Dinge wie Perzentile in Numpy eingebaut werden würden.
Uri
16
Inzwischen existiert eine Perzentilfunktion in numpy: docs.scipy.org/doc/numpy/reference/generated/…
Anaphory
1
Sie können es auch als Aggregationsfunktion verwenden, z. B. um das zehnte Perzentil jeder Gruppe einer Wertespalte nach Schlüssel zu berechnen. Verwenden Siedf.groupby('key')[['value']].agg(lambda g: np.percentile(g, 10))
patricksurry
1
Beachten Sie, dass SciPy empfiehlt, np.percentile für NumPy 1.9 und höher zu verwenden
timdiels
73

Übrigens gibt es eine reine Python-Implementierung der Perzentilfunktion , falls man sich nicht auf scipy verlassen möchte. Die Funktion wird unten kopiert:

## {{{ http://code.activestate.com/recipes/511478/ (r1)
import math
import functools

def percentile(N, percent, key=lambda x:x):
    """
    Find the percentile of a list of values.

    @parameter N - is a list of values. Note N MUST BE already sorted.
    @parameter percent - a float value from 0.0 to 1.0.
    @parameter key - optional key function to compute value from each element of N.

    @return - the percentile of the values
    """
    if not N:
        return None
    k = (len(N)-1) * percent
    f = math.floor(k)
    c = math.ceil(k)
    if f == c:
        return key(N[int(k)])
    d0 = key(N[int(f)]) * (c-k)
    d1 = key(N[int(c)]) * (k-f)
    return d0+d1

# median is 50th percentile.
median = functools.partial(percentile, percent=0.5)
## end of http://code.activestate.com/recipes/511478/ }}}
Boris Gorelik
quelle
53
Ich bin der Autor des obigen Rezepts. Ein Kommentator in ASPN hat darauf hingewiesen, dass der ursprüngliche Code einen Fehler aufweist. Die Formel sollte d0 = Schlüssel (N [int (f)]) * (ck) sein; d1 = Schlüssel (N [int (c)]) * (kf). Es wurde auf ASPN korrigiert.
Wai Yip Tung
1
Woher weiß man percentile, wofür man es verwenden soll N? Es ist im Funktionsaufruf nicht angegeben.
Richard
14
Für diejenigen, die den Code nicht einmal gelesen haben, bevor er verwendet wird, muss N sortiert werden
Kevin
Der Lambda-Ausdruck verwirrt mich. Was macht es und wie macht es das? Ich weiß, was Lambda-Ausdruck ist, also frage ich nicht, was Lambda ist. Ich frage, was macht dieser spezifische Lambda-Ausdruck und wie macht er das Schritt für Schritt? Vielen Dank!
Dsanchez
Mit der Lambda-Funktion können Sie die Daten transformieren, Nbevor Sie ein Perzentil berechnen. Angenommen, Sie haben tatsächlich eine Liste von Tupeln N = [(1, 2), (3, 1), ..., (5, 1)]und möchten das Perzentil des ersten Elements der Tupel erhalten, dann wählen Sie key=lambda x: x[0]. Sie können auch einige (in der Reihenfolge ändernde) Transformationen auf die Listenelemente anwenden, bevor Sie ein Perzentil berechnen.
Elias Strehle
26
import numpy as np
a = [154, 400, 1124, 82, 94, 108]
print np.percentile(a,95) # gives the 95th percentile
Richie
quelle
19

Hier erfahren Sie, wie Sie dies ohne Numpy tun, indem Sie nur Python verwenden, um das Perzentil zu berechnen.

import math

def percentile(data, percentile):
    size = len(data)
    return sorted(data)[int(math.ceil((size * percentile) / 100)) - 1]

p5 = percentile(mylist, 5)
p25 = percentile(mylist, 25)
p50 = percentile(mylist, 50)
p75 = percentile(mylist, 75)
p95 = percentile(mylist, 95)
Ashkan
quelle
2
Ja, Sie müssen die Liste vorher sortieren: mylist = sortiert (...)
Ashkan
12

Die Definition des Perzentils, die ich normalerweise sehe, erwartet als Ergebnis den Wert aus der angegebenen Liste, unter dem P Prozent der Werte gefunden werden ... was bedeutet, dass das Ergebnis aus der Menge stammen muss, nicht aus einer Interpolation zwischen Mengenelementen. Um dies zu erreichen, können Sie eine einfachere Funktion verwenden.

def percentile(N, P):
    """
    Find the percentile of a list of values

    @parameter N - A list of values.  N must be sorted.
    @parameter P - A float value from 0.0 to 1.0

    @return - The percentile of the values.
    """
    n = int(round(P * len(N) + 0.5))
    return N[n-1]

# A = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
# B = (15, 20, 35, 40, 50)
#
# print percentile(A, P=0.3)
# 4
# print percentile(A, P=0.8)
# 9
# print percentile(B, P=0.3)
# 20
# print percentile(B, P=0.8)
# 50

Wenn Sie lieber den Wert aus der angegebenen Liste erhalten möchten, bei oder unter dem P Prozent der Werte gefunden werden, verwenden Sie diese einfache Änderung:

def percentile(N, P):
    n = int(round(P * len(N) + 0.5))
    if n > 1:
        return N[n-2]
    else:
        return N[0]

Oder mit der von @ijustlovemath vorgeschlagenen Vereinfachung:

def percentile(N, P):
    n = max(int(round(P * len(N) + 0.5)), 2)
    return N[n-2]
mpounsett
quelle
danke, ich erwarte auch, dass Perzentil / Median tatsächliche Werte aus den Mengen und nicht aus Interpolationen
ergibt
1
Hallo @mpounsett. Vielen Dank für den oberen Code. Warum gibt Ihr Perzentil immer ganzzahlige Werte zurück? Die Perzentilfunktion sollte das N-te Perzentil einer Werteliste zurückgeben, und dies kann auch eine Gleitkommazahl sein. Zum Beispiel kann die Excel PERCENTILEzurückgibt Funktion folgende Perzentile für Ihre oberen Beispiele: 3.7 = percentile(A, P=0.3), 0.82 = percentile(A, P=0.8), 20 = percentile(B, P=0.3), 42 = percentile(B, P=0.8).
Marco
1
Es wird im ersten Satz erklärt. Die gebräuchlichere Definition von Perzentil ist, dass es die Zahl in einer Reihe ist, unter der P Prozent der Werte in der Reihe gefunden werden. Da dies die Indexnummer eines Elements in einer Liste ist, kann es kein Float sein.
mpounsett
Dies funktioniert nicht für das 0. Perzentil. Es gibt den Maximalwert zurück. Eine schnelle Lösung wäre, die n = int(...)in eine max(int(...), 1)Funktion zu wickeln
ijustlovemath
Meinen Sie zur Verdeutlichung das zweite Beispiel? Ich bekomme eher 0 als den Maximalwert. Der Fehler befindet sich tatsächlich in der else-Klausel. Ich habe die Indexnummer und nicht den beabsichtigten Wert gedruckt. Wenn Sie die Zuweisung von 'n' in einen max () -Aufruf einschließen, wird dies ebenfalls behoben. Sie möchten jedoch, dass der zweite Wert 2 und nicht 1 ist. Sie können dann die gesamte if / else-Struktur entfernen und einfach das Ergebnis von N drucken [n-2]. Das 0. Perzentil funktioniert im ersten Beispiel einwandfrei und gibt '1' bzw. '15' zurück.
mpounsett
8

Ab Python 3.8dem Start enthält die Standardbibliothek die folgende quantilesFunktion statistics:

from statistics import quantiles

quantiles([1, 2, 3, 4, 5], n=100)
# [0.06, 0.12, 0.18, 0.24, 0.3, 0.36, 0.42, 0.48, 0.54, 0.6, 0.66, 0.72, 0.78, 0.84, 0.9, 0.96, 1.02, 1.08, 1.14, 1.2, 1.26, 1.32, 1.38, 1.44, 1.5, 1.56, 1.62, 1.68, 1.74, 1.8, 1.86, 1.92, 1.98, 2.04, 2.1, 2.16, 2.22, 2.28, 2.34, 2.4, 2.46, 2.52, 2.58, 2.64, 2.7, 2.76, 2.82, 2.88, 2.94, 3.0, 3.06, 3.12, 3.18, 3.24, 3.3, 3.36, 3.42, 3.48, 3.54, 3.6, 3.66, 3.72, 3.78, 3.84, 3.9, 3.96, 4.02, 4.08, 4.14, 4.2, 4.26, 4.32, 4.38, 4.44, 4.5, 4.56, 4.62, 4.68, 4.74, 4.8, 4.86, 4.92, 4.98, 5.04, 5.1, 5.16, 5.22, 5.28, 5.34, 5.4, 5.46, 5.52, 5.58, 5.64, 5.7, 5.76, 5.82, 5.88, 5.94]
quantiles([1, 2, 3, 4, 5], n=100)[49] # 50th percentile (e.g median)
# 3.0

quantilesgibt für eine gegebene Verteilung disteine Liste von n - 1Schnittpunkten zurück, die die nQuantilintervalle trennen (Unterteilung distin nkontinuierliche Intervalle mit gleicher Wahrscheinlichkeit):

statistics.quantiles (dist, *, n = 4, method = 'exklusiv')

wo nin unserem Fall ( percentiles) ist 100.

Xavier Guihot
quelle
6

Überprüfen Sie das Modul scipy.stats:

 scipy.stats.scoreatpercentile
Evert
quelle
2

Führen Sie Folgendes aus, um das Perzentil einer Reihe zu berechnen:

from scipy.stats import rankdata
import numpy as np

def calc_percentile(a, method='min'):
    if isinstance(a, list):
        a = np.asarray(a)
    return rankdata(a, method=method) / float(len(a))

Beispielsweise:

a = range(20)
print {val: round(percentile, 3) for val, percentile in zip(a, calc_percentile(a))}
>>> {0: 0.05, 1: 0.1, 2: 0.15, 3: 0.2, 4: 0.25, 5: 0.3, 6: 0.35, 7: 0.4, 8: 0.45, 9: 0.5, 10: 0.55, 11: 0.6, 12: 0.65, 13: 0.7, 14: 0.75, 15: 0.8, 16: 0.85, 17: 0.9, 18: 0.95, 19: 1.0}
Roei Bahumi
quelle
1

Falls Sie die Antwort benötigen, um Mitglied des Eingabe-Numpy-Arrays zu sein:

Nur um hinzuzufügen, dass die Perzentilfunktion in numpy standardmäßig die Ausgabe als linear gewichteten Durchschnitt der beiden benachbarten Einträge im Eingabevektor berechnet. In einigen Fällen möchten Benutzer möglicherweise, dass das zurückgegebene Perzentil ein tatsächliches Element des Vektors ist. In diesem Fall können Sie ab Version 1.9.0 die Option "Interpolation" mit "niedriger", "höher" oder "am nächsten" verwenden.

import numpy as np
x=np.random.uniform(10,size=(1000))-5.0

np.percentile(x,70) # 70th percentile

2.075966046220879

np.percentile(x,70,interpolation="nearest")

2.0729677997904314

Letzteres ist ein tatsächlicher Eintrag im Vektor, während Ersteres eine lineare Interpolation von zwei Vektoreinträgen ist, die an das Perzentil grenzen

Adrian Tompkins
quelle
0

für eine Reihe: verwendet beschreiben Funktionen

Angenommen, Sie haben df mit den folgenden Spalten sales und id. Wenn Sie Perzentile für Verkäufe berechnen möchten, funktioniert dies folgendermaßen:

df['sales'].describe(percentiles = [0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1])

0.0: .0: minimum
1: maximum 
0.1 : 10th percentile and so on
Ashwini
quelle
0

Eine bequeme Methode zum Berechnen von Perzentilen für eine eindimensionale Numpy-Sequenz oder -Matrix ist die Verwendung von Numpy.percentile < https://docs.scipy.org/doc/numpy/reference/generated/numpy.percentile.html >. Beispiel:

import numpy as np

a = np.array([0,1,2,3,4,5,6,7,8,9,10])
p50 = np.percentile(a, 50) # return 50th percentile, e.g median.
p90 = np.percentile(a, 90) # return 90th percentile.
print('median = ',p50,' and p90 = ',p90) # median =  5.0  and p90 =  9.0

Wenn Ihre Daten jedoch einen NaN-Wert enthalten, ist die obige Funktion nicht hilfreich. Die empfohlene Funktion in diesem Fall ist die Funktion numpy.nanpercentile < https://docs.scipy.org/doc/numpy/reference/generated/numpy.nanpercentile.html >:

import numpy as np

a_NaN = np.array([0.,1.,2.,3.,4.,5.,6.,7.,8.,9.,10.])
a_NaN[0] = np.nan
print('a_NaN',a_NaN)
p50 = np.nanpercentile(a_NaN, 50) # return 50th percentile, e.g median.
p90 = np.nanpercentile(a_NaN, 90) # return 90th percentile.
print('median = ',p50,' and p90 = ',p90) # median =  5.5  and p90 =  9.1

In den beiden oben dargestellten Optionen können Sie weiterhin den Interpolationsmodus auswählen. Befolgen Sie zum besseren Verständnis die folgenden Beispiele.

import numpy as np

b = np.array([1,2,3,4,5,6,7,8,9,10])
print('percentiles using default interpolation')
p10 = np.percentile(b, 10) # return 10th percentile.
p50 = np.percentile(b, 50) # return 50th percentile, e.g median.
p90 = np.percentile(b, 90) # return 90th percentile.
print('p10 = ',p10,', median = ',p50,' and p90 = ',p90)
#p10 =  1.9 , median =  5.5  and p90 =  9.1

print('percentiles using interpolation = ', "linear")
p10 = np.percentile(b, 10,interpolation='linear') # return 10th percentile.
p50 = np.percentile(b, 50,interpolation='linear') # return 50th percentile, e.g median.
p90 = np.percentile(b, 90,interpolation='linear') # return 90th percentile.
print('p10 = ',p10,', median = ',p50,' and p90 = ',p90)
#p10 =  1.9 , median =  5.5  and p90 =  9.1

print('percentiles using interpolation = ', "lower")
p10 = np.percentile(b, 10,interpolation='lower') # return 10th percentile.
p50 = np.percentile(b, 50,interpolation='lower') # return 50th percentile, e.g median.
p90 = np.percentile(b, 90,interpolation='lower') # return 90th percentile.
print('p10 = ',p10,', median = ',p50,' and p90 = ',p90)
#p10 =  1 , median =  5  and p90 =  9

print('percentiles using interpolation = ', "higher")
p10 = np.percentile(b, 10,interpolation='higher') # return 10th percentile.
p50 = np.percentile(b, 50,interpolation='higher') # return 50th percentile, e.g median.
p90 = np.percentile(b, 90,interpolation='higher') # return 90th percentile.
print('p10 = ',p10,', median = ',p50,' and p90 = ',p90)
#p10 =  2 , median =  6  and p90 =  10

print('percentiles using interpolation = ', "midpoint")
p10 = np.percentile(b, 10,interpolation='midpoint') # return 10th percentile.
p50 = np.percentile(b, 50,interpolation='midpoint') # return 50th percentile, e.g median.
p90 = np.percentile(b, 90,interpolation='midpoint') # return 90th percentile.
print('p10 = ',p10,', median = ',p50,' and p90 = ',p90)
#p10 =  1.5 , median =  5.5  and p90 =  9.5

print('percentiles using interpolation = ', "nearest")
p10 = np.percentile(b, 10,interpolation='nearest') # return 10th percentile.
p50 = np.percentile(b, 50,interpolation='nearest') # return 50th percentile, e.g median.
p90 = np.percentile(b, 90,interpolation='nearest') # return 90th percentile.
print('p10 = ',p10,', median = ',p50,' and p90 = ',p90)
#p10 =  2 , median =  5  and p90 =  9

Wenn Ihr Eingabearray nur aus ganzzahligen Werten besteht, könnte Sie die Perzentilantwort als Ganzzahl interessieren. Wenn ja, wählen Sie den Interpolationsmodus wie "niedriger", "höher" oder "am nächsten".

Italo Gervasio
quelle