【问题标题】:Maintaining a container of objects sorted by the difference between that object's member and its neighbor's member维护一个对象容器,按对象成员与其邻居成员之间的差异排序
【发布时间】:2011-10-14 11:06:21
【问题描述】:

我正在努力实现直方图,其中一个关键点是直方图箱的快速合并。因为我对直方图逼近的数据集没有先验知识,所以我需要想出一种方法,在超过最大 bin 数后快速合并相邻的 bin。

因此,举个例子,如果您使用五个直方图 bin 来近似数据流 23、19、10、16、36、2、9、32、30、45,您将读取前五个元素,获得:

(23, 1), (19,1), (10,1), (16,1), (36,1)

添加 bin (2,1) 会导致问题,因为我们已经超过了 bin 的最大数量。因此,我们添加 (2,1) 并合并两个最接近的 bin - (16,1) 和 (19,1) - 以获得替换这两个的新 bin (17.5,2)。

对直方图的其余部分重复此方法,得到最终输出:

(2,1), (9.5,2), (19.33,3), (32.67,3), (45,1)。

在不考虑复杂性问题的情况下实现这一点是微不足道的。但是,我真的很关心如何针对大型数据集进行优化,因为我的“微不足道”实现最终需要 15 秒才能在 100,000 个高斯分布值的流上运行。

我目前的想法是使用 boost::multi_index 来跟踪我的 HistogramBin 结构,其定义为:

struct HistogramBin
{
    double bin;
    unsigned long count;
    bool isNull;

    HistogramBin(double x, bool n = false)
    : bin(x), count(1), isNull(n) {}

    bool operator<(const HistogramBin &other) const
    { return (bin < other.bin); }

    // Merges other with this histogram bin
    // E.g., if you have (2.0,1) and (3.0,2), you'd merge them into (2.67,3)
    void merge(const HistogramBin &other)
    {
        unsigned long old_count = count;
        count += other.count;
        bin = (bin*old_count + other.bin*other.count)/count;
    }

    // Gets the difference between two histogram bins
    const double getDifference(const HistogramBin &other) const
    { return (double)abs(bin - other.bin); }
};

因此,multi_index 将使用 ordered_unique 对 HistogramBin::bin 进行排序。

现在,这并不能解决根据相邻 bin 之间的差异对 bin 进行排序的问题。 HistogramBin::bin 的索引为我们提供了 HistogramBin 对象的有序列表,但下一步是计算当前 bin 与下一个 bin 之间的差异,然后也对 那些 值进行排序.

有没有办法对这些值进行排序,同时保持列表的完整性,并且不引入新的容器(例如差异/迭代器键/值对的多重映射)?

维护这个列表是我目前对复杂性问题的近乎最优解决方案的想法,因为它只需要在合并时进行更改,并且只有在添加新值时才会发生合并。

任何想法或见解将不胜感激。

【问题讨论】:

  • 您的垃圾箱应该具备哪些属性?我认为可以对传入的值进行排序,然后根据您的标准设置箱的限制。
  • 不清楚根据相邻元素之间的差异对容器进行排序是什么意思。或许举个例子就能说明问题。
  • @n.m.我试图在问题中举个例子。通过按相邻元素之间的差异进行排序,我的意思是在排序后,“排序后的差异图”将类似于:(6, (10,1), (16,1)), (3, (16,1), (19,1)), ...,这就是你想要排序的向量——根据差异。这就是告诉我们将 (16,1) 和 (19,1) 合并到 (17.5,2) 中的原因。
  • 看看这个问题的答案:stackoverflow.com/questions/3698532/online-k-means-clustering 如果我正确理解你的问题,那几乎就是你要找的,最初的 k 猜测是你的第一个 k 值.
  • @kmore 实际上是 O(n*log(m)),如果你保持你的 bin 中心有序,你可以对它进行二分搜索,最接近的值要么是之前的要么是之后的它

标签: c++ algorithm boost time-complexity


【解决方案1】:

我看到的主要问题是,您创建了一个系统,在该系统中,您不断地重新计算直方图,在最坏的情况下,对于每个新元素。

这样的事情怎么样:

  1. 对于 N 个 binmin 到 Binmax,将它们分配给输入的初始值
  2. 对于每个新数 X,如果 X 为 min 则设置 Binmin = X else if X > Binmax 设置 Bin最大 = X
  3. 如果您更改了 2 中的边界,请将每个 bin 的值设置为 BinL = (Binmax - Binmin) / N * L,其中 L 是 bin 序数
  4. 将 X 添加到与 X 最接近的 bin。

这是餐巾纸的背面,所以我确定某处有误。这个想法是仅在值超出直方图时“重构”直方图,因此您需要做的正常情况就是将 X 添加到最匹配它的 bin 中。我相信如果不相等,这应该会产生非常相似的直方图。第 1 步是你的初始化,第 2-4 步是一个循环,如果不清楚。

【讨论】:

  • 如果我的阅读正确,这需要先验了解被读入直方图的数据的性质——这对于在线直方图来说是不可能的。这个想法是在不知道其界限或范围的情况下近似数据的基本分布。
  • 不,它不需要先验知识。我认为您指的是第一步。如果您愿意,您可以为所有值选择相同的数字,例如 0。您也可以做出有根据的猜测。唯一遇到问题的情况是,如果您选择的值超出了实际最小值和最大值的范围 - 这将导致数据的次优表示。我的算法和你的算法都可以看到的另一个问题是异常值会导致同样的问题。
  • 对,那么您怎么知道您选择的值是否超出了实际最小值和最大值的范围?下面是我的算法如何逼近 100,000 个元素的正态分布的示例(均值 = 100,标准差 = 10):i.imgur.com/S96VB.png,因此仍然可以适当处理异常值
  • 好吧,简单的解决方案,想想吧。将所有 bin 设置为初始值。
【解决方案2】:

将此作为答案发布:

看看这个问题的答案:Online k-means clustering。如果我正确理解您的问题,那几乎就是您要查找的内容,其中最初的 k 猜测是您的第一个 k 值。

如果你保持你的 bin 中心有序,你可以对列表进行二分搜索,最接近的值是它之前或之后的值,总体复杂度为 O(n*log(m)) 其中m 是 bin 的数量n 是数据量。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-03
    • 1970-01-01
    • 2015-07-29
    • 2014-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多