获得数据流的平均值,p95和p99

时间:2013-05-08 22:23:46

标签: algorithm average precision moving-average

我有传入的数据,我想计算该数据的平均值,第95百分位和第99百分位数 - 我对最后1000个值最感兴趣。在任何时候,我都想查询这个对象以获得三个值中的任何一个(这可以在任何时候发生,而不仅仅是当看到mod 1000的数字是0时)。有没有办法在不保留最后1000个样本的情况下获得这三个值?

这不一定是完美的,所以我们可以使用一些技巧来获得一个很好的估计。此外,速度是另一个问题。感谢

(我将在C ++中这样做,但我认为这并不重要)

2 个答案:

答案 0 :(得分:4)

至少,您需要维护最近1000个元素的队列。

要保持运行平均值,请保持最近1000个元素的运行总计;向队列添加新元素时,将其值添加到总计中,并且还会减去刚刚从队列中删除的最旧元素的值。返回总数除以1000,然后就可以了。

要保持正在运行的第N个百分位数,请保持两个堆并保持堆中元素的计数; “较低”堆具有较低的N%值,而“较高”堆具有较高(1-N)%(例如,较低的第95百分位堆将具有950个元素,并且较高的第5百分位堆将具有有50个元素)。在任何时候你都可以从上堆返回最低元素,那就是你的百分位数。从最近值的队列中删除元素时,也要从堆中删除该值。如果这使得堆不平衡(例如,下层堆有951个元素而上层堆有49个元素),则移动元素以平衡它们(例如从下层堆中移除顶部元素并将其添加到上层堆中)。 p>

因为你想要两个百分位数,所以使用三个堆 - 较低的堆具有较低的950个元素,中间具有接下来的40个,而较高的堆具有最高的10.返回第95个百分位的中间堆的最低元素,和第99百分位数的上层的最低元素。

添加和删除堆元素是O(lg(n)),因此这是向队列添加新元素的成本和三个堆:从堆中删除最旧的队列元素(O(lg(n)) ,将新队列元素添加到适当的堆(O(lg(n)),并在需要时平衡堆(再次,O(lg(n))。将新元素添加到最高元素更大的最低堆比堆元素,即

if (newElement < lowestHeap.maxElement) {
    lowestHeap.add(newElement)
} else if (newElement < middleHeap.maxElement) {
    middleHeap.add(newElement)
} else { 
    highestHeap.add(newElement)
}

确保您的堆允许重复元素

答案 1 :(得分:1)

首先让我们假设您可以存储1000个数字(让我们说k乘以1000,其中k是常数)。

保持3堆:

  1. 存储10(或50)个元素(heapA)
  2. 的minheap
  3. 存储剩余990(或950个元素)(heapB)
  4. 的最大值
  5. 保持元素顺序的最小化。最旧的元素始终位于此堆堆顶部C)
  6. 这三个堆是特殊的:heapC还保持到heapA或heapB中相应元素的链接。 heapA和heapB也跟踪heapC中的相同元素。

    这是它的工作方式:

    1. 假设系统中有1000个元素。 heapA有10个元素,heapB 990和heapC有1000个元素
    2. 从系统中删除最旧的元素。从heapC中删除它并使用链接从heapA或heapB
    3. 中删除它
    4. 重新平衡三堆。
    5. 根据heapA
    6. 的顶部,将新元素的顺序添加到heapA或heapB中
    7. 将元素的顺序添加到heapC。
    8. 执行此操作时,还要相互添加链接。