具有最大内存效率的增量中值计算
Posted
技术标签:
【中文标题】具有最大内存效率的增量中值计算【英文标题】:Incremental median computation with max memory efficiency 【发布时间】:2011-03-23 06:27:18 【问题描述】:我有一个产生价值的过程,并且我观察到了这一过程。当进程终止时,我想计算这些值的中位数。
如果我必须计算平均值,我可以只存储总和和生成值的数量,因此需要 O(1) 内存。中位数呢?有没有办法节省存储所有值带来的明显 O(n)?
编辑:对 2 种情况感兴趣:1)流长度已知,2)不知道。
【问题讨论】:
非常有趣的问题。如果您只需要知道某个精度的中位数,并且您希望概率分布不会随着采样时间而改变,那么您可以尽早估计中位数的“99% 置信区间”,并且只存储其中的数字该间隔(并跟踪您丢弃的间隔之外的间隔)。当 N 非常大时,这将更有效 - 但它确实取决于您所需的结果精度。 【参考方案1】:您将需要至少存储 ceil(n/2) 个点,因为前 n/2 个点中的任何一个都可能是中位数。存储点并找到中位数可能是最简单的。如果保存 ceil(n/2) 点是有价值的,则将前 n/2 点读入排序列表(二叉树可能是最好的),然后在添加新点时丢弃低点或高点并保留跟踪两端抛出的点数。
编辑:
如果流长度未知,那么显然,正如斯蒂芬在 cmets 中观察到的,那么我们别无选择,只能记住一切。如果可能存在重复项,我们可以使用 Dolphins 存储值和计数的想法节省一点内存。
【讨论】:
不,我不这么认为。有了这个 n = 13,我们最多只需要存储 7 个。我不确定你的 n 是多少。使用这个流,我们读取前 7 个,然后在读取 2 时丢掉 0。我真的不明白你的反对意见。 好的,我把这个问题读成一个未知长度的流,但现在我意识到这并没有说明......无论哪种方式13/2==6
对我来说:) 无论如何,这是一个真实的观察。不幸的是,我无法反转 -1,因为我没有这样做。而n/2
仍然是O(n)
:)
deinst: 你能帮我知道你将如何在保存前 n/2 个点的情况下找到这个列表的中位数:0,3,2,1,5,6,8,7 ,4
最多保留 5 分,因为 ceil(9/2)==5: [0], [0,3], [0,2,3], [0,1,2,3], [0,1,2,3,5], (1)[1,2,3,5,6], (2)[2,3,5,6,8], (3)[3,5,6,7,8], (3)[3,4,5,6,7](1)
。第 5 项是 4。(0,1,2,3,4,5,6,7,8) -> 中间项是 4。
谢谢斯蒂芬。这不像我的那么混乱。【参考方案2】:
你可以
如果可以接受,请使用统计数据 - 例如,您可以使用抽样。 使用有关号码流的知识 使用类似计数排序的方法:k
distinct values 表示存储 O(k)
内存)
或丢弃已知的异常值并保留一个(高、低)计数器。
如果您知道自己没有重复项,则可以使用位图...但这只是 O(n)
的较小常量。
【讨论】:
【参考方案3】:我遇到了同样的问题,并且找到了一种尚未在此处发布的方法。希望我的回答可以帮助将来的人。
如果您知道自己的值范围并且不太关心中值精度,则可以使用常量内存逐步创建量化值的直方图。然后很容易找到中值或任何值的位置,用你的量化误差。
例如,假设您的数据流是图像像素值,并且您知道这些值都是整数,都在 0~255 之间。要以增量方式创建图像直方图,只需从零开始创建 256 个计数器(bin),并在扫描输入时在对应于像素值的 bin 上计数一个。创建直方图后,找到第一个大于数据大小一半的累积计数以获得中位数。
对于实数数据,您仍然可以计算直方图,其中每个 bin 具有量化值(例如 10、1 或 0.1 等的 bin),具体取决于您想要的预期数据值范围和精度。
如果您不知道整个数据样本的取值范围,您仍然可以估计中位数的可能取值范围,并在此范围内计算直方图。这自然会丢弃异常值,但这正是我们在计算中位数时想要的。
【讨论】:
我发现我的答案是斯蒂芬的答案的一种扩展,但这篇文章提供了更多细节。【参考方案4】:如果您有离散值和大量重复,您可以存储值和计数,这样可以节省一点空间。
可能在计算的各个阶段,只要您确定中位数不在该顶部或底部范围内,您就可以丢弃顶部“n”和底部“n”值。 例如假设您期望 100,000 个值。每当您存储的数字达到(例如)12,000 时,您可以丢弃最高的 1000 和最低的 1000,将存储量降回 10,000。
如果值的分布相当一致,这会很好。但是,如果您有可能在接近尾声时收到大量非常高或非常低的值,这可能会扭曲您的计算。基本上,如果您丢弃小于(最终)中位数的“高”值或等于或大于(最终)中位数的“低”值,那么您的计算就会关闭。
更新 一个例子 假设数据集是数字 1,2,3,4,5,6,7,8,9。 通过检查,中位数为 5。
假设您得到的前 5 个数字是 1,3,5,7,9。 为了节省空间,我们丢弃了最高和最低,留下 3,5,7 现在再得到两个,2,6,所以我们的存储空间是 2,3,5,6,7 丢弃最高和最低,留下 3,5,6 获取最后两个 4,8,我们有 3,4,5,6,8 中位数仍然是 5,世界是个好地方。
但是,假设我们得到的前五个数字是 1,2,3,4,5 丢弃顶部和底部留下 2,3,4 再拿两个 6,7,我们有 2,3,4,6,7 丢弃顶部和底部留下 3,4,6 得到最后两个 8,9,我们有 3,4,6,8,9 中位数为 6,这是不正确的。
如果我们的数字分布良好,我们可以继续修剪四肢。如果它们可能以大量或大量的小数量聚集在一起,那么丢弃是有风险的。
【讨论】:
以上是关于具有最大内存效率的增量中值计算的主要内容,如果未能解决你的问题,请参考以下文章