【问题标题】:Memory-efficient downsampling (charting) of a growing array不断增长的数组的内存高效下采样(图表)
【发布时间】:2016-09-11 12:21:50
【问题描述】:

我的一个节点进程每半秒接收一个样本点,我想更新我收到的所有样本点的历史图表。 图表应该是一个数组,其中包含从 0 到当前点的所有点的下采样历史记录。 换句话说,数组的最大长度应该是l。如果我收到的样本点多于l,我希望图表数组是整个历史记录的下采样到l 的版本。

用代码来表达:

const CHART_LENGTH = 2048
createChart(CHART_LENGTH)
onReceivePoint = function(p) {
    // p can be considered a number
    const chart = addPointToChart(p)
    // chart is an array representing all the samples received, from 0 to now
    console.assert(chart.length <= CHART_LENGTH)
}

我已经有了一个带有数字数组的下采样函数:

function downsample (arr, density) {
  let i, j, p, _i, _len
  const downsampled = []
  for (i = _i = 0, _len = arr.length; _i < _len; i = ++_i) {
    p = arr[i]
    j = ~~(i / arr.length * density)
    if (downsampled[j] == null) downsampled[j] = 0
    downsampled[j] += Math.abs(arr[i] * density / arr.length)
  }
  return downsampled
}

这样做的一个简单方法显然是将我收到的所有点保存到一个数组中,并在数组增长时应用downsample 函数。这会起作用,但是,由于这段代码会在服务器中运行,可能会连续数月运行,它最终会使支持数组增长得如此之多,以至于进程会耗尽内存。

问题是:有没有办法重新使用图表本身的先前内容来构造图表数组,以避免维持不断增长的数据结构?换句话说,这个问题是否有一个恒定的内存复杂度解决方案?

请注意,图表必须包含自采样点 #0 以来的全部历史记录,因此不能接受最后 n 个点的图表。

【问题讨论】:

    标签: javascript algorithm memory charts sampling


    【解决方案1】:

    唯一不会扭曲数据并且可以多次使用的操作是聚合整数个相邻样本。你可能想要 2 个。

    更具体地说:如果您发现添加新样本会超出数组边界,请执行以下操作:从数组的开头开始,平均两个后续样本。这会将数组大小减少 2,并且您有空间添加新样本。这样做,您应该跟踪当前的集群大小c(构成数组中一个条目的样本量)。你从一个开始。每次减少都会使集群大小乘以 2。

    现在的问题是您不能再将新样本直接添加到数组中,因为它们具有完全不同的比例。相反,您应该将下一个 c 样本平均到一个新条目。事实证明,在当前集群中存储样本数量n 就足够了。因此,如果您添加一个新示例 s,您将执行以下操作。

    n++
    if n = 1
        append s to array
    else        
        //update the average
        last array element += (s - last array element) / n
    if n = c
        n = 0 //start a new cluster
    

    所以你实际需要的内存如下:

    • 预定义长度的历史数组
    • 历史数组中的元素个数
    • 当前集群大小c
    • 当前簇的元素个数n

    额外内存的大小不取决于样本总数,因此O(1)

    【讨论】:

    • 我不确定我是否理解“从数组的开头开始并平均两个后续样本”。我应该从字面上取 a[0] 和 a[1],将它们平均并将它们放在 a[0] 的位置,将数组移回一个位置吗?或者我应该平均 a[0] 和 a[1]、a[2] 和 a[3] 等直到数组的末尾,结果是一个半长的数组?
    • 这就是我的意思:a0 := 0.5(a0+a1); a1:=0.5(a2+a3); a2:=0.5(a4+a5); ...
    猜你喜欢
    • 2017-12-28
    • 1970-01-01
    • 2019-11-08
    • 1970-01-01
    • 2013-10-20
    • 2016-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多