【问题标题】:Median of multiple vectors of double (c++, vector < vector<double> >)double的多个向量的中位数(c++,vector<vector<double>>)
【发布时间】:2014-10-29 17:01:03
【问题描述】:

我有一个数据结构,其中包含一个向量向量,每个向量包含约 16000000 个双精度值。

我现在想对这些向量进行中值组合,也就是说,我在第 i 处取值,计算这些向量的中值,然后将它们存储在第 i 处的结果向量中。

我已经有了直截了当的解决方案,但是速度非常慢:

vector< vector<double> > vectors; //vectors contains the datavectors
vector<double> tmp;
vector<double> result;
vector<double> tmpmedian;
double pixels = 0.0;
double matrixcount = vectors.size();

    tmp = vectors.at(0);
    pixels = tmp.size();
    for (int i = 0; i < pixels; i++) {
        for (int j = 0; j < matrixcount; j++) {
            tmp = vectors.at(j);
            tmpmedian.push_back(tmp.at(i));
        }
        result.push_back(medianOfVector(tmpmedian));
        tmpmedian.clear();
    }

return result;

而且 medianOfVector 看起来像这样:

double result = 0;

if ((vec.size() % 2) != 0) {
    vector<double>::iterator i = vec.begin();
    vector<double>::size_type m = (vec.size() / 2);

    nth_element(i, i + m, vec.end());
    result = vec.at(m);
} else {
    vector<double>::iterator i = vec.begin();
    vector<double>::size_type m = (vec.size() / 2) - 1;

    nth_element(i, i + m, vec.end());
    result = (vec.at(m) + vec.at(m + 1)) / 2;
}

return result;

我有一种算法或方法可以更快地做到这一点,它几乎需要永恒的时间才能做到。


编辑:感谢您的回复,如果有人对此感兴趣,这里是固定版本,现在将三个向量与约 16000000 个元素中值组合大约需要 9 秒,平均组合大约需要 3 秒:

vector< vector<double> > vectors; //vectors contains the datavectors
vector<double> *tmp;
vector<double> result;
vector<double> tmpmedian;

    tmp = &vectors.at(0);
    int size = tmp->size();
    int vectorsize = vectors.size();
    for (int i = 0; i < size; i++) {
        for (int j = 0; j < vectorsize; j++) {
            tmp = &vectors.at(j);
            tmpmedian.push_back(tmp->at(i));
        }
        result.push_back(medianOfVector(tmpmedian));
        tmpmedian.clear();
    }
return result;

和中位数的向量:

double result = 0;

if ((vec.size() % 2) != 0) {
    vector<double>::iterator i = vec.begin();
    vector<double>::size_type m = (vec.size() / 2);

    nth_element(i, i + m, vec.end());
    result = vec.at(m);
} else {
    vector<double>::iterator i = vec.begin();
    vector<double>::size_type m = (int) (((vec.size() - 1) / 2));
    nth_element(i, i + m, vec.end());
    double min = vec.at(m);
    double max = *min_element(i + m + 1, vec.end());
    result = (min + max) / 2;
}

return result;
}

【问题讨论】:

  • 我不确定如果没有关于正在处理的数据的更多信息,人们能够提出多少有用的算法建议。他们是否可以对数据或您知道它将具有的属性做出进一步的假设?如果您正在处理大量未知内容的可变长度向量,那么您可能无法通过算法做很多事情(但可能通过实现仍有一些改进)。
  • 在我看来这可以并行完成?您是否考虑过将其卸载到 GPU(使用 CUDA/C++AMP/OpenCL...)?
  • 您正在制作大量矢量副本。你能传递指向原始向量的指针吗?
  • 在您的 medianOfVector 中,您调用 nth_element 来设置第 m 个元素,然后也访问第 (m+1) 个元素。不幸的是,这不一定是设置的。
  • @Owen:可悲的是有点随机,数据是图像的表示,大小>16 MPixels。

标签: c++ vector double median


【解决方案1】:

有几点,都源于您将tmp 定义为矢量而不是(例如)参考。

vector<double> tmp;

tmp = vectors.at(0);
pixels = tmp.size();

在这里,您将整个 vectors[0] 复制到 tmp 中,只是为了提取大小。通过避免复制,您几乎肯定会获得一些速度:

pixels = vectors.at(0).size();

这不是复制整个向量来获取其大小,而是获取第一个向量的引用,并获取该现有向量的大小。

for (int i = 0; i < pixels; i++) {
    for (int j = 0; j < matrixcount; j++) {
        tmp = vectors.at(j);
        tmpmedian.push_back(tmp.at(i));
    }

在这里,您再次将整个 vectors.at(j) 复制到 tmp。但是(再次)您并不真正需要所有数据的新副本——您只是从该副本中检索单个项目。您可以直接从原始向量中检索所需的数据,而无需复制整个内容:

tmpmedian.push_back(vectors.at(j).at(i));

下一步可能是从使用.at 切换到operator[]

tmpmedian.push_back(vectors[j][i]);

不过,这更像是一种权衡——它不太可能获得几乎一样多的收益,并且在此过程中失去了一点安全性(范围检查)。为避免失去安全性,您可以考虑(例如)在当前代码中使用基于范围的 for 循环而不是计数的 for 循环。

沿着相当不同的路线,您可以改为从使用vector&lt;vector&lt;double&gt;&gt; 更改为在向量周围使用小包装器,以将二维寻址转换为单个向量。将其与合适的按列迭代器一起使用,您可以避免将tmpmedian 创建为基本上是原始二维矩阵的列的副本——相反,您可以将按列迭代器传递给medianOfVector,然后进行迭代通过一列就地原始数据。

【讨论】:

    猜你喜欢
    • 2011-06-14
    • 1970-01-01
    • 2017-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-17
    相关资源
    最近更新 更多