【问题标题】:how to approximate 90th percentile given a stream of millions of numbers给定数百万个数字流,如何近似第 90 个百分位
【发布时间】:2018-06-11 15:00:20
【问题描述】:

我需要计算每秒得到的数字流的第 90 个百分位数。每秒可能高达数百万个数字,但第 90 个百分位必须是近似的,不一定是精确的。优先级队列/最大堆是执行此操作的最佳方式还是其他方式?如果是这样,我最终将如何近似该值?

【问题讨论】:

  • 您是否在每秒批量处理这些数字?还有百分位数,它是否必须适用于整个流,还是您只需要最新的估计值?
  • 你的输入分布是什么样的?
  • 流的元素是独立的吗?
  • 我正在计算每秒的第 90 个百分位,而这些秒中的每一秒可能有多达数百万个我必须计算百分位的数字(但大约,不必精确) .分布在 0 到 150 之间,并且是独立的。
  • 那么在0到150之间?创建 150 个桶,当有物品进来时增加相应的桶。当您收到所有物品后,从最大的桶开始计数,直到达到总数的 10%。这将是你的 90%。

标签: java statistics heap priority-queue percentile


【解决方案1】:

您选择的方法取决于数据的性质。如果您知道,在您开始接收项目流之前,您将收到多少个项目,您可以使用基于堆的选择算法。例如,如果您知道您将收到 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 个百分位值。

此方法将比其他两种方法更快,并且使用的内存要少得多。但这是一个近似值,而不是一个精确值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-01
    • 1970-01-01
    • 2018-02-07
    • 1970-01-01
    • 2011-01-29
    • 1970-01-01
    • 2012-11-01
    • 1970-01-01
    相关资源
    最近更新 更多