将数组转换为百分位数
Convert array into percentiles
我有一个要转换为百分位数的数组。例如,假设我有一个正态分布数组:
import numpy as np
import matplotlib.pyplot as plt
arr = np.random.normal(0, 1, 1000)
plt.hist(arr)
对于该数组中的每个值,我想计算该值的百分位数(例如 0 是上述分布的第 50 个百分位数,因此 0 -> 0.5)。结果应该是均匀分布的,因为每个百分位数应该具有相同的权重。
我找到了 np.percentile
但是这个函数 return 是 一个给定数组和分位数的值 而我需要的是 return 给定数组和值的分位数。
有没有比较高效的方法呢?
from scipy.stats import percentileofscore
import pandas as pd
# generate example data
arr = np.random.normal(0, 1, 10)
# pre-sort array
arr_sorted = sorted(arr)
# calculate percentiles using scipy func percentileofscore on each array element
s = pd.Series(arr)
percentiles = s.apply(lambda x: percentileofscore(arr_sorted, x))
检查结果是否正确:
df = pd.DataFrame({'data': s, 'percentiles': percentiles})
df.sort_values(by='data')
data percentiles
3 -1.692881 10.0
8 -1.395427 20.0
7 -1.162031 30.0
6 -0.568550 40.0
9 0.047298 50.0
5 0.296661 60.0
0 0.534816 70.0
4 0.542267 80.0
1 0.584766 90.0
2 1.185000 100.0
这是另一种方法。我想你问的是估计概率积分变换。这段代码产生了一个相当细粒度的估计,即 inverted_edf
.
它通过计算 SAMPLE
中不同值的点之间的线性插值来进行。然后计算样本经验df,最后inverted_edf
.
我应该提一下,即使样本量为 1,000,尾部的百分位数也会受到相当大的统计变异性的影响,尽管 0.5 的情况会更少。
import statsmodels.distributions.empirical_distribution as edf
from scipy.interpolate import interp1d
import numpy as np
import matplotlib.pyplot as plt
SAMPLE = np.random.normal(0, 1, 1000)
sample_edf = edf.ECDF(SAMPLE)
slope_changes = sorted(set(SAMPLE))
sample_edf_values_at_slope_changes = [ sample_edf(item) for item in slope_changes]
inverted_edf = interp1d(sample_edf_values_at_slope_changes, slope_changes)
x = np.linspace(0.005, 1)
y = inverted_edf(x)
#~ plt.plot(x, y, 'ro', x, y, 'b-')
plt.plot(x, y, 'b-')
plt.show()
p = 0.5
print ('%s percentile:' % (100*p), inverted_edf(p))
这是两次运行的图形和文本输出。
50.0 percentile: -0.05917394517540461
50.0 percentile: -0.0034011090849578695
下面是一段简单的代码,用于计算列表中每个元素的百分位排名。我将给定元素的百分位数定义为列表中小于或等于给定元素的元素的百分比。
import numpy as np
x = [2,3,2,110,200,55,-1,0,6,45]
ptile = [ (len(list(np.where(np.array(x)<=i)[0]))/len(x))*100 for i in x]
print (ptile)
O/P
[40.0, 50.0, 40.0, 90.0, 100.0, 80.0, 10.0, 20.0, 60.0, 70.0]
实现此目的的方法有很多种,具体取决于您要使用的库和您拥有的数据类型。
import numpy as np
# Input data
arr = np.random.normal(0, 1, 10)
在 numpy 数组上使用 scipy.stats.percentileofscore
:
from scipy import stats
np.vectorize(lambda x: stats.percentileofscore(arr, x))(arr)
在 numpy 数组或列表上使用 scipy.stats.rankdata
:
from scipy import stats
stats.rankdata(arr, "average") / len(arr)
在 Pandas DataFrame 上使用 pandas.DataFrame.rank
:
import numpy as np
df = pd.DataFrame(arr)
df.rank(pct=True)
我有一个要转换为百分位数的数组。例如,假设我有一个正态分布数组:
import numpy as np
import matplotlib.pyplot as plt
arr = np.random.normal(0, 1, 1000)
plt.hist(arr)
对于该数组中的每个值,我想计算该值的百分位数(例如 0 是上述分布的第 50 个百分位数,因此 0 -> 0.5)。结果应该是均匀分布的,因为每个百分位数应该具有相同的权重。
我找到了 np.percentile
但是这个函数 return 是 一个给定数组和分位数的值 而我需要的是 return 给定数组和值的分位数。
有没有比较高效的方法呢?
from scipy.stats import percentileofscore
import pandas as pd
# generate example data
arr = np.random.normal(0, 1, 10)
# pre-sort array
arr_sorted = sorted(arr)
# calculate percentiles using scipy func percentileofscore on each array element
s = pd.Series(arr)
percentiles = s.apply(lambda x: percentileofscore(arr_sorted, x))
检查结果是否正确:
df = pd.DataFrame({'data': s, 'percentiles': percentiles})
df.sort_values(by='data')
data percentiles
3 -1.692881 10.0
8 -1.395427 20.0
7 -1.162031 30.0
6 -0.568550 40.0
9 0.047298 50.0
5 0.296661 60.0
0 0.534816 70.0
4 0.542267 80.0
1 0.584766 90.0
2 1.185000 100.0
这是另一种方法。我想你问的是估计概率积分变换。这段代码产生了一个相当细粒度的估计,即 inverted_edf
.
它通过计算 SAMPLE
中不同值的点之间的线性插值来进行。然后计算样本经验df,最后inverted_edf
.
我应该提一下,即使样本量为 1,000,尾部的百分位数也会受到相当大的统计变异性的影响,尽管 0.5 的情况会更少。
import statsmodels.distributions.empirical_distribution as edf
from scipy.interpolate import interp1d
import numpy as np
import matplotlib.pyplot as plt
SAMPLE = np.random.normal(0, 1, 1000)
sample_edf = edf.ECDF(SAMPLE)
slope_changes = sorted(set(SAMPLE))
sample_edf_values_at_slope_changes = [ sample_edf(item) for item in slope_changes]
inverted_edf = interp1d(sample_edf_values_at_slope_changes, slope_changes)
x = np.linspace(0.005, 1)
y = inverted_edf(x)
#~ plt.plot(x, y, 'ro', x, y, 'b-')
plt.plot(x, y, 'b-')
plt.show()
p = 0.5
print ('%s percentile:' % (100*p), inverted_edf(p))
这是两次运行的图形和文本输出。
50.0 percentile: -0.05917394517540461
50.0 percentile: -0.0034011090849578695
下面是一段简单的代码,用于计算列表中每个元素的百分位排名。我将给定元素的百分位数定义为列表中小于或等于给定元素的元素的百分比。
import numpy as np
x = [2,3,2,110,200,55,-1,0,6,45]
ptile = [ (len(list(np.where(np.array(x)<=i)[0]))/len(x))*100 for i in x]
print (ptile)
O/P
[40.0, 50.0, 40.0, 90.0, 100.0, 80.0, 10.0, 20.0, 60.0, 70.0]
实现此目的的方法有很多种,具体取决于您要使用的库和您拥有的数据类型。
import numpy as np
# Input data
arr = np.random.normal(0, 1, 10)
在 numpy 数组上使用 scipy.stats.percentileofscore
:
from scipy import stats
np.vectorize(lambda x: stats.percentileofscore(arr, x))(arr)
在 numpy 数组或列表上使用 scipy.stats.rankdata
:
from scipy import stats
stats.rankdata(arr, "average") / len(arr)
在 Pandas DataFrame 上使用 pandas.DataFrame.rank
:
import numpy as np
df = pd.DataFrame(arr)
df.rank(pct=True)