【问题标题】:Histogram approximation for streaming data流数据的直方图逼近
【发布时间】:2025-12-29 17:15:11
【问题描述】:

这个问题是answered here 的一个小扩展。我正在重新实现在this paper 的第 2.1 节中找到的直方图近似的一个版本,我想在再次开始这个过程之前把我所有的鸭子排成一排。上次,我使用了boost::multi_index,但性能不是最好的,我想避免std::set 的桶插入/查找复杂性的对数。由于我使用的直方图数量(随机森林中随机树的每个叶节点每个类每个特征一个),计算复杂度必须尽可能接近常数。

用于实现直方图的标准技术涉及将输入实数值映射到 bin 编号。为此,一种方法是:

  1. 初始化大小为 N 的标准 C 数组,其中 N = 箱数;和
  2. 将输入值(实数)乘以某个因子,然后将结果取底,得到它在 C 数组中的索引。

这适用于具有统一 bin 大小的直方图,并且非常有效。但是,上述链接论文的第 2.1 节提供了一种没有统一 bin 大小的直方图算法。

另一个问题是,简单地将输入实数值乘以一个因子并将结果乘积作为索引会因负数而失败。为了解决这个问题,我考虑在数组中的某处标识一个“0”箱。此 bin 将以 0.0 为中心;上面/下面的 bin 可以使用刚刚解释的相同的乘法和下限方法进行计算,只需稍作修改,根据需要将下限乘积加到二或从二中减去。

这就提出了合并的问题:论文中的算法合并了两个最近的 bin,从中心到中心测量。在实践中,这会创建一个“锯齿状”直方图近似值,因为某些 bin 的计数非常大,而其他 bin 则不会。当然,这是由于 bin 大小不均匀,不会导致任何精度损失。但是,如果我们尝试对非统一大小的 bin 进行归一化以使其统一,则会发生精度损失。这是因为假设 m/2 个样本落在 bin 中心的左右两侧,其中 m = bin count。我们可以将每个 bin 建模为高斯,但这仍然会导致精度损失(尽管很小)

这就是我现在陷入困境的地方,导致了这个主要问题:实现接受流数据并将每个样本存储在统一大小的 bin 中的直方图的最佳方法是什么?

【问题讨论】:

    标签: c++ algorithm data-structures machine-learning histogram


    【解决方案1】:

    保留四个变量。

    int N;  // assume for simplicity that N is even
    int count[N];
    double lower_bound;
    double bin_size;
    

    当新样本x 到达时,计算double i = floor(x - lower_bound) / bin_size。如果i >= 0 && i < N,则递增count[i]。如果i >= N,则重复加倍bin_size,直到x - lower_bound < N * bin_size。在每次加倍时,调整计数(通过利用稀疏性进行多次加倍来优化)。

    for (int j = 0; j < N / 2; j++) count[j] = count[2 * j] + count[2 * j + 1];
    for (int j = N / 2; j < N; j++) count[j] = 0;
    

    i &lt; 0 的情况比较棘手,因为我们需要减少 lower_bound 并增加 bin_size(同样,优化稀疏性或一步调整计数)。

    while (lower_bound > x) {
        lower_bound -= N * bin_size;
        bin_size += bin_size;
        for (int j = N - 1; j > N / 2 - 1; j--) count[j] = count[2 * j - N] + count[2 * j - N + 1];
        for (int j = 0; j < N / 2; j++) count[j] = 0;
    }
    

    例外情况代价高昂,但在初始 bin 大小的数据范围内仅发生对数次。

    如果您在浮点中实现这一点,请注意浮点数不是实数,并且像 lower_bound -= N * bin_size 这样的语句可能会出现错误(在这种情况下,如果 N * bin_size 远小于 lower_bound)。我建议 bin_size 始终是基数(通常是两个)的幂。

    【讨论】: