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

Posted

技术标签:

【中文标题】获取数据流的平均值、p95 和 p99【英文标题】:getting the average, p95 and p99 of a stream of data 【发布时间】:2013-05-03 07:21:51 【问题描述】:

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

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

(我将在 C++ 中执行此操作,但我认为这并不重要)

【问题讨论】:

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

至少,您需要维护一个包含最近 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)

确保您的堆允许重复元素

【讨论】:

【参考方案2】:

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

保留 3 个堆:

    用于存储 10(或 50)个元素 (heapA) 的 minheap 用于存储剩余 990(或 950 个元素)的 maxheap (heapB) 用于保持元素顺序的 minheap。最旧的元素总是在这个堆的顶部 heapC)

这三个堆是特殊的:heapC 还保留了指向 heapA 或 heapB 中相应元素的链接。 heapA 和 heapB 也跟踪 heapC 中的相同元素。

这是它的工作方式:

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

【讨论】:

以上是关于获取数据流的平均值、p95 和 p99的主要内容,如果未能解决你的问题,请参考以下文章

如何通过Zabbix获取监控数据

(运行的干净代码)根据来自另一个数据帧的日期间隔和字符串条件获取一个数据帧中的值的平均值

如何根据条件获取给定数据的 k 聚类平均值?

如何在 laravel 中获取所有平均评分的数据

如何获取具有多列的时间序列数据框中的每小时平均值

从 csv 获取数据并计算平均值