Algorithm 获取数据流的平均值p95和p99

Algorithm 获取数据流的平均值p95和p99,algorithm,average,precision,moving-average,Algorithm,Average,Precision,Moving Average,我有输入数据,我想计算该数据的平均值,第95和99个百分位-我最感兴趣的是最后1000个值。在任何时候,我都想查询这个对象以获得三个值中的任何一个(这可以在任何时候发生,而不仅仅是当mod 1000看到的数字为0时)。有没有办法在不保留最后1000个样本的情况下获得这三个值 这并不一定是完美的,所以我们可以使用一些技巧来获得一个好的估计。此外,速度是另一个问题。谢谢 (我将在C++中做这件事,但我不认为这有什么关系)至少,你需要保持最近1000个元素的队列。 要保持运行平均值,请保持最近1000

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

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


(我将在C++中做这件事,但我不认为这有什么关系)

至少,你需要保持最近1000个元素的队列。

要保持运行平均值,请保持最近1000个元素的运行总数;向队列中添加新元素时,将其值添加到总数中,并减去刚从队列中删除的最旧元素的值。返回总数除以1000的结果

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

因为您想要两个百分位,所以使用三个堆-较低的堆包含较低的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)
}
if(newElement

确保您的堆允许重复元素

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

保持3堆:

  • 存储10(或50)个元素的minheap(heapA)
  • 用于存储剩余990(或950个元素)的最大堆(heapB)
  • 保持元素顺序的最小堆。最旧的元素始终在此堆的顶部(heapC)
  • 这三个堆是特殊的:heapC还保持到heapA或heapB中相应元素的链接。heapA和heapB还保持对heapC中相同元素的跟踪

    这就是它的工作方式:

  • 假设系统中有1000个元素,heapA有10个元素,heapb990和heapC有1000个元素
  • 从系统中删除最旧的元素。从heapC中删除它,并使用链接从heapA或heapB中删除它
  • 重新平衡这三个堆
  • 根据heapA的顶部,将新元素的顺序添加到heapA或heapB中
  • 将元素的顺序添加到heapC
  • 在执行此操作时,还可以相互添加链接

  • 我认为您可以保存1000个条目的数组,而不会带来太多麻烦或内存损失。问题是数据的顺序(我认为,如果您想要获得百分位数,您需要对其进行排序)是的,排序是最麻烦的部分。如果你不将数据保存在数组中,我认为没有办法计算任何百分位数,因此,算法(我认为应该是这样的)是:1.存储数据;2.排序数据(使用你最喜欢的方法);3.在所需位置获取值(
    array[n]
    其中
    n=round(array.length*p)
    0