如果给出数百万个数字流,如何估计第90个百分点

时间:2018-01-01 17:53:18

标签: java statistics heap priority-queue percentile

我需要计算每秒钟得到的数字流的第90个百分位数。它可能达到每秒数百万个数字,但是第90个百分位只需要近似而不一定精确。优先级队列/最大堆是最好的方法,或其他什么?如果是这样,我最终将如何逼近该值?

1 个答案:

答案 0 :(得分:3)

您选择的方法取决于数据的性质。如果您知道,在开始接收项目流之前,您将收到多少项,您可以使用基于堆的选择算法。例如,如果您知道自己将获得1,000,000个项目并且需要知道90%的百分位数,那么您就知道第100,000个项目标记了第90个百分位数。要找到它,请执行以下操作:

create an empty min heap
add the first 100,000 items to the heap
for each remaining item
    if the item is larger than the smallest item on the heap
        remove the smallest item from the heap
        add the new item to the heap

当你完成时,堆包含100,000个最大的项,堆的根是最小的。这是你的第90个百分点值。

使用更多内存的更快方法是将所有传入项目保存在列表中,然后运行Quickselect以查找第100,000个最大项目。

以上两点都会给你一个确切的答案。

如果您知道您的号码将在相对较小的范围内,您可以创建存储桶以存储它们。例如,您说您的号码在0到150范围内。因此您需要151个桶。您的值不是整数,但由于您说近似值很好,您可以在将值放入桶之前对值进行舍入。所以这样的事情应该有效:

buckets = array of 151 values
for each value
    int_value = round(value)
    buckets[int_value] = buckets[int_value] + 1

现在您已计算出每个值,计算出第90个百分位是一个简单的问题,即从数组末尾计算值(最高值)直到达到10%。类似的东西:

target = 100000  // we want the top 10 percent
bucket = 150
total = 0
while (bucket >= 0)
    total += buckets[bucket]
    if (total >= target)
        break
    bucket = bucket - 1

此时,bucket的值是您的大约90百分位值。

此方法将比其他两种方法更快,并且将使用相当少的内存。但它是一个近似值,而不是一个确切的值。

相关问题