Làm cách nào để tính phần trăm với python / numpy?


214

Có cách nào thuận tiện để tính toán phần trăm cho một dãy numpy chuỗi hoặc một chiều không?

Tôi đang tìm kiếm một cái gì đó tương tự như hàm phần trăm của Excel.

Tôi đã xem tài liệu tham khảo thống kê của NumPy và không thể tìm thấy điều này. Tất cả những gì tôi có thể tìm thấy là trung vị (phân vị thứ 50), nhưng không phải là thứ gì đó cụ thể hơn.


Một câu hỏi liên quan về tính toán phân vị theo tần số: stackoverflow.com/questions/25070086/
newtover

Câu trả lời:


282

Bạn có thể quan tâm đến gói Thống kê SciPy . Nó có chức năng phân vị mà bạn theo đuổi và nhiều tính năng thống kê khác.

percentile() có sẵn trong numpyquá.

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

Tấm vé này khiến tôi tin rằng họ sẽ không hòa nhập percentile()vào bất cứ lúc nào sớm.


2
Cảm ơn bạn! Vì vậy, đó là nơi nó đang ẩn náu. Tôi đã nhận thức được scipy nhưng tôi đoán tôi đã giả định những thứ đơn giản như phần trăm sẽ được xây dựng thành numpy.
Uri

16
Đến bây giờ, một hàm phần trăm tồn tại trong numpy: docs.scipy.org/doc/numpy/reference/generated/ Kẻ
Anaphory

1
Bạn cũng có thể sử dụng nó như một hàm tổng hợp, ví dụ để tính phần trăm thứ mười của mỗi nhóm của một cột giá trị theo khóa, sử dụngdf.groupby('key')[['value']].agg(lambda g: np.percentile(g, 10))
patricksurry

1
Lưu ý rằng SciPy khuyên bạn nên sử dụng np.percentile cho NumPy 1.9 trở lên
timdiels

73

Nhân tiện, có một triển khai Python thuần túy của hàm phân vị , trong trường hợp người ta không muốn phụ thuộc vào scipy. Các chức năng được sao chép dưới đây:

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

53
Tôi là tác giả của công thức trên. Một bình luận trong ASPN đã chỉ ra mã gốc có lỗi. Công thức nên là d0 = key (N [int (f)]) * (ck); d1 = khóa (N [int (c)]) * (kf). Nó đã được sửa chữa trên ASPN.
Wai Yip Tung

1
Làm thế nào để percentilebiết những gì để sử dụng cho N? Nó không được chỉ định trong chức năng gọi.
Richard

14
Đối với những người thậm chí không đọc mã, trước khi sử dụng nó, N phải được sắp xếp
kevin

Tôi bối rối trước biểu hiện lambda. Nó làm gì và làm như thế nào? Tôi biết lambda biểu hiện là gì vì vậy tôi không hỏi lambda là gì. Tôi đang hỏi biểu thức lambda cụ thể này làm gì và làm thế nào để thực hiện nó, từng bước một? Cảm ơn!
DSanchez

Hàm lambda cho phép bạn chuyển đổi dữ liệu Ntrước khi tính phần trăm. Giả sử bạn thực sự có một danh sách các bộ dữ liệu N = [(1, 2), (3, 1), ..., (5, 1)]và bạn muốn lấy phần trăm của phần tử đầu tiên của bộ dữ liệu, sau đó bạn chọn key=lambda x: x[0]. Bạn cũng có thể áp dụng một số chuyển đổi (thay đổi thứ tự) cho các thành phần danh sách trước khi tính phần trăm.
Elias Stroundle

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

19

Dưới đây là cách thực hiện mà không cần numpy, chỉ sử dụng python để tính phần trăm.

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
Có, bạn phải sắp xếp danh sách trước: mylist = sort (...)
Ashkan

12

Định nghĩa về phân vị tôi thường thấy là kết quả của giá trị từ danh sách được cung cấp bên dưới mà phần trăm P của các giá trị được tìm thấy ... có nghĩa là kết quả phải từ tập hợp, không phải là phép nội suy giữa các phần tử tập hợp. Để có được điều đó, bạn có thể sử dụng một chức năng đơn giản hơn.

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

Nếu bạn muốn nhận giá trị từ danh sách được cung cấp tại hoặc dưới mức P phần trăm của các giá trị được tìm thấy, thì hãy sử dụng sửa đổi đơn giản này:

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

Hoặc với sự đơn giản hóa được đề xuất bởi @ijustlovemath:

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

cảm ơn, tôi cũng hy vọng phần trăm / trung vị sẽ tạo ra các giá trị thực tế từ các tập hợp chứ không phải nội suy
hansaplast

1
Xin chào @mpounsett. Cảm ơn bạn cho mã trên. Tại sao phân vị của bạn luôn trả về giá trị nguyên? Hàm phân vị sẽ trả về phân vị thứ N của danh sách các giá trị và đây cũng có thể là số nổi. Ví dụ, Excel PERCENTILEchức năng trả về percentiles sau cho ví dụ trên của bạn: 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
Nó được giải thích trong câu đầu tiên. Định nghĩa phổ biến hơn về phân vị là nó là số trong một chuỗi bên dưới mà phần trăm P của các giá trị được tìm thấy. Vì đó là số chỉ mục của một mục trong danh sách, nên nó không thể là số float.
mpounsett

Điều này không hoạt động cho phân vị thứ 0. Nó trả về giá trị tối đa. Một sửa chữa nhanh chóng sẽ là bọc n = int(...)một max(int(...), 1)chức năng
ijustlovemath

Để làm rõ, bạn có nghĩa là trong ví dụ thứ hai? Tôi nhận được 0 chứ không phải giá trị tối đa. Lỗi thực sự nằm trong mệnh đề khác .. Tôi đã in số chỉ mục chứ không phải giá trị tôi dự định. Kết thúc việc gán 'n' trong lệnh gọi max () cũng sẽ sửa nó, nhưng bạn muốn giá trị thứ hai là 2 chứ không phải 1. Sau đó, bạn có thể loại bỏ toàn bộ cấu trúc if / other và chỉ in kết quả của N [n-2]. Phân vị thứ 0 hoạt động tốt trong ví dụ đầu tiên, trả về '1' và '15' tương ứng.
mpounsett

8

Bắt đầu Python 3.8, thư viện chuẩn đi kèm với quantileschức năng như một phần của statisticsmô-đun:

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

quantilestrả về cho một phân phối nhất định distmột danh sách các n - 1điểm cắt phân tách các nkhoảng lượng tử (chia distthành ncác khoảng liên tục với xác suất bằng nhau):

stats.quantiles (dist, *, n = 4, method = 'Exclusive')

trong đó n, trong trường hợp của chúng tôi ( percentiles) là 100.


6

kiểm tra mô-đun scipy.stats:

 scipy.stats.scoreatpercentile

2

Để tính phần trăm của một chuỗi, hãy chạy:

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

Ví dụ:

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

Trong trường hợp bạn cần câu trả lời để trở thành thành viên của mảng numpy đầu vào:

Chỉ cần thêm rằng hàm phần trăm trong numpy theo mặc định sẽ tính toán đầu ra dưới dạng trung bình trọng số tuyến tính của hai mục nhập lân cận trong vectơ đầu vào. Trong một số trường hợp, mọi người có thể muốn phần trăm được trả về là một phần tử thực của vectơ, trong trường hợp này, từ v1.9.0 trở đi, bạn có thể sử dụng tùy chọn "nội suy", với "thấp hơn", "cao hơn" hoặc "gần nhất".

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

Cái sau là một mục thực tế trong vectơ, trong khi cái trước là một phép nội suy tuyến tính của hai mục vectơ giáp phần trăm


0

cho một loạt: các chức năng mô tả được sử dụng

giả sử bạn có df với các cột và doanh số cột sau đây. bạn muốn tính phần trăm cho doanh số thì nó hoạt động như thế này,

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

Một cách thuận tiện để tính toán phần trăm cho chuỗi hoặc ma trận một chiều là sử dụng numpy.percentile < https://docs.scipy.org/doc/numpy/reference/generated/numpy.percentile.html >. Thí dụ:

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

Tuy nhiên, nếu có bất kỳ giá trị NaN nào trong dữ liệu của bạn, chức năng trên sẽ không hữu ích. Hàm được đề xuất sử dụng trong trường hợp đó là hàm 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

Trong hai tùy chọn được trình bày ở trên, bạn vẫn có thể chọn chế độ nội suy. Thực hiện theo các ví dụ dưới đây để dễ hiểu hơn.

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

Nếu mảng đầu vào của bạn chỉ bao gồm các giá trị số nguyên, bạn có thể quan tâm đến câu trả lời phần trăm dưới dạng số nguyên. Nếu vậy, hãy chọn chế độ nội suy, chẳng hạn như 'thấp hơn', 'cao hơn' hoặc 'gần nhất'.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.