这个问题只是answered here的一个细微延伸。我正在努力重新实现this paper第2.1节中的直方图近似版本,我希望在再次开始此过程之前连接所有的鸭子。上次,我使用boost::multi_index
,但性能并不是最好的,我想避免插入/找到std::set
的复杂性的桶数量的对数。由于我正在使用的直方图的数量(随机森林中随机树的每个叶节点每个特征一个),计算复杂度必须尽可能接近常数。
用于实现直方图的标准技术涉及将输入实际值映射到bin编号。要做到这一点,一种方法是:
这适用于具有统一bin大小的直方图,并且非常有效。但是,上面链接的论文的第2.1节提供了没有统一分箱大小的直方图算法。
另一个问题是,简单地将输入实际值乘以一个因子,并使用得到的产品作为索引,会出现负数。为了解决这个问题,我考虑在数组中的某处识别一个'0'bin。这个箱子将以0.0为中心;它上面/下面的垃圾箱可以使用刚才解释的相同的乘法和平面方法计算,稍作修改,将地板产品加到两个或必要时减去两个。
然后提出了合并的问题:本文中的算法合并了两个最接近的箱,从中心到中心测量。在实践中,这会产生“锯齿状”直方图近似值,因为某些箱子会有非常大的数量,而其他箱子则不会。当然,这是由于不均匀尺寸的箱,并且不会导致任何精度损失。然而,如果我们试图将非均匀尺寸的箱子标准化以制造均匀,则会发生精度损失。这是因为假设m / 2样本落在bin中心的左侧和右侧,其中m = bin计数。我们可以将每个bin建模为高斯,但这仍然会导致精度损失(尽管很小)
这就是我现在被困住的地方,导致了这个主要问题:实现直方图接受流数据并将每个样本存储在统一大小的容器中的最佳方法是什么?
答案 0 :(得分:6)
保留四个变量。
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 < 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;
}
特殊情况很昂贵,但在初始箱尺寸范围内,您的数据范围内只会出现对数次数。
如果以浮点方式实现此功能,请注意浮点数不是实数,而lower_bound -= N * bin_size
之类的语句可能行为不当(在这种情况下,如果N * bin_size
远小于lower_bound
{1}})。我建议bin_size
始终是基数(通常是两个)的幂。