Bagaimana cara menghitung persentil dengan python / numpy?


214

Apakah ada cara yang mudah untuk menghitung persentil untuk urutan atau array numpy satu dimensi?

Saya mencari sesuatu yang mirip dengan fungsi persentil Excel.

Saya mencari referensi statistik NumPy, dan tidak dapat menemukan ini. Yang bisa saya temukan adalah median (persentil ke-50), tetapi bukan sesuatu yang lebih spesifik.


Pertanyaan terkait tentang perhitungan persentil dari frekuensi: stackoverflow.com/questions/25070086/…
newtover

Jawaban:


282

Anda mungkin tertarik dengan paket SciPy Stats . Ini memiliki fungsi persentil yang Anda cari dan banyak barang statistik lainnya.

percentile() tersedia di numpyjuga.

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

Tiket ini membuat saya percaya bahwa mereka tidak akan berintegrasi percentile()dengan numpy dalam waktu dekat.


2
Terima kasih! Jadi disitulah tempat persembunyiannya. Saya sadar akan hal yang cerdik tetapi saya kira saya mengasumsikan hal-hal sederhana seperti persentil akan dibangun menjadi numpy.
Uri

16
Sekarang, fungsi persentil ada di numpy: docs.scipy.org/doc/numpy/reference/generated/…
Anaphory

1
Anda dapat menggunakannya sebagai fungsi agregasi juga, misalnya untuk menghitung persepuluh persepuluh dari setiap kelompok kolom nilai dengan kunci, gunakandf.groupby('key')[['value']].agg(lambda g: np.percentile(g, 10))
patricksurry

1
Perhatikan bahwa SciPy merekomendasikan untuk menggunakan np.percentile untuk NumPy 1.9 dan lebih tinggi
timdiels

73

Ngomong-ngomong, ada implementasi Python murni dari fungsi persentil , kalau-kalau seseorang tidak mau bergantung pada Scipy. Fungsi ini disalin di bawah:

## {{{ 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/ }}}

54
Saya penulis resep di atas. Seorang komentator di ASPN telah menunjukkan kode asli memiliki bug. Rumusnya harus d0 = kunci (N [int (f)]) * (ck); d1 = kunci (N [int (c)]) * (kf). Telah diperbaiki pada ASPN.
Wai Yip Tung

1
Bagaimana cara percentilemengetahui untuk apa N? Itu tidak ditentukan dalam panggilan fungsi.
Richard

14
bagi mereka yang bahkan tidak membaca kode, sebelum menggunakannya, N harus disortir
kevin

Saya bingung dengan ekspresi lambda. Apa yang dilakukan dan bagaimana cara melakukannya? Saya tahu apa ekspresi lambda, jadi saya tidak bertanya apa itu lambda. Saya bertanya apa yang dilakukan ekspresi lambda spesifik ini dan bagaimana melakukannya, langkah demi langkah? Terima kasih!
dsanchez

Fungsi lambda memungkinkan Anda mengubah data Nsebelum menghitung persentil. Katakanlah Anda benar-benar memiliki daftar tupel N = [(1, 2), (3, 1), ..., (5, 1)]dan Anda ingin mendapatkan persentil dari elemen pertama tupel, lalu Anda pilih key=lambda x: x[0]. Anda juga bisa menerapkan beberapa transformasi (perubahan urutan) ke elemen daftar sebelum menghitung persentil.
Elias Strehle

26
import numpy as np
a = [154, 400, 1124, 82, 94, 108]
print np.percentile(a,95) # gives the 95th percentile

19

Berikut cara melakukannya tanpa numpy, hanya menggunakan python untuk menghitung persentil.

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)

2
Ya, Anda harus mengurutkan daftar sebelumnya: mylist = diurutkan (...)
Ashkan

12

Definisi persentil yang biasanya saya lihat mengharapkan sebagai akibatnya nilai dari daftar yang disediakan di bawah P nilai-nilai yang ditemukan ... yang berarti hasilnya harus dari himpunan, bukan interpolasi antara elemen himpunan. Untuk mendapatkannya, Anda bisa menggunakan fungsi yang lebih sederhana.

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

Jika Anda lebih suka mendapatkan nilai dari daftar yang disediakan di atau di bawah P persen nilai yang ditemukan, maka gunakan modifikasi sederhana ini:

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

Atau dengan penyederhanaan yang disarankan oleh @ijustlovemath:

def percentile(N, P):
    n = max(int(round(P * len(N) + 0.5)), 2)
    return N[n-2]

terima kasih, saya juga mengharapkan persentil / median untuk menghasilkan nilai aktual dari set dan bukan interpolasi
hansaplast

1
Hai @mpounsett. Terima kasih atas kodenya. Mengapa persentil Anda selalu mengembalikan nilai integer? Fungsi persentil harus mengembalikan persentil ke-N dari daftar nilai, dan ini bisa menjadi angka float juga. Sebagai contoh, Excel PERCENTILEmengembalikan fungsi persentil berikut untuk contoh bagian atas: 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
Itu dijelaskan dalam kalimat pertama. Definisi persentil yang lebih umum adalah bahwa itu adalah angka dalam seri di mana P persen nilai dalam seri tersebut ditemukan. Karena itu adalah nomor indeks dari suatu item dalam daftar, itu tidak bisa berupa pelampung.
mpounsett

Ini tidak berfungsi untuk persentil ke-0. Ini mengembalikan nilai maksimum. Sebuah perbaikan cepat akan membungkus n = int(...)dalam max(int(...), 1)fungsi
ijustlovemath

Untuk memperjelas, maksud Anda dalam contoh kedua? Saya mendapatkan 0 daripada nilai maksimum. Bug ini sebenarnya ada di klausa lain .. Saya mencetak nomor indeks daripada nilai yang saya maksudkan. Membungkus penugasan 'n' dalam panggilan maks () juga akan memperbaikinya, tetapi Anda ingin nilai kedua menjadi 2, bukan 1. Anda kemudian dapat menghilangkan seluruh struktur if / else dan hanya mencetak hasil N [n-2]. Persentil 0 berfungsi dengan baik dalam contoh pertama, masing-masing mengembalikan '1' dan '15'.
mpounsett

8

Mulai Python 3.8, perpustakaan standar dilengkapi dengan quantilesfungsi sebagai bagian dari statisticsmodul:

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

quantilesmengembalikan untuk distribusi yang diberikan distdaftar n - 1titik potong yang memisahkan ninterval kuantil (pembagian distmenjadi ninterval kontinu dengan probabilitas yang sama):

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

di mana n, dalam kasus kami ( percentiles) adalah 100.


6

periksa modul scipy.stats:

 scipy.stats.scoreatpercentile

2

Untuk menghitung persentil suatu seri, jalankan:

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

Sebagai contoh:

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}

1

Jika Anda membutuhkan jawaban untuk menjadi anggota array numpy input:

Hanya untuk menambahkan bahwa fungsi persentil dalam numpy secara default menghitung output sebagai rata-rata tertimbang linear dari dua entri yang berdekatan dalam vektor input. Dalam beberapa kasus orang mungkin ingin persentil yang dikembalikan menjadi elemen aktual dari vektor, dalam hal ini, dari v1.9.0 dan seterusnya Anda dapat menggunakan opsi "interpolasi", dengan pilihan "lebih rendah", "lebih tinggi" atau "terdekat".

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

Yang terakhir adalah entri aktual dalam vektor, sedangkan yang pertama adalah interpolasi linier dari dua entri vektor yang membatasi persentil


0

untuk seri: digunakan menggambarkan fungsi

misalkan Anda memiliki df dengan kolom penjualan dan id berikut. Anda ingin menghitung persentil untuk penjualan maka berfungsi seperti ini,

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

0

Cara yang nyaman untuk menghitung persentil untuk urutan atau matriks numpy satu dimensi adalah dengan menggunakan numpy.percentile < https://docs.scipy.org/doc/numpy/reference/generated/numpy.percentile.html >. Contoh:

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

Namun, jika ada nilai NaN dalam data Anda, fungsi di atas tidak akan berguna. Fungsi yang disarankan untuk digunakan dalam kasus itu adalah fungsi 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

Dalam dua opsi yang disajikan di atas, Anda masih dapat memilih mode interpolasi. Ikuti contoh di bawah ini untuk memudahkan pemahaman.

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

Jika array input Anda hanya terdiri dari nilai integer, Anda mungkin tertarik pada jawaban persentil sebagai integer. Jika demikian, pilih mode interpolasi seperti 'lebih rendah', 'lebih tinggi', atau 'terdekat'.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.