我如何计算百分比与python/numpy?

是否有一种方便的方法来计算一个序列或一维numpy数组的百分位数?

我正在寻找类似Excel的百分位数函数。

我在NumPy的统计参考中找不到这个。我所能找到的是中位数(第50百分位),但没有更具体的东西。

424301 次浏览

你可能会对SciPy统计数据包感兴趣。它有百分位函数你在后面和许多其他统计好东西。

percentile() 是可用的也在numpy中。

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

这张票让我相信他们不会很快将percentile()集成到numpy中。

顺便说一下,还有百分位数函数的纯python实现,以防有人不想依赖scipy。函数复制如下:

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

检查scipy。统计模块:

 scipy.stats.scoreatpercentile

我通常看到的百分位数的定义期望从所提供的列表中找到P个百分比的值…这意味着结果必须来自集合,而不是集合元素之间的插值。为此,可以使用一个更简单的函数。

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

如果你想从所提供的列表中获得等于或低于P百分比的值,那么使用以下简单的修改:

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

或者使用@ijustlovemath建议的简化:

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

下面是如何在没有numpy的情况下,仅使用python来计算百分比。

import math


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


percentile([10.0, 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0], 90)
# 9.0
percentile([142, 232, 290, 120, 274, 123, 146, 113, 272, 119, 124, 277, 207], 50)
# 146
import numpy as np
a = [154, 400, 1124, 82, 94, 108]
print np.percentile(a,95) # gives the 95th percentile

要计算一个系列的百分位数,运行:

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

例如:

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}

如果你需要答案是输入numpy数组的成员:

再加上numpy中的百分位数函数默认情况下将输出计算为输入向量中两个相邻项的线性加权平均。在某些情况下,人们可能希望返回的百分位数是向量的实际元素,在这种情况下,从v1.9.0开始,您可以使用“插值”选项,使用“低”、“高”或“最近”。

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

后者是向量中的一个实际条目,而前者是与百分位数相邻的两个向量条目的线性插值

对于系列:用于描述函数

假设df具有以下列sales和id。你想计算销售额的百分比,它是这样工作的,

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

Python 3.8开始,标准库附带quantiles函数作为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

对于给定的分布distquantiles返回一个n - 1切点列表,这些切点分隔了n分位数区间(以等概率将dist分割为n连续区间):

统计数据。分位数(dist, *, n=4, method='exclusive')

其中n,在我们的例子中(percentiles)是100

计算一维numpy序列或矩阵的百分位数的一种方便方法是使用numpy。百分位& lt; https://docs.scipy.org/doc/numpy/reference/generated/numpy.percentile.html >。例子:

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

但是,如果您的数据中有任何NaN值,则上述函数将没有用处。在这种情况下,推荐使用numpy函数。>函数:

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

在上面给出的两个选项中,您仍然可以选择插值模式。为了更容易理解,请参考下面的例子。

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

如果您的输入数组只包含整数值,那么您可能对作为整数的百分比答案感兴趣。如果是这样,选择插值模式,如'低','高',或'最近'。

我引导数据,然后绘制出10个样本的置信区间。置信区间表示概率在5%到95%之间的范围。

 import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
import json
import dc_stat_think as dcst


data = [154, 400, 1124, 82, 94, 108]
#print (np.percentile(data,[0.5,95])) # gives the 95th percentile


bs_data = dcst.draw_bs_reps(data, np.mean, size=6*10)


#print(np.reshape(bs_data,(24,6)))


x= np.linspace(1,6,6)
print(x)
for (item1,item2,item3,item4,item5,item6) in bs_data.reshape((10,6)):
line_data=[item1,item2,item3,item4,item5,item6]
ci=np.percentile(line_data,[.025,.975])
mean_avg=np.mean(line_data)
fig, ax = plt.subplots()
ax.plot(x,line_data)
ax.fill_between(x, (line_data-ci[0]), (line_data+ci[1]), color='b', alpha=.1)
ax.axhline(mean_avg,color='red')
plt.show()