Python - 加速查找大于阈值的集合的百分位数

时间:2016-03-04 21:26:36

标签: python cython

我需要找出一组数字中的哪个百分位超过阈值。有没有办法可以加快速度?我的实现对于预期的应用来说太慢了。如果这改变了什么,我正在使用mpirun -np 100 python program.py运行我的程序。我不能使用numba,因为这个程序的其余部分使用try / except语句。

import numpy as np
my_vals = []
threshold_val = 0.065
for i in range(60000):
    my_vals.append(np.random.normal(0.05, 0.02))

for i in np.arange(0,100,0.001):
    if np.percentile(my_vals,i) > threshold_val:
        perc = 1*i
        break
else: perc = 100

2 个答案:

答案 0 :(得分:1)

由于高斯(正态)分布产生钟形曲线,您应该能够以最高概率计算百分位数,然后编写代码以首先检查,然后使用修改后的二进制搜索来查找最佳最低门槛。

例如,如果您确定您的参数最有可能支持,例如17.951(这只是一个例子,我实际上并不打算计算它),然后开始接近那一点而不是从0开始。像二元搜索一样对待 - 将你的下限设为0,你的上限设为100.0 ,并设置点将列表二等分为分布的最佳百分位数。

如果您当前的上限超过threshold_val,则将下半部分平分,以找到匹配的最低值;如果它没有超过阈值,则将上半部分平分等等。在0.000到100.000的范围内,如果从17.951开始并发现它不高于阈值,则调整到17.952到100.000的范围并尝试58.976(中间)。一旦找到高于阈值的值,则使用该值作为上限(因为它是非最佳答案)。继续此过程,直到下限和上限相隔0.001,这将为您提供最佳答案。平均而言,您应该运行大约17次测试而不是100,000次。

如果您的正态分布发生变化,您也可以自动计算最佳值,因为分布会产生钟形曲线,并且无论如何您都会知道基于参数的钟形曲线的统计数据。

您的解决方案只需要找到百分位数高于阈值的最低值,因此这种方法应该最小化您需要检查的样本数量。

还有一个提示:np.percentile必须在代码中对my_vals进行100,000次排序;我不知道预先排序的列表是否有帮助,但是可能值得检查(您可能需要测试几个可能的排序参数,因为它似乎没有记录它排序的方向)

答案 1 :(得分:1)

您可以通过对值进行排序并搜索超过阈值的第一个值来直接找到解决方案。百分位数是此元素之前的数组值的分数:

import numpy as np
my_vals = []
threshold_val = 0.065
for i in range(60000):
    my_vals.append(np.random.normal(0.05, 0.02))

from bisect import bisect_right

print bisect_right(sorted(my_vals),threshold_val)/float(len(my_vals))*100